8268320: Better error recovery for broken patterns in switch
Reviewed-by: vromero
This commit is contained in:
parent
ca283c3ac0
commit
4ee400ae43
src/jdk.compiler/share/classes/com/sun/tools/javac
test/langtools/tools/javac
@ -169,6 +169,8 @@ public class Attr extends JCTree.Visitor {
|
||||
allowStaticInterfaceMethods = Feature.STATIC_INTERFACE_METHODS.allowedInSource(source);
|
||||
allowReifiableTypesInInstanceof = Feature.REIFIABLE_TYPES_INSTANCEOF.allowedInSource(source);
|
||||
allowRecords = Feature.RECORDS.allowedInSource(source);
|
||||
allowPatternSwitch = (preview.isEnabled() || !preview.isPreview(Feature.PATTERN_SWITCH)) &&
|
||||
Feature.PATTERN_SWITCH.allowedInSource(source);
|
||||
sourceName = source.name;
|
||||
useBeforeDeclarationWarning = options.isSet("useBeforeDeclarationWarning");
|
||||
|
||||
@ -209,6 +211,10 @@ public class Attr extends JCTree.Visitor {
|
||||
*/
|
||||
private final boolean allowRecords;
|
||||
|
||||
/** Are patterns in switch allowed
|
||||
*/
|
||||
private final boolean allowPatternSwitch;
|
||||
|
||||
/**
|
||||
* Switch: warn about use of variable before declaration?
|
||||
* RFE: 6425594
|
||||
@ -1724,14 +1730,22 @@ public class Attr extends JCTree.Visitor {
|
||||
rs.basicLogResolveHelper = prevResolveHelper;
|
||||
}
|
||||
} else {
|
||||
Type pattype = attribExpr(expr, switchEnv, seltype);
|
||||
ResultInfo valTypInfo = new ResultInfo(KindSelector.VAL_TYP,
|
||||
!seltype.hasTag(ERROR) ? seltype
|
||||
: Type.noType);
|
||||
Type pattype = attribTree(expr, switchEnv, valTypInfo);
|
||||
if (!pattype.hasTag(ERROR)) {
|
||||
if (!stringSwitch && !types.isAssignable(seltype, syms.intType)) {
|
||||
log.error(pat.pos(), Errors.ConstantLabelNotCompatible(pattype, seltype));
|
||||
}
|
||||
if (pattype.constValue() == null) {
|
||||
log.error(expr.pos(),
|
||||
(stringSwitch ? Errors.StringConstReq : Errors.ConstExprReq));
|
||||
Symbol s = TreeInfo.symbol(expr);
|
||||
if (s != null && s.kind == TYP && allowPatternSwitch) {
|
||||
log.error(expr.pos(),
|
||||
Errors.PatternExpected);
|
||||
} else {
|
||||
log.error(expr.pos(),
|
||||
(stringSwitch ? Errors.StringConstReq : Errors.ConstExprReq));
|
||||
}
|
||||
} else if (!stringSwitch && !types.isAssignable(seltype, syms.intType)) {
|
||||
log.error(pat.pos(), Errors.ConstantLabelNotCompatible(pattype, seltype));
|
||||
} else if (!labels.add(pattype.constValue())) {
|
||||
log.error(c.pos(), Errors.DuplicateCaseLabel);
|
||||
} else {
|
||||
|
@ -1189,6 +1189,9 @@ compiler.err.static.imp.only.classes.and.interfaces=\
|
||||
compiler.err.string.const.req=\
|
||||
constant string expression required
|
||||
|
||||
compiler.err.pattern.expected=\
|
||||
type pattern expected
|
||||
|
||||
# 0: symbol, 1: fragment
|
||||
compiler.err.cannot.generate.class=\
|
||||
error while generating class {0}\n\
|
||||
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
// key: compiler.err.pattern.expected
|
||||
// key: compiler.note.preview.filename
|
||||
// key: compiler.note.preview.recompile
|
||||
// options: --enable-preview -source ${jdk.version}
|
||||
|
||||
class PatternSwitch {
|
||||
private void doSwitch(Object o) {
|
||||
switch (o) {
|
||||
case String: break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
SwitchErrors.java:35:31: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.pattern.switch)
|
||||
SwitchErrors.java:34:18: compiler.err.constant.label.not.compatible: java.lang.String, java.lang.Object
|
||||
SwitchErrors.java:40:18: compiler.err.constant.label.not.compatible: int, java.lang.Object
|
||||
SwitchErrors.java:46:18: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String, java.lang.Integer)
|
||||
SwitchErrors.java:47:18: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.Integer, java.lang.CharSequence)
|
||||
SwitchErrors.java:52:18: compiler.err.preview.feature.disabled: (compiler.misc.feature.case.null)
|
||||
SwitchErrors.java:53:18: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String, int)
|
||||
SwitchErrors.java:54:18: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: int, java.lang.CharSequence)
|
||||
SwitchErrors.java:60:20: compiler.err.total.pattern.and.default
|
||||
SwitchErrors.java:66:13: compiler.err.pattern.dominated
|
||||
SwitchErrors.java:72:18: compiler.err.total.pattern.and.default
|
||||
SwitchErrors.java:78:18: compiler.err.duplicate.total.pattern
|
||||
SwitchErrors.java:84:20: compiler.err.duplicate.default.label
|
||||
SwitchErrors.java:90:20: compiler.err.duplicate.default.label
|
||||
SwitchErrors.java:101:13: compiler.err.duplicate.case.label
|
||||
SwitchErrors.java:106:13: compiler.err.duplicate.case.label
|
||||
SwitchErrors.java:111:28: compiler.err.flows.through.to.pattern
|
||||
SwitchErrors.java:117:18: compiler.err.flows.through.to.pattern
|
||||
SwitchErrors.java:124:18: compiler.err.flows.through.to.pattern
|
||||
SwitchErrors.java:131:18: compiler.err.flows.through.to.pattern
|
||||
SwitchErrors.java:136:18: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String, java.lang.Integer)
|
||||
SwitchErrors.java:142:18: compiler.err.instanceof.reifiable.not.safe: java.util.List, java.util.List<java.lang.Integer>
|
||||
SwitchErrors.java:148:18: compiler.err.cant.resolve.location: kindname.class, Undefined, , , (compiler.misc.location: kindname.class, SwitchErrors, null)
|
||||
SwitchErrors.java:155:18: compiler.err.type.found.req: int, (compiler.misc.type.req.class.array)
|
||||
SwitchErrors.java:172:27: compiler.err.flows.through.to.pattern
|
||||
SwitchErrors.java:178:18: compiler.err.flows.through.to.pattern
|
||||
SwitchErrors.java:184:13: compiler.err.pattern.dominated
|
||||
SwitchErrors.java:196:18: compiler.err.const.expr.req
|
||||
SwitchErrors.java:202:76: compiler.err.cant.resolve.location: kindname.variable, n, , , (compiler.misc.location: kindname.class, SwitchErrors, null)
|
||||
SwitchErrors.java:208:71: compiler.err.cant.resolve.location: kindname.variable, n, , , (compiler.misc.location: kindname.class, SwitchErrors, null)
|
||||
SwitchErrors.java:33:9: compiler.err.not.exhaustive.statement
|
||||
SwitchErrors.java:39:9: compiler.err.not.exhaustive.statement
|
||||
SwitchErrors.java:45:9: compiler.err.not.exhaustive.statement
|
||||
SwitchErrors.java:51:9: compiler.err.not.exhaustive.statement
|
||||
SwitchErrors.java:99:9: compiler.err.not.exhaustive.statement
|
||||
SwitchErrors.java:105:9: compiler.err.not.exhaustive.statement
|
||||
SwitchErrors.java:110:9: compiler.err.not.exhaustive.statement
|
||||
SwitchErrors.java:115:9: compiler.err.not.exhaustive.statement
|
||||
SwitchErrors.java:121:9: compiler.err.not.exhaustive.statement
|
||||
SwitchErrors.java:128:9: compiler.err.not.exhaustive.statement
|
||||
SwitchErrors.java:188:9: compiler.err.not.exhaustive.statement
|
||||
41 errors
|
@ -26,6 +26,7 @@
|
||||
* @bug 8262891
|
||||
* @summary Verify errors related to pattern switches.
|
||||
* @compile/fail/ref=SwitchErrors.out --enable-preview -source ${jdk.version} -XDrawDiagnostics -XDshould-stop.at=FLOW SwitchErrors.java
|
||||
* @compile/fail/ref=SwitchErrors-no-preview.out -XDrawDiagnostics -XDshould-stop.at=FLOW SwitchErrors.java
|
||||
*/
|
||||
public class SwitchErrors {
|
||||
void incompatibleSelectorObjectString(Object o) {
|
||||
@ -190,6 +191,12 @@ public class SwitchErrors {
|
||||
}
|
||||
sealed class SealedNonAbstract permits A {}
|
||||
final class A extends SealedNonAbstract {}
|
||||
void errorRecoveryNoPattern1(Object o) {
|
||||
switch (o) {
|
||||
case String: break;
|
||||
case Object obj: break;
|
||||
}
|
||||
}
|
||||
Object guardWithMatchingStatement(Object o1, Object o2) {
|
||||
switch (o1) {
|
||||
case String s && s.isEmpty() || o2 instanceof Number n: return n;
|
||||
|
@ -1,46 +1,47 @@
|
||||
SwitchErrors.java:33:18: compiler.err.constant.label.not.compatible: java.lang.String, java.lang.Object
|
||||
SwitchErrors.java:39:18: compiler.err.constant.label.not.compatible: int, java.lang.Object
|
||||
SwitchErrors.java:45:18: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String, java.lang.Integer)
|
||||
SwitchErrors.java:46:18: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.Integer, java.lang.CharSequence)
|
||||
SwitchErrors.java:51:18: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: compiler.misc.type.null, int)
|
||||
SwitchErrors.java:52:18: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String, int)
|
||||
SwitchErrors.java:53:18: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: int, java.lang.CharSequence)
|
||||
SwitchErrors.java:59:20: compiler.err.total.pattern.and.default
|
||||
SwitchErrors.java:65:13: compiler.err.pattern.dominated
|
||||
SwitchErrors.java:65:24: compiler.err.total.pattern.and.default
|
||||
SwitchErrors.java:71:18: compiler.err.total.pattern.and.default
|
||||
SwitchErrors.java:77:18: compiler.err.duplicate.total.pattern
|
||||
SwitchErrors.java:83:20: compiler.err.duplicate.default.label
|
||||
SwitchErrors.java:89:20: compiler.err.duplicate.default.label
|
||||
SwitchErrors.java:94:27: compiler.err.duplicate.default.label
|
||||
SwitchErrors.java:100:13: compiler.err.duplicate.case.label
|
||||
SwitchErrors.java:105:13: compiler.err.duplicate.case.label
|
||||
SwitchErrors.java:110:28: compiler.err.flows.through.to.pattern
|
||||
SwitchErrors.java:116:18: compiler.err.flows.through.to.pattern
|
||||
SwitchErrors.java:123:18: compiler.err.flows.through.to.pattern
|
||||
SwitchErrors.java:130:18: compiler.err.flows.through.to.pattern
|
||||
SwitchErrors.java:135:18: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String, java.lang.Integer)
|
||||
SwitchErrors.java:141:18: compiler.err.instanceof.reifiable.not.safe: java.util.List, java.util.List<java.lang.Integer>
|
||||
SwitchErrors.java:147:18: compiler.err.cant.resolve.location: kindname.class, Undefined, , , (compiler.misc.location: kindname.class, SwitchErrors, null)
|
||||
SwitchErrors.java:154:18: compiler.err.type.found.req: int, (compiler.misc.type.req.class.array)
|
||||
SwitchErrors.java:160:28: compiler.err.flows.through.from.pattern
|
||||
SwitchErrors.java:166:18: compiler.err.flows.through.from.pattern
|
||||
SwitchErrors.java:171:27: compiler.err.flows.through.to.pattern
|
||||
SwitchErrors.java:177:18: compiler.err.flows.through.to.pattern
|
||||
SwitchErrors.java:183:13: compiler.err.pattern.dominated
|
||||
SwitchErrors.java:195:76: compiler.err.cant.resolve.location: kindname.variable, n, , , (compiler.misc.location: kindname.class, SwitchErrors, null)
|
||||
SwitchErrors.java:201:71: compiler.err.cant.resolve.location: kindname.variable, n, , , (compiler.misc.location: kindname.class, SwitchErrors, null)
|
||||
SwitchErrors.java:32:9: compiler.err.not.exhaustive.statement
|
||||
SwitchErrors.java:38:9: compiler.err.not.exhaustive.statement
|
||||
SwitchErrors.java:44:9: compiler.err.not.exhaustive.statement
|
||||
SwitchErrors.java:50:9: compiler.err.not.exhaustive.statement
|
||||
SwitchErrors.java:98:9: compiler.err.not.exhaustive.statement
|
||||
SwitchErrors.java:104:9: compiler.err.not.exhaustive.statement
|
||||
SwitchErrors.java:109:9: compiler.err.not.exhaustive.statement
|
||||
SwitchErrors.java:114:9: compiler.err.not.exhaustive.statement
|
||||
SwitchErrors.java:120:9: compiler.err.not.exhaustive.statement
|
||||
SwitchErrors.java:127:9: compiler.err.not.exhaustive.statement
|
||||
SwitchErrors.java:187:9: compiler.err.not.exhaustive.statement
|
||||
SwitchErrors.java:34:18: compiler.err.constant.label.not.compatible: java.lang.String, java.lang.Object
|
||||
SwitchErrors.java:40:18: compiler.err.constant.label.not.compatible: int, java.lang.Object
|
||||
SwitchErrors.java:46:18: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String, java.lang.Integer)
|
||||
SwitchErrors.java:47:18: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.Integer, java.lang.CharSequence)
|
||||
SwitchErrors.java:52:18: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: compiler.misc.type.null, int)
|
||||
SwitchErrors.java:53:18: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String, int)
|
||||
SwitchErrors.java:54:18: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: int, java.lang.CharSequence)
|
||||
SwitchErrors.java:60:20: compiler.err.total.pattern.and.default
|
||||
SwitchErrors.java:66:13: compiler.err.pattern.dominated
|
||||
SwitchErrors.java:66:24: compiler.err.total.pattern.and.default
|
||||
SwitchErrors.java:72:18: compiler.err.total.pattern.and.default
|
||||
SwitchErrors.java:78:18: compiler.err.duplicate.total.pattern
|
||||
SwitchErrors.java:84:20: compiler.err.duplicate.default.label
|
||||
SwitchErrors.java:90:20: compiler.err.duplicate.default.label
|
||||
SwitchErrors.java:95:27: compiler.err.duplicate.default.label
|
||||
SwitchErrors.java:101:13: compiler.err.duplicate.case.label
|
||||
SwitchErrors.java:106:13: compiler.err.duplicate.case.label
|
||||
SwitchErrors.java:111:28: compiler.err.flows.through.to.pattern
|
||||
SwitchErrors.java:117:18: compiler.err.flows.through.to.pattern
|
||||
SwitchErrors.java:124:18: compiler.err.flows.through.to.pattern
|
||||
SwitchErrors.java:131:18: compiler.err.flows.through.to.pattern
|
||||
SwitchErrors.java:136:18: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String, java.lang.Integer)
|
||||
SwitchErrors.java:142:18: compiler.err.instanceof.reifiable.not.safe: java.util.List, java.util.List<java.lang.Integer>
|
||||
SwitchErrors.java:148:18: compiler.err.cant.resolve.location: kindname.class, Undefined, , , (compiler.misc.location: kindname.class, SwitchErrors, null)
|
||||
SwitchErrors.java:155:18: compiler.err.type.found.req: int, (compiler.misc.type.req.class.array)
|
||||
SwitchErrors.java:161:28: compiler.err.flows.through.from.pattern
|
||||
SwitchErrors.java:167:18: compiler.err.flows.through.from.pattern
|
||||
SwitchErrors.java:172:27: compiler.err.flows.through.to.pattern
|
||||
SwitchErrors.java:178:18: compiler.err.flows.through.to.pattern
|
||||
SwitchErrors.java:184:13: compiler.err.pattern.dominated
|
||||
SwitchErrors.java:196:18: compiler.err.pattern.expected
|
||||
SwitchErrors.java:202:76: compiler.err.cant.resolve.location: kindname.variable, n, , , (compiler.misc.location: kindname.class, SwitchErrors, null)
|
||||
SwitchErrors.java:208:71: compiler.err.cant.resolve.location: kindname.variable, n, , , (compiler.misc.location: kindname.class, SwitchErrors, null)
|
||||
SwitchErrors.java:33:9: compiler.err.not.exhaustive.statement
|
||||
SwitchErrors.java:39:9: compiler.err.not.exhaustive.statement
|
||||
SwitchErrors.java:45:9: compiler.err.not.exhaustive.statement
|
||||
SwitchErrors.java:51:9: compiler.err.not.exhaustive.statement
|
||||
SwitchErrors.java:99:9: compiler.err.not.exhaustive.statement
|
||||
SwitchErrors.java:105:9: compiler.err.not.exhaustive.statement
|
||||
SwitchErrors.java:110:9: compiler.err.not.exhaustive.statement
|
||||
SwitchErrors.java:115:9: compiler.err.not.exhaustive.statement
|
||||
SwitchErrors.java:121:9: compiler.err.not.exhaustive.statement
|
||||
SwitchErrors.java:128:9: compiler.err.not.exhaustive.statement
|
||||
SwitchErrors.java:188:9: compiler.err.not.exhaustive.statement
|
||||
- compiler.note.preview.filename: SwitchErrors.java, DEFAULT
|
||||
- compiler.note.preview.recompile
|
||||
43 errors
|
||||
44 errors
|
||||
|
@ -278,7 +278,7 @@ public class Switches {
|
||||
String testStringWithGuards1(E e) {
|
||||
switch (e != null ? e.name() : null) {
|
||||
case "A": return "a";
|
||||
case "B": return "b";
|
||||
case Switches.ConstantClassClash: return "b";
|
||||
case String x && "C".equals(x): return "C";
|
||||
case "C": return "broken";
|
||||
case null, String x: return String.valueOf(x);
|
||||
@ -288,7 +288,7 @@ public class Switches {
|
||||
String testStringWithGuardsExpression1(E e) {
|
||||
return switch (e != null ? e.name() : null) {
|
||||
case "A" -> "a";
|
||||
case "B" -> "b";
|
||||
case ConstantClassClash -> "b";
|
||||
case String x && "C".equals(x) -> "C";
|
||||
case "C" -> "broken";
|
||||
case null, String x -> String.valueOf(x);
|
||||
@ -366,6 +366,12 @@ public class Switches {
|
||||
}
|
||||
}
|
||||
|
||||
//verify that for cases like:
|
||||
//case ConstantClassClash ->
|
||||
//ConstantClassClash is interpreted as a field, not as a class
|
||||
private static final String ConstantClassClash = "B";
|
||||
private static class ConstantClassClash {}
|
||||
|
||||
sealed interface I {}
|
||||
final class A implements I {}
|
||||
final class B implements I {}
|
||||
|
Loading…
x
Reference in New Issue
Block a user