Skip to content

Commit 54ba974

Browse files
committed
Reflecting recent spec changes.
1 parent aeddb85 commit 54ba974

File tree

16 files changed

+437
-60
lines changed

16 files changed

+437
-60
lines changed

src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1659,8 +1659,15 @@ private void handleSwitch(JCTree switchTree,
16591659
boolean enumSwitch = (seltype.tsym.flags() & Flags.ENUM) != 0;
16601660
boolean stringSwitch = types.isSameType(seltype, syms.stringType);
16611661
boolean errorEnumSwitch = TreeInfo.isErrorEnumSwitch(selector, cases);
1662-
if (!enumSwitch && !stringSwitch && !types.isAssignable(seltype, syms.intType)) {
1662+
boolean patternSwitch;
1663+
if (!enumSwitch && !stringSwitch && !errorEnumSwitch &&
1664+
!types.isAssignable(seltype, syms.intType)) {
16631665
preview.checkSourceLevel(selector.pos(), Feature.PATTERN_SWITCH);
1666+
patternSwitch = true;
1667+
} else {
1668+
patternSwitch = cases.stream()
1669+
.flatMap(c -> c.labels.stream())
1670+
.anyMatch(l -> l.isPattern());
16641671
}
16651672

16661673
// Attribute all cases and
@@ -1783,8 +1790,10 @@ private void handleSwitch(JCTree switchTree,
17831790
}
17841791
if (switchTree.hasTag(SWITCH)) {
17851792
((JCSwitch) switchTree).hasTotalPattern = hasDefault || hasTotalPattern;
1793+
((JCSwitch) switchTree).patternSwitch = patternSwitch;
17861794
} else if (switchTree.hasTag(SWITCH_EXPRESSION)) {
17871795
((JCSwitchExpression) switchTree).hasTotalPattern = hasDefault || hasTotalPattern;
1796+
((JCSwitchExpression) switchTree).patternSwitch = patternSwitch;
17881797
} else {
17891798
Assert.error(switchTree.getTag().name());
17901799
}

src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java

Lines changed: 42 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -665,11 +665,13 @@ public void visitSwitch(JCSwitch tree) {
665665
ListBuffer<PendingExit> prevPendingExits = pendingExits;
666666
pendingExits = new ListBuffer<>();
667667
scan(tree.selector);
668+
Set<Object> constants = tree.patternSwitch ? allSwitchConstants(tree.selector) : null;
668669
for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
669670
alive = Liveness.ALIVE;
670671
JCCase c = l.head;
671672
for (JCCaseLabel pat : c.labels) {
672673
scan(pat);
674+
handleConstantCaseLabel(constants, pat);
673675
}
674676
scanStats(c.stats);
675677
c.completesNormally = alive != Liveness.DEAD;
@@ -685,6 +687,10 @@ public void visitSwitch(JCSwitch tree) {
685687
l.tail.head.pos(),
686688
Warnings.PossibleFallThroughIntoCase);
687689
}
690+
if ((constants == null || !constants.isEmpty()) && !tree.hasTotalPattern &&
691+
tree.patternSwitch && !TreeInfo.isErrorEnumSwitch(tree.selector, tree.cases)) {
692+
log.error(tree, Errors.NotExhaustiveStatement);
693+
}
688694
if (!tree.hasTotalPattern) {
689695
alive = Liveness.ALIVE;
690696
}
@@ -696,47 +702,14 @@ public void visitSwitchExpression(JCSwitchExpression tree) {
696702
ListBuffer<PendingExit> prevPendingExits = pendingExits;
697703
pendingExits = new ListBuffer<>();
698704
scan(tree.selector);
699-
Set<Object> constants = null;
700-
TypeSymbol selectorSym = tree.selector.type.tsym;
701-
if ((selectorSym.flags() & ENUM) != 0) {
702-
constants = new HashSet<>();
703-
Predicate<Symbol> enumConstantFilter =
704-
s -> (s.flags() & ENUM) != 0 && s.kind == Kind.VAR;
705-
for (Symbol s : selectorSym.members().getSymbols(enumConstantFilter)) {
706-
constants.add(s.name);
707-
}
708-
} else if (selectorSym.isAbstract() && selectorSym.isSealed() && selectorSym.kind == Kind.TYP) {
709-
constants = new HashSet<>();
710-
constants.addAll(((ClassSymbol) selectorSym).permitted);
711-
}
712-
boolean coversInput = tree.hasTotalPattern;
705+
Set<Object> constants = allSwitchConstants(tree.selector);
713706
Liveness prevAlive = alive;
714707
for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
715708
alive = Liveness.ALIVE;
716709
JCCase c = l.head;
717710
for (JCCaseLabel pat : c.labels) {
718711
scan(pat);
719-
if (constants != null) {
720-
if (pat.isExpression()) {
721-
JCExpression expr = (JCExpression) pat;
722-
if (expr.hasTag(IDENT))
723-
constants.remove(((JCIdent) expr).name);
724-
} else if (pat.isPattern()) {
725-
PatternPrimaryType patternType = TreeInfo.primaryPatternType((JCPattern) pat);
726-
727-
if (patternType.unconditional()) {
728-
constants.remove(patternType.type().tsym);
729-
}
730-
}
731-
}
732-
if (pat.isPattern()) {
733-
PatternPrimaryType patternType = TreeInfo.primaryPatternType((JCPattern) pat);
734-
if (patternType.unconditional() &&
735-
types.isSubtype(types.erasure(tree.selector.type),
736-
types.erasure(patternType.type()))) {
737-
coversInput = true;
738-
}
739-
}
712+
handleConstantCaseLabel(constants, pat);
740713
}
741714
scanStats(c.stats);
742715
if (alive == Liveness.ALIVE) {
@@ -750,14 +723,47 @@ public void visitSwitchExpression(JCSwitchExpression tree) {
750723
}
751724
c.completesNormally = alive != Liveness.DEAD;
752725
}
753-
if ((constants == null || !constants.isEmpty()) && !coversInput &&
726+
if ((constants == null || !constants.isEmpty()) && !tree.hasTotalPattern &&
754727
!TreeInfo.isErrorEnumSwitch(tree.selector, tree.cases)) {
755728
log.error(tree, Errors.NotExhaustive);
756729
}
757730
alive = prevAlive;
758731
alive = alive.or(resolveYields(tree, prevPendingExits));
759732
}
760733

734+
private Set<Object> allSwitchConstants(JCExpression selector) {
735+
Set<Object> constants = null;
736+
TypeSymbol selectorSym = selector.type.tsym;
737+
if ((selectorSym.flags() & ENUM) != 0) {
738+
constants = new HashSet<>();
739+
Predicate<Symbol> enumConstantFilter =
740+
s -> (s.flags() & ENUM) != 0 && s.kind == Kind.VAR;
741+
for (Symbol s : selectorSym.members().getSymbols(enumConstantFilter)) {
742+
constants.add(s.name);
743+
}
744+
} else if (selectorSym.isAbstract() && selectorSym.isSealed() && selectorSym.kind == Kind.TYP) {
745+
constants = new HashSet<>();
746+
constants.addAll(((ClassSymbol) selectorSym).permitted);
747+
}
748+
return constants;
749+
}
750+
751+
private void handleConstantCaseLabel(Set<Object> constants, JCCaseLabel pat) {
752+
if (constants != null) {
753+
if (pat.isExpression()) {
754+
JCExpression expr = (JCExpression) pat;
755+
if (expr.hasTag(IDENT))
756+
constants.remove(((JCIdent) expr).name);
757+
} else if (pat.isPattern()) {
758+
PatternPrimaryType patternType = TreeInfo.primaryPatternType((JCPattern) pat);
759+
760+
if (patternType.unconditional()) {
761+
constants.remove(patternType.type().tsym);
762+
}
763+
}
764+
}
765+
}
766+
761767
public void visitTry(JCTry tree) {
762768
ListBuffer<PendingExit> prevPendingExits = pendingExits;
763769
pendingExits = new ListBuffer<>();

src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3583,18 +3583,25 @@ public void visitReturn(JCReturn tree) {
35833583
}
35843584

35853585
public void visitSwitch(JCSwitch tree) {
3586-
handleSwitch(tree, tree.selector, tree.cases);
3586+
List<JCCase> cases = tree.patternSwitch ? addDefaultIfNeeded(tree.cases) : tree.cases;
3587+
handleSwitch(tree, tree.selector, cases);
35873588
}
35883589

35893590
@Override
35903591
public void visitSwitchExpression(JCSwitchExpression tree) {
3591-
if (tree.cases.stream().flatMap(c -> c.labels.stream()).noneMatch(p -> p.hasTag(Tag.DEFAULTCASELABEL))) {
3592+
List<JCCase> cases = addDefaultIfNeeded(tree.cases);
3593+
handleSwitch(tree, tree.selector, cases);
3594+
}
3595+
3596+
private List<JCCase> addDefaultIfNeeded(List<JCCase> cases) {
3597+
if (cases.stream().flatMap(c -> c.labels.stream()).noneMatch(p -> p.hasTag(Tag.DEFAULTCASELABEL))) {
35923598
JCThrow thr = make.Throw(makeNewClass(syms.incompatibleClassChangeErrorType,
35933599
List.nil()));
35943600
JCCase c = make.Case(JCCase.STATEMENT, List.of(make.DefaultCaseLabel()), List.of(thr), null);
3595-
tree.cases = tree.cases.append(c);
3601+
cases = cases.append(c);
35963602
}
3597-
handleSwitch(tree, tree.selector, tree.cases);
3603+
3604+
return cases;
35983605
}
35993606

36003607
private void handleSwitch(JCTree tree, JCExpression selector, List<JCCase> cases) {

src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
import com.sun.tools.javac.code.Type.ClassType;
7070
import com.sun.tools.javac.code.Type.MethodType;
7171
import com.sun.tools.javac.code.Type.WildcardType;
72+
import com.sun.tools.javac.code.TypeTag;
7273
import static com.sun.tools.javac.code.TypeTag.BOT;
7374
import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
7475
import com.sun.tools.javac.jvm.Target;
@@ -253,26 +254,23 @@ public void visitGuardPattern(JCGuardPattern tree) {
253254

254255
@Override
255256
public void visitSwitch(JCSwitch tree) {
256-
handleSwitch(tree, tree.selector, tree.cases);
257+
handleSwitch(tree, tree.selector, tree.cases, tree.hasTotalPattern, tree.patternSwitch);
257258
}
258259

259260
@Override
260261
public void visitSwitchExpression(JCSwitchExpression tree) {
261-
handleSwitch(tree, tree.selector, tree.cases);
262+
handleSwitch(tree, tree.selector, tree.cases, tree.hasTotalPattern, tree.patternSwitch);
262263
}
263264

264265
private void handleSwitch(JCTree tree,
265266
JCExpression selector,
266-
List<JCCase> cases) {
267+
List<JCCase> cases,
268+
boolean hasTotalPattern,
269+
boolean patternSwitch) {
267270
Type seltype = selector.type;
268271
boolean enumSwitch = (seltype.tsym.flags() & Flags.ENUM) != 0;
269-
boolean stringSwitch = types.isSameType(seltype, syms.stringType);
270-
boolean enhancedType = !types.unboxedTypeOrType(seltype).isPrimitive() &&
271-
!enumSwitch && !stringSwitch;
272-
boolean hasPatternLabels = cases.stream()
273-
.flatMap(c -> c.labels.stream())
274-
.anyMatch(l -> l.isPattern());
275-
if (hasPatternLabels || enhancedType) {
272+
273+
if (patternSwitch) {
276274
Assert.check(preview.isEnabled());
277275
Assert.check(preview.usesPreview(env.toplevel.sourcefile));
278276

@@ -343,6 +341,13 @@ private void handleSwitch(JCTree tree,
343341
.flatMap(c -> c.labels.stream())
344342
.anyMatch(p -> p.isExpression() &&
345343
TreeInfo.isNull((JCExpression) p));
344+
if (hasTotalPattern && !hasNullCase) {
345+
JCCase last = cases.last();
346+
if (last.labels.stream().noneMatch(l -> l.hasTag(Tag.DEFAULTCASELABEL))) {
347+
last.labels = last.labels.prepend(makeLit(syms.botType, null));
348+
hasNullCase = true;
349+
}
350+
}
346351
statements.append(make.at(tree.pos).VarDef(temp, !hasNullCase ? attr.makeNullCheck(selector)
347352
: selector));
348353
VarSymbol index = new VarSymbol(Flags.SYNTHETIC,

src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1376,6 +1376,9 @@ compiler.err.unreachable.stmt=\
13761376
compiler.err.not.exhaustive=\
13771377
the switch expression does not cover all possible input values
13781378

1379+
compiler.err.not.exhaustive.statement=\
1380+
the switch statement does not cover all possible input values
1381+
13791382
compiler.err.initializer.must.be.able.to.complete.normally=\
13801383
initializer must be able to complete normally
13811384

src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1270,6 +1270,7 @@ public static class JCSwitch extends JCStatement implements SwitchTree {
12701270
/** Position of closing brace, optional. */
12711271
public int endpos = Position.NOPOS;
12721272
public boolean hasTotalPattern;
1273+
public boolean patternSwitch;
12731274
protected JCSwitch(JCExpression selector, List<JCCase> cases) {
12741275
this.selector = selector;
12751276
this.cases = cases;
@@ -1355,6 +1356,7 @@ public static class JCSwitchExpression extends JCPolyExpression implements Switc
13551356
/** Position of closing brace, optional. */
13561357
public int endpos = Position.NOPOS;
13571358
public boolean hasTotalPattern;
1359+
public boolean patternSwitch;
13581360
protected JCSwitchExpression(JCExpression selector, List<JCCase> cases) {
13591361
this.selector = selector;
13601362
this.cases = cases;

test/langtools/tools/javac/diags/examples/CantRefNonEffectivelyFinalVar.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ void test2() {
4949
void test3(Object o, int i) {
5050
switch (o) {
5151
case String s && s.length() == i++: break;
52+
default: break;
5253
}
5354
}
5455
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
// key: compiler.err.not.exhaustive.statement
25+
// key: compiler.note.preview.filename
26+
// key: compiler.note.preview.recompile
27+
// options: --enable-preview --source ${jdk.version}
28+
29+
class NotExhaustive {
30+
void t(Object o) {
31+
switch (o) {
32+
case String s -> System.err.println("String of length: " + s.length());
33+
};
34+
}
35+
}

0 commit comments

Comments
 (0)