changeset 50337:45cb2747b2cd switch

Introducing CaseTree.getExpressions() instead of desugaring to consequent cases with fall through in the parser.
author jlahoda
date Fri, 20 Apr 2018 17:31:34 +0200
parents 91076e2839c7
children 5870f172f52b
files src/jdk.compiler/share/classes/com/sun/source/tree/CaseTree.java src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TreeDiffer.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/CRTable.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java test/langtools/tools/javac/lib/DPrinter.java
diffstat 18 files changed, 136 insertions(+), 103 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk.compiler/share/classes/com/sun/source/tree/CaseTree.java	Tue Apr 17 18:19:22 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/CaseTree.java	Fri Apr 20 17:31:34 2018 +0200
@@ -49,11 +49,22 @@
     /**
      * Returns the expression for the case, or
      * {@code null} if this is the default case.
+     * If this case has multiple lables, returns the first label.
      * @return the expression for the case, or null
+     * @deprecated Use {@link #getExpressions()}
      */
+    @Deprecated
     ExpressionTree getExpression();
 
     /**
+     * Returns the labels for this case.
+     * For default case, returns an empty list.
+     * @return labels for this case
+     * @since TBD
+     */
+    List<? extends ExpressionTree> getExpressions();
+
+    /**
      * Returns the statements labeled by the case.
      * If this is a case in switch expression in for
      * {@code case expression -> value}, returns a list
--- a/src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java	Tue Apr 17 18:19:22 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java	Fri Apr 20 17:31:34 2018 +0200
@@ -357,7 +357,7 @@
      */
     @Override
     public R visitCase(CaseTree node, P p) {
-        R r = scan(node.getExpression(), p);
+        R r = scan(node.getExpressions(), p);
         if (node.getCaseKind() == CaseKind.VALUE)
             r = scanAndReduce(node.getValue(), p, r);
         else
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Tue Apr 17 18:19:22 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Fri Apr 20 17:31:34 2018 +0200
@@ -1483,38 +1483,39 @@
             boolean hasDefault = false;      // Is there a default label?
             for (List<JCCase> l = cases; l.nonEmpty(); l = l.tail) {
                 JCCase c = l.head;
-                JCExpression pat = c.pat;
-                if (pat != null) {
-                    if (TreeInfo.isNull(pat)) {
-                        if (!allowNullCase) {
-                            log.error(DiagnosticFlag.SOURCE_LEVEL,
-                                      selector.pos(),
-                                      Feature.SWITCH_CASE_NULL.error(sourceName));
-                        }
-                        //case null:
-                        //TODO: check -source
-                        if (seltype.isPrimitive()) {
-                            log.error(c.pos(), Errors.SwitchNullMustBeReference);
-                        }
-                        if (!labels.add(null)) {
-                            log.error(c.pos(), Errors.DuplicateCaseLabel);
-                        }
-                    } else if (enumSwitch) {
-                        Symbol sym = enumConstant(pat, seltype);
-                        if (sym == null) {
-                            log.error(pat.pos(), Errors.EnumLabelMustBeUnqualifiedEnum);
-                        } else if (!labels.add(sym)) {
-                            log.error(c.pos(), Errors.DuplicateCaseLabel);
-                        }
-                    } else {
-                        Type pattype = attribExpr(pat, switchEnv, unboxedSelType);
-                        if (!pattype.hasTag(ERROR)) {
-                            if (pattype.constValue() == null) {
-                                log.error(pat.pos(),
-                                          (stringSwitch ? Errors.StringConstReq : Errors.ConstExprReq));
-                            } else if (!labels.add(pattype.constValue())) {
+                if (c.getExpressions().nonEmpty()) {
+                    for (JCExpression pat : c.getExpressions()) {
+                        if (TreeInfo.isNull(pat)) {
+                            if (!allowNullCase) {
+                                log.error(DiagnosticFlag.SOURCE_LEVEL,
+                                          selector.pos(),
+                                          Feature.SWITCH_CASE_NULL.error(sourceName));
+                            }
+                            //case null:
+                            //TODO: check -source
+                            if (seltype.isPrimitive()) {
+                                log.error(c.pos(), Errors.SwitchNullMustBeReference);
+                            }
+                            if (!labels.add(null)) {
                                 log.error(c.pos(), Errors.DuplicateCaseLabel);
                             }
+                        } else if (enumSwitch) {
+                            Symbol sym = enumConstant(pat, seltype);
+                            if (sym == null) {
+                                log.error(pat.pos(), Errors.EnumLabelMustBeUnqualifiedEnum);
+                            } else if (!labels.add(sym)) {
+                                log.error(c.pos(), Errors.DuplicateCaseLabel);
+                            }
+                        } else {
+                            Type pattype = attribExpr(pat, switchEnv, unboxedSelType);
+                            if (!pattype.hasTag(ERROR)) {
+                                if (pattype.constValue() == null) {
+                                    log.error(pat.pos(),
+                                              (stringSwitch ? Errors.StringConstReq : Errors.ConstExprReq));
+                                } else if (!labels.add(pattype.constValue())) {
+                                    log.error(c.pos(), Errors.DuplicateCaseLabel);
+                                }
+                            }
                         }
                     }
                 } else if (hasDefault) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java	Tue Apr 17 18:19:22 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java	Fri Apr 20 17:31:34 2018 +0200
@@ -610,12 +610,14 @@
             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
                 alive = true;
                 JCCase c = l.head;
-                if (c.pat == null)
+                if (c.pats.isEmpty())
                     hasDefault = true;
                 else {
-                    scan(c.pat);
-                    if (constants != null) {
-                        constants.remove(c.pat.type.constValue());
+                    for (JCExpression pat : c.pats) {
+                        scan(pat);
+                        if (constants != null) {
+                            constants.remove(pat.type.constValue());
+                        }
                     }
                 }
                 scanStats(c.stats);
@@ -655,15 +657,17 @@
             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
                 alive = true;
                 JCCase c = l.head;
-                if (c.pat == null)
+                if (c.pats.isEmpty())
                     hasDefault = true;
                 else {
-                    scan(c.pat);
-                    if (constants != null) {
-                        if (c.pat.hasTag(IDENT))
-                            constants.remove(((JCIdent) c.pat).name);
-                        if (c.pat.type != null)
-                            constants.remove(c.pat.type.constValue());
+                    for (JCExpression pat : c.pats) {
+                        scan(pat);
+                        if (constants != null) {
+                            if (pat.hasTag(IDENT))
+                                constants.remove(((JCIdent) pat).name);
+                            if (pat.type != null)
+                                constants.remove(pat.type.constValue());
+                        }
                     }
                 }
                 scanStats(c.stats);
@@ -1116,9 +1120,7 @@
             scan(selector);
             for (List<JCCase> l = cases; l.nonEmpty(); l = l.tail) {
                 JCCase c = l.head;
-                if (c.pat != null) {
-                    scan(c.pat);
-                }
+                scan(c.pats);
                 scan(c.stats);
             }
             resolveBreaks(tree, prevPendingExits);
@@ -2200,10 +2202,12 @@
                 inits.assign(initsSwitch);
                 uninits.assign(uninits.andSet(uninitsSwitch));
                 JCCase c = l.head;
-                if (c.pat == null) {
+                if (c.pats.isEmpty()) {
                     hasDefault = true;
                 } else {
-                    scanExpr(c.pat);
+                    for (JCExpression pat : c.pats) {
+                        scanExpr(pat);
+                    }
                 }
                 if (hasDefault) {
                     inits.assign(initsSwitch);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Tue Apr 17 18:19:22 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Fri Apr 20 17:31:34 2018 +0200
@@ -721,7 +721,7 @@
             JCBreak br = make.Break(null);
             breaks.add(br);
             List<JCStatement> stmts = entry.getValue().append(br).toList();
-            cases.add(make.Case(CaseKind.STATEMENT, make.Literal(entry.getKey()), stmts));
+            cases.add(make.Case(CaseKind.STATEMENT, List.of(make.Literal(entry.getKey())), stmts));
         }
         JCSwitch sw = make.Switch(deserGetter("getImplMethodName", syms.stringType), cases.toList());
         for (JCBreak br : breaks) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java	Tue Apr 17 18:19:22 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java	Fri Apr 20 17:31:34 2018 +0200
@@ -3321,6 +3321,29 @@
     }
 
     public void visitSwitch(JCSwitch tree) {
+        //expand multiple label cases:
+        ListBuffer<JCCase> cases = new ListBuffer<>();
+
+        for (JCCase c : tree.cases) {
+            switch (c.pats.size()) {
+                case 0: //default
+                case 1: //single label
+                    cases.append(c);
+                    break;
+                default: //multiple labels, expand:
+                    List<JCExpression> patterns = c.pats;
+                    while (patterns.tail.nonEmpty()) {
+                        cases.append(make.Case(CaseKind.STATEMENT, List.of(patterns.head), List.nil()));
+                        patterns = patterns.tail;
+                    }
+                    c.pats = patterns;
+                    cases.append(c);
+                    break;
+            }
+        }
+
+        tree.cases = cases.toList();
+
         Type selsuper = types.supertype(tree.selector.type);
         boolean enumSwitch = selsuper != null &&
             (tree.selector.type.tsym.flags() & ENUM) != 0;
@@ -3417,14 +3440,14 @@
             
             if (!hasNullCase(tree)) {
                 JCThrow npe = make.Throw(makeNewClass(syms.nullPointerExceptionType, List.nil()));
-                tree.cases = tree.cases.prepend(make.Case(CaseKind.STATEMENT, makeNull(), List.of(npe)));
+                tree.cases = tree.cases.prepend(make.Case(CaseKind.STATEMENT, List.of(makeNull()), List.of(npe)));
             }
 
             int caseIdx = 0;
             
             for (JCCase c : tree.cases) {
-                if (c.pat != null) {
-                    c.pat = make.Literal(isNullCase(c) ? -1 : caseIdx++);
+                if (c.pats.nonEmpty()) {
+                    c.pats = List.of(make.Literal(TreeInfo.isNull(c.pats.head) ? -1 : caseIdx++));
                 }
             }
 
@@ -3478,8 +3501,8 @@
                     indyType,
                     Stream.concat(firstParam,
                                   tree.cases.stream()
-                                            .filter(c -> c.pat != null && !TreeInfo.isNull(c.pat))
-                                            .map(c -> pattern2Label.apply(c.pat))
+                                            .filter(c -> c.pats.nonEmpty() && !TreeInfo.isNull(c.pats.head))
+                                            .map(c -> pattern2Label.apply(c.pats.head))
                                  )
                           .toArray());
 
@@ -3504,10 +3527,10 @@
                                                              ordinalMethod)));
         ListBuffer<JCCase> cases = new ListBuffer<>();
         for (JCCase c : tree.cases) {
-            if (c.pat != null) {
-                VarSymbol label = (VarSymbol)TreeInfo.symbol(c.pat);
+            if (c.pats.nonEmpty()) {
+                VarSymbol label = (VarSymbol)TreeInfo.symbol(c.pats.head);
                 JCLiteral pat = map.forConstant(label);
-                cases.append(make.Case(CaseKind.STATEMENT, pat, c.stats));
+                cases.append(make.Case(CaseKind.STATEMENT, List.of(pat), c.stats));
             } else {
                 cases.append(c);
             }
@@ -3577,9 +3600,8 @@
             int casePosition = 0;
 
             for(JCCase oneCase : caseList) {
-                JCExpression expression = oneCase.getExpression();
-
-                if (expression != null) { // expression for a "default" case is null
+                if (oneCase.pats.nonEmpty()) { // pats is empty for a "default" case
+                    JCExpression expression = oneCase.pats.head;
                     String labelExpr = (String) expression.type.constValue();
                     Integer mapping = caseLabelToPosition.put(labelExpr, casePosition);
                     Assert.checkNull(mapping);
@@ -3663,7 +3685,7 @@
                 breakStmt.target = switch1;
                 lb.append(elsepart).append(breakStmt);
 
-                caseBuffer.append(make.Case(CaseKind.STATEMENT, make.Literal(hashCode), lb.toList()));
+                caseBuffer.append(make.Case(CaseKind.STATEMENT, List.of(make.Literal(hashCode)), lb.toList()));
             }
 
             switch1.cases = caseBuffer.toList();
@@ -3680,17 +3702,16 @@
                 // replacement switch being created.
                 patchTargets(oneCase, tree, switch2);
 
-                boolean isDefault = (oneCase.getExpression() == null);
+                boolean isDefault = (oneCase.pats.isEmpty());
                 JCExpression caseExpr;
                 if (isDefault)
                     caseExpr = null;
                 else {
-                    caseExpr = make.Literal(caseLabelToPosition.get((String)TreeInfo.skipParens(oneCase.
-                                                                                                getExpression()).
+                    caseExpr = make.Literal(caseLabelToPosition.get((String)TreeInfo.skipParens(oneCase.pats.head).
                                                                     type.constValue()));
                 }
 
-                lb.append(make.Case(CaseKind.STATEMENT, caseExpr,
+                lb.append(make.Case(CaseKind.STATEMENT, caseExpr == null ? List.nil() : List.of(caseExpr),
                                     oneCase.getStatements()));
             }
 
@@ -3702,11 +3723,7 @@
     }
 
     private boolean hasNullCase(JCSwitch tree) {
-        return tree.cases.stream().anyMatch(this::isNullCase);
-    }
-
-    private boolean isNullCase(JCCase c) {
-        return c.pat != null && TreeInfo.isNull(c.pat);
+        return tree.cases.stream().flatMap(c -> c.pats.stream()).anyMatch(TreeInfo::isNull);
     }
 
     @Override
@@ -3721,9 +3738,9 @@
         stmtList.append(make.at(tree.pos()).VarDef(dollar_switchexpr, null).setType(dollar_switchexpr.type));
         JCSwitch switchStatement = make.Switch(tree.selector, null);
         switchStatement.cases = tree.cases.stream().map(c -> convertCase(dollar_switchexpr, switchStatement, tree, c)).collect(List.collector());
-        if (tree.cases.stream().noneMatch(c -> c.pat == null)) {
+        if (tree.cases.stream().noneMatch(c -> c.pats.isEmpty())) {
             JCThrow thr = make.Throw(makeNewClass(syms.incompatibleClassChangeErrorType, List.nil()));
-            switchStatement.cases = switchStatement.cases.append(make.Case(CaseKind.STATEMENT, null, List.of(thr)));
+            switchStatement.cases = switchStatement.cases.append(make.Case(CaseKind.STATEMENT, List.nil(), List.of(thr)));
         }
         stmtList.append(translate(switchStatement));
 
@@ -3752,7 +3769,7 @@
                     }
                 }
             }.translate(c.stats));
-            return make.Case(CaseKind.STATEMENT, c.pat, statements.toList());
+            return make.Case(CaseKind.STATEMENT, c.pats, statements.toList());
         }
 
     public void visitNewArray(JCNewArray tree) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java	Tue Apr 17 18:19:22 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java	Fri Apr 20 17:31:34 2018 +0200
@@ -613,7 +613,7 @@
     }
 
     public void visitCase(JCCase tree) {
-        tree.pat = translate(tree.pat, null);
+        tree.pats = translate(tree.pats, null);
         tree.stats = translate(tree.stats);
         result = tree;
     }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TreeDiffer.java	Tue Apr 17 18:19:22 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TreeDiffer.java	Fri Apr 20 17:31:34 2018 +0200
@@ -265,7 +265,7 @@
     @Override
     public void visitCase(JCCase tree) {
         JCCase that = (JCCase) parameter;
-        result = scan(tree.pat, that.pat) && scan(tree.stats, that.stats);
+        result = scan(tree.pats, that.pats) && scan(tree.stats, that.stats);
     }
 
     @Override
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/CRTable.java	Tue Apr 17 18:19:22 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/CRTable.java	Fri Apr 20 17:31:34 2018 +0200
@@ -313,7 +313,7 @@
 
         public void visitCase(JCCase tree) {
             SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
-            sr.mergeWith(csp(tree.pat));
+            sr.mergeWith(csp(tree.pats));
             sr.mergeWith(csp(tree.stats));
             result = sr;
         }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Tue Apr 17 18:19:22 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Fri Apr 20 17:31:34 2018 +0200
@@ -1149,8 +1149,9 @@
 
             List<JCCase> l = cases;
             for (int i = 0; i < labels.length; i++) {
-                if (l.head.pat != null) {
-                    int val = ((Number)l.head.pat.type.constValue()).intValue();
+                if (l.head.pats.nonEmpty()) {
+                    Assert.check(l.head.pats.size() == 1);
+                    int val = ((Number)l.head.pats.head.type.constValue()).intValue();
                     labels[i] = val;
                     if (val < lo) lo = val;
                     if (hi < val) hi = val;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java	Tue Apr 17 18:19:22 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java	Fri Apr 20 17:31:34 2018 +0200
@@ -1391,19 +1391,17 @@
     private List<JCCase> switchExpressionStatementGroup() {
         ListBuffer<JCCase> caseExprs = new ListBuffer<>();
         int casePos = token.pos;
-        JCExpression pat;
+        ListBuffer<JCExpression> pats = new ListBuffer<>();
 
         if (token.kind == DEFAULT) {
             nextToken();
-            pat = null;
         } else {
             accept(CASE);
             while (true) {
-                pat = term(EXPR | NOLAMBDA);
+                pats.append(term(EXPR | NOLAMBDA));
                 if (token.kind != COMMA) break;
                 checkSourceLevel(Feature.SWITCH_MULTIPLE_CASE_LABELS);
                 nextToken();
-                caseExprs.append(toP(F.at(casePos).Case(CaseKind.STATEMENT, pat, List.nil())));
             };
         }
         List<JCStatement> stats = null;
@@ -1428,7 +1426,7 @@
                 kind = CaseKind.STATEMENT;
                 break;
         }
-        caseExprs.append(toP(F.at(casePos).Case(kind, pat, stats)));
+        caseExprs.append(toP(F.at(casePos).Case(kind, pats.toList(), stats)));
         return caseExprs.toList();
     }
 
@@ -2804,19 +2802,16 @@
         switch (token.kind) {
         case CASE:
             nextToken();
-            JCExpression pat;
+            ListBuffer<JCExpression> pats = new ListBuffer<>();
             while (true) {
-                pat = parseExpression();
+                pats.append(parseExpression());
                 if (token.kind != COMMA) break;
                 nextToken();
                 checkSourceLevel(Feature.SWITCH_MULTIPLE_CASE_LABELS);
-                c = F.at(pos).Case(CaseKind.STATEMENT, pat, List.nil());
-                storeEnd(c, S.prevToken().endPos);
-                cases.append(c);
             };
             accept(COLON);
             stats = blockStatements();
-            c = F.at(pos).Case(CaseKind.STATEMENT, pat, stats);
+            c = F.at(pos).Case(CaseKind.STATEMENT, pats.toList(), stats);
             if (stats.isEmpty())
                 storeEnd(c, S.prevToken().endPos);
             return cases.append(c).toList();
@@ -2824,7 +2819,7 @@
             nextToken();
             accept(COLON);
             stats = blockStatements();
-            c = F.at(pos).Case(CaseKind.STATEMENT, null, stats);
+            c = F.at(pos).Case(CaseKind.STATEMENT, List.nil(), stats);
             if (stats.isEmpty())
                 storeEnd(c, S.prevToken().endPos);
             return cases.append(c).toList();
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java	Tue Apr 17 18:19:22 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java	Fri Apr 20 17:31:34 2018 +0200
@@ -1249,11 +1249,13 @@
      */
     public static class JCCase extends JCStatement implements CaseTree {
         public final CaseKind caseKind;
-        public JCExpression pat;
+        public List<JCExpression> pats;
         public List<JCStatement> stats;
-        protected JCCase(CaseKind caseKind, JCExpression pat, List<JCStatement> stats) {
+        protected JCCase(CaseKind caseKind, List<JCExpression> pats, List<JCStatement> stats) {
+            Assert.checkNonNull(pats);
+            Assert.check(pats.isEmpty() || pats.head != null);
             this.caseKind = caseKind;
-            this.pat = pat;
+            this.pats = pats;
             this.stats = stats;
         }
         @Override
@@ -1261,8 +1263,10 @@
 
         @Override @DefinedBy(Api.COMPILER_TREE)
         public Kind getKind() { return Kind.CASE; }
+        @Override @Deprecated @DefinedBy(Api.COMPILER_TREE)
+        public JCExpression getExpression() { return pats.head; }
         @Override @DefinedBy(Api.COMPILER_TREE)
-        public JCExpression getExpression() { return pat; }
+        public List<JCExpression> getExpressions() { return pats; }
         @DefinedBy(Api.COMPILER_TREE)
         public List<JCStatement> getStatements() { return stats; }
         @DefinedBy(Api.COMPILER_TREE)
@@ -3050,7 +3054,7 @@
         JCLabeledStatement Labelled(Name label, JCStatement body);
         JCSwitch Switch(JCExpression selector, List<JCCase> cases);
         JCSwitchExpression SwitchExpression(JCExpression selector, List<JCCase> cases);
-        JCCase Case(CaseKind caseKind, JCExpression pat, List<JCStatement> stats);
+        JCCase Case(CaseKind caseKind, List<JCExpression> pat, List<JCStatement> stats);
         JCSynchronized Synchronized(JCExpression lock, JCBlock body);
         JCTry Try(JCBlock body, List<JCCatch> catchers, JCBlock finalizer);
         JCTry Try(List<JCTree> resources,
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java	Tue Apr 17 18:19:22 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java	Fri Apr 20 17:31:34 2018 +0200
@@ -835,11 +835,11 @@
 
     public void visitCase(JCCase tree) {
         try {
-            if (tree.pat == null) {
+            if (tree.pats.isEmpty()) {
                 print("default");
             } else {
                 print("case ");
-                printExpr(tree.pat);
+                printExprs(tree.pats);
             }
             print(": "); //XXX
             println();
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java	Tue Apr 17 18:19:22 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java	Fri Apr 20 17:31:34 2018 +0200
@@ -147,9 +147,9 @@
     @DefinedBy(Api.COMPILER_TREE)
     public JCTree visitCase(CaseTree node, P p) {
         JCCase t = (JCCase) node;
-        JCExpression pat = copy(t.pat, p);
+        List<JCExpression> pats = copy(t.pats, p);
         List<JCStatement> stats = copy(t.stats, p);
-        return M.at(t.pos).Case(t.caseKind, pat, stats);
+        return M.at(t.pos).Case(t.caseKind, pats, stats);
     }
 
     @DefinedBy(Api.COMPILER_TREE)
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java	Tue Apr 17 18:19:22 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java	Fri Apr 20 17:31:34 2018 +0200
@@ -273,8 +273,8 @@
         return tree;
     }
 
-    public JCCase Case(CaseKind caseKind, JCExpression pat, List<JCStatement> stats) {
-        JCCase tree = new JCCase(caseKind, pat, stats);
+    public JCCase Case(CaseKind caseKind, List<JCExpression> pats, List<JCStatement> stats) {
+        JCCase tree = new JCCase(caseKind, pats, stats);
         tree.pos = pos;
         return tree;
     }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java	Tue Apr 17 18:19:22 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java	Fri Apr 20 17:31:34 2018 +0200
@@ -176,7 +176,7 @@
     }
 
     public void visitCase(JCCase tree) {
-        scan(tree.pat);
+        scan(tree.pats);
         scan(tree.stats);
     }
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java	Tue Apr 17 18:19:22 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java	Fri Apr 20 17:31:34 2018 +0200
@@ -207,7 +207,7 @@
     }
 
     public void visitCase(JCCase tree) {
-        tree.pat = translate(tree.pat);
+        tree.pats = translate(tree.pats);
         tree.stats = translate(tree.stats);
         result = tree;
     }
--- a/test/langtools/tools/javac/lib/DPrinter.java	Tue Apr 17 18:19:22 2018 +0200
+++ b/test/langtools/tools/javac/lib/DPrinter.java	Fri Apr 20 17:31:34 2018 +0200
@@ -736,7 +736,7 @@
 
         @Override
         public void visitCase(JCCase tree) {
-            printTree("pat", tree.pat);
+            printList("pat", tree.pats);
             printList("stats", tree.stats);
         }