changeset 50338:5870f172f52b switch

A crude prototype of the new switch unification proposal.
author jlahoda
date Fri, 20 Apr 2018 17:32:32 +0200
parents 45cb2747b2cd
children d557ba6ef129
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/jvm/Gen.java src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.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 test/langtools/tools/javac/expswitch/ExpSwitchNestingTest.java test/langtools/tools/javac/switchexpr/ExpressionSwitch.java test/langtools/tools/javac/switchexpr/ExpressionSwitchBugs.java test/langtools/tools/javac/switchexpr/ExpressionSwitchFallThrough.java test/langtools/tools/javac/switchexpr/ExpressionSwitchFallThrough1.java test/langtools/tools/javac/switchexpr/ExpressionSwitchFallThrough1.out test/langtools/tools/javac/switchextra/MultipleLabelsExpression.java test/langtools/tools/javac/switchextra/SwitchStatementArrow.java test/langtools/tools/javac/switchextra/SwitchStatementBroken.java test/langtools/tools/javac/switchextra/SwitchStatementBroken.out test/langtools/tools/javac/tree/SourceTreeScannerTest.java test/langtools/tools/javac/tree/TreePosTest.java
diffstat 23 files changed, 304 insertions(+), 51 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk.compiler/share/classes/com/sun/source/tree/CaseTree.java	Fri Apr 20 17:31:34 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/CaseTree.java	Fri Apr 20 17:32:32 2018 +0200
@@ -76,13 +76,13 @@
 
     /**
      * If this is a case in switch expression in for
-     * {@linkplain CaseKind#VALUE}, the value of
+     * {@linkplain CaseKind#ARROW}, the right-hand-side of
      * the case, null otherwise.
      * 
      * @return case value or null
      * @since TBD
      */
-    public default ExpressionTree getValue() {
+    public default Tree getBody() {
         return null;
     }
 
@@ -113,10 +113,6 @@
         /**
          * Case is in the form: {@code case <expression> -> <expression>}.
          */
-        VALUE,
-        /**
-         * Case is in the form: {@code case <expression> -> throw ...}.
-         */
-        THROW;
+        ARROW;
     }
 }
--- a/src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java	Fri Apr 20 17:31:34 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java	Fri Apr 20 17:32:32 2018 +0200
@@ -358,8 +358,8 @@
     @Override
     public R visitCase(CaseTree node, P p) {
         R r = scan(node.getExpressions(), p);
-        if (node.getCaseKind() == CaseKind.VALUE)
-            r = scanAndReduce(node.getValue(), p, r);
+        if (node.getCaseKind() == CaseKind.ARROW)
+            r = scanAndReduce(node.getBody(), p, r);
         else
             r = scanAndReduce(node.getStatements(), p, r);
         return r;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Fri Apr 20 17:31:34 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Fri Apr 20 17:32:32 2018 +0200
@@ -31,6 +31,7 @@
 import javax.lang.model.element.ElementKind;
 import javax.tools.JavaFileObject;
 
+import com.sun.source.tree.CaseTree.CaseKind;
 import com.sun.source.tree.IdentifierTree;
 import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
 import com.sun.source.tree.MemberSelectTree;
@@ -1481,8 +1482,17 @@
             // check that there are no duplicate case labels or default clauses.
             Set<Object> labels = new HashSet<>(); // The set of case labels.
             boolean hasDefault = false;      // Is there a default label?
+            CaseKind caseKind = null;
+            boolean wasError = false;
             for (List<JCCase> l = cases; l.nonEmpty(); l = l.tail) {
                 JCCase c = l.head;
+                if (caseKind == null) {
+                    caseKind = c.caseKind;
+                } else if (caseKind != c.caseKind && !wasError) {
+                    log.error(c.pos(),
+                              Errors.SwitchMixingCaseTypes);
+                    wasError = true;
+                }
                 if (c.getExpressions().nonEmpty()) {
                     for (JCExpression pat : c.getExpressions()) {
                         if (TreeInfo.isNull(pat)) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java	Fri Apr 20 17:31:34 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java	Fri Apr 20 17:32:32 2018 +0200
@@ -31,6 +31,7 @@
 import java.util.HashSet;
 import java.util.Set;
 
+import com.sun.source.tree.CaseTree.CaseKind;
 import com.sun.source.tree.LambdaExpressionTree.BodyKind;
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.code.Scope.WriteableScope;
@@ -621,8 +622,9 @@
                     }
                 }
                 scanStats(c.stats);
+                c.completesNormally = alive;
                 // Warn about fall-through if lint switch fallthrough enabled.
-                if (alive &&
+                if (alive && c.caseKind == CaseKind.STATEMENT &&
                     lint.isEnabled(Lint.LintCategory.FALLTHROUGH) &&
                     c.stats.nonEmpty() && l.tail.nonEmpty())
                     log.warning(Lint.LintCategory.FALLTHROUGH,
@@ -671,6 +673,7 @@
                     }
                 }
                 scanStats(c.stats);
+                c.completesNormally = alive;
             }
             if ((constants == null || !constants.isEmpty()) && !hasDefault) {
                 log.error(tree, Errors.NotExhaustive);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Fri Apr 20 17:31:34 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Fri Apr 20 17:32:32 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, List.of(make.Literal(entry.getKey())), stmts));
+            cases.add(make.Case(CaseKind.STATEMENT, List.of(make.Literal(entry.getKey())), stmts, null));
         }
         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	Fri Apr 20 17:31:34 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java	Fri Apr 20 17:32:32 2018 +0200
@@ -3333,7 +3333,7 @@
                 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()));
+                        cases.append(make.Case(CaseKind.STATEMENT, List.of(patterns.head), List.nil(), null));
                         patterns = patterns.tail;
                     }
                     c.pats = patterns;
@@ -3341,6 +3341,14 @@
                     break;
             }
         }
+        
+        for (JCCase c : cases) {
+            if (c.caseKind == CaseKind.ARROW && c.completesNormally) {
+                JCBreak b = make.Break(null);
+                b.target = tree;
+                c.stats = c.stats.append(b);
+            }
+        }
 
         tree.cases = cases.toList();
 
@@ -3440,7 +3448,7 @@
             
             if (!hasNullCase(tree)) {
                 JCThrow npe = make.Throw(makeNewClass(syms.nullPointerExceptionType, List.nil()));
-                tree.cases = tree.cases.prepend(make.Case(CaseKind.STATEMENT, List.of(makeNull()), List.of(npe)));
+                tree.cases = tree.cases.prepend(make.Case(CaseKind.STATEMENT, List.of(makeNull()), List.of(npe), null));
             }
 
             int caseIdx = 0;
@@ -3530,7 +3538,7 @@
             if (c.pats.nonEmpty()) {
                 VarSymbol label = (VarSymbol)TreeInfo.symbol(c.pats.head);
                 JCLiteral pat = map.forConstant(label);
-                cases.append(make.Case(CaseKind.STATEMENT, List.of(pat), c.stats));
+                cases.append(make.Case(CaseKind.STATEMENT, List.of(pat), c.stats, null));
             } else {
                 cases.append(c);
             }
@@ -3685,7 +3693,7 @@
                 breakStmt.target = switch1;
                 lb.append(elsepart).append(breakStmt);
 
-                caseBuffer.append(make.Case(CaseKind.STATEMENT, List.of(make.Literal(hashCode)), lb.toList()));
+                caseBuffer.append(make.Case(CaseKind.STATEMENT, List.of(make.Literal(hashCode)), lb.toList(), null));
             }
 
             switch1.cases = caseBuffer.toList();
@@ -3712,7 +3720,7 @@
                 }
 
                 lb.append(make.Case(CaseKind.STATEMENT, caseExpr == null ? List.nil() : List.of(caseExpr),
-                                    oneCase.getStatements()));
+                                    oneCase.getStatements(), null));
             }
 
             switch2.cases = lb.toList();
@@ -3740,7 +3748,7 @@
         switchStatement.cases = tree.cases.stream().map(c -> convertCase(dollar_switchexpr, switchStatement, tree, c)).collect(List.collector());
         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, List.nil(), List.of(thr)));
+            switchStatement.cases = switchStatement.cases.append(make.Case(CaseKind.STATEMENT, List.nil(), List.of(thr), null));
         }
         stmtList.append(translate(switchStatement));
 
@@ -3769,7 +3777,7 @@
                     }
                 }
             }.translate(c.stats));
-            return make.Case(CaseKind.STATEMENT, c.pats, statements.toList());
+            return make.Case(CaseKind.STATEMENT, c.pats, statements.toList(), null);
         }
 
     public void visitNewArray(JCNewArray tree) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Fri Apr 20 17:31:34 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Fri Apr 20 17:32:32 2018 +0200
@@ -332,6 +332,9 @@
      *  Mark beginning of gap in catch all range for finalizer.
      */
     void genFinalizer(Env<GenContext> env) {
+        if (env == null || env.info == null) {
+            System.err.println("XXX");
+        }
         if (code.isAlive() && env.info.finalize != null)
             env.info.finalize.gen();
     }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java	Fri Apr 20 17:31:34 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java	Fri Apr 20 17:32:32 2018 +0200
@@ -31,6 +31,7 @@
 import com.sun.source.tree.CaseTree.CaseKind;
 import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
 import com.sun.source.tree.ModuleTree.ModuleKind;
+import com.sun.source.tree.Tree;
 
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.code.Source.Feature;
@@ -1405,18 +1406,19 @@
             };
         }
         List<JCStatement> stats = null;
+        JCTree body = null;
         CaseKind kind;
         switch (token.kind) {
             case ARROW:
                 nextToken();
-                if (token.kind == TokenKind.THROW) {
-                    //TODO: record the arrow used?
+                if (token.kind == TokenKind.THROW || token.kind == TokenKind.LBRACE) {
                     stats = List.of(parseStatement());
-                    kind = CaseKind.THROW;
+                    body = stats.head;
+                    kind = CaseKind.ARROW;
                 } else {
                     JCExpression value = parseExpression();
                     stats = List.of(to(F.at(value).Break(value)));
-                    kind = CaseKind.VALUE;
+                    kind = CaseKind.ARROW;
                     accept(SEMI);
                 }
                 break;
@@ -1426,7 +1428,7 @@
                 kind = CaseKind.STATEMENT;
                 break;
         }
-        caseExprs.append(toP(F.at(casePos).Case(kind, pats.toList(), stats)));
+        caseExprs.append(toP(F.at(casePos).Case(kind, pats.toList(), stats, body)));
         return caseExprs.toList();
     }
 
@@ -2800,30 +2802,52 @@
         JCCase c;
         ListBuffer<JCCase> cases = new ListBuffer<JCCase>();
         switch (token.kind) {
-        case CASE:
+        case CASE: {
             nextToken();
             ListBuffer<JCExpression> pats = new ListBuffer<>();
             while (true) {
-                pats.append(parseExpression());
+                pats.append(term(EXPR | NOLAMBDA));
                 if (token.kind != COMMA) break;
                 nextToken();
                 checkSourceLevel(Feature.SWITCH_MULTIPLE_CASE_LABELS);
             };
-            accept(COLON);
-            stats = blockStatements();
-            c = F.at(pos).Case(CaseKind.STATEMENT, pats.toList(), stats);
+            CaseKind caseKind;
+            JCTree body = null;
+            if (token.kind == ARROW) {
+                accept(ARROW);
+                caseKind = CaseKind.ARROW;
+                stats = List.of(parseStatementAsBlock());
+                body = stats.head;
+            } else {
+                accept(COLON);
+                caseKind = CaseKind.STATEMENT;
+                stats = blockStatements();
+            }
+            c = F.at(pos).Case(caseKind, pats.toList(), stats, body);
             if (stats.isEmpty())
                 storeEnd(c, S.prevToken().endPos);
             return cases.append(c).toList();
-        case DEFAULT:
+        }
+        case DEFAULT: {
             nextToken();
-            accept(COLON);
-            stats = blockStatements();
-            c = F.at(pos).Case(CaseKind.STATEMENT, List.nil(), stats);
+            CaseKind caseKind;
+            JCTree body = null;
+            if (token.kind == COLON) {
+                accept(COLON);
+                caseKind = CaseKind.STATEMENT;
+                stats = blockStatements();
+            } else {
+                accept(ARROW);
+                caseKind = CaseKind.ARROW;
+                stats = List.of(parseStatementAsBlock());
+                body = stats.head;
+            }
+            c = F.at(pos).Case(caseKind, List.nil(), stats, body);
             if (stats.isEmpty())
                 storeEnd(c, S.prevToken().endPos);
             return cases.append(c).toList();
         }
+        }
         throw new AssertionError("should not reach here");
     }
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Fri Apr 20 17:31:34 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Fri Apr 20 17:32:32 2018 +0200
@@ -3305,3 +3305,5 @@
 compiler.err.switch.invalid.type=\
     the switch selector must be either String, enum, a primitive type or a boxed primitive type, found: {0}
 
+compiler.err.switch.mixing.case.types=\
+    different case kinds used in the switch
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java	Fri Apr 20 17:31:34 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java	Fri Apr 20 17:32:32 2018 +0200
@@ -1251,12 +1251,15 @@
         public final CaseKind caseKind;
         public List<JCExpression> pats;
         public List<JCStatement> stats;
-        protected JCCase(CaseKind caseKind, List<JCExpression> pats, List<JCStatement> stats) {
+        public JCTree body;
+        public boolean completesNormally;
+        protected JCCase(CaseKind caseKind, List<JCExpression> pats, List<JCStatement> stats, JCTree body) {
             Assert.checkNonNull(pats);
             Assert.check(pats.isEmpty() || pats.head != null);
             this.caseKind = caseKind;
             this.pats = pats;
             this.stats = stats;
+            this.body = body;
         }
         @Override
         public void accept(Visitor v) { v.visitCase(this); }
@@ -1270,7 +1273,7 @@
         @DefinedBy(Api.COMPILER_TREE)
         public List<JCStatement> getStatements() { return stats; }
         @DefinedBy(Api.COMPILER_TREE)
-        public JCExpression getValue() { return caseKind == CaseKind.VALUE ? ((JCBreak) stats.head).value : null; }
+        public JCTree getBody() { return body; }
         @Override
         public CaseKind getCaseKind() {
             return caseKind;
@@ -3054,7 +3057,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, List<JCExpression> pat, List<JCStatement> stats);
+        JCCase Case(CaseKind caseKind, List<JCExpression> pat, List<JCStatement> stats, JCTree body);
         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/TreeCopier.java	Fri Apr 20 17:31:34 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java	Fri Apr 20 17:32:32 2018 +0200
@@ -149,7 +149,8 @@
         JCCase t = (JCCase) node;
         List<JCExpression> pats = copy(t.pats, p);
         List<JCStatement> stats = copy(t.stats, p);
-        return M.at(t.pos).Case(t.caseKind, pats, stats);
+        JCTree body = copy(t.body, p);
+        return M.at(t.pos).Case(t.caseKind, pats, stats, body);
     }
 
     @DefinedBy(Api.COMPILER_TREE)
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java	Fri Apr 20 17:31:34 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java	Fri Apr 20 17:32:32 2018 +0200
@@ -273,8 +273,8 @@
         return tree;
     }
 
-    public JCCase Case(CaseKind caseKind, List<JCExpression> pats, List<JCStatement> stats) {
-        JCCase tree = new JCCase(caseKind, pats, stats);
+    public JCCase Case(CaseKind caseKind, List<JCExpression> pats, List<JCStatement> stats, JCTree body) {
+        JCCase tree = new JCCase(caseKind, pats, stats, body);
         tree.pos = pos;
         return tree;
     }
--- a/test/langtools/tools/javac/expswitch/ExpSwitchNestingTest.java	Fri Apr 20 17:31:34 2018 +0200
+++ b/test/langtools/tools/javac/expswitch/ExpSwitchNestingTest.java	Fri Apr 20 17:32:32 2018 +0200
@@ -18,7 +18,7 @@
     private static final String WHILE = "while (cond) { # }";
     private static final String DO = "do { # } while (cond);";
     private static final String SSWITCH = "switch (x) { case 0: # };";
-    private static final String ESWITCH = "int res = switch (x) { case 0: # default -> 0; };";
+    private static final String ESWITCH = "int res = switch (x) { case 0 -> { # } default -> 0; };";
     private static final String IF = "if (cond) { # }";
     private static final String BLOCK = "{ # }";
     private static final String BREAK_Z = "break 0;";
--- a/test/langtools/tools/javac/switchexpr/ExpressionSwitch.java	Fri Apr 20 17:31:34 2018 +0200
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitch.java	Fri Apr 20 17:32:32 2018 +0200
@@ -48,17 +48,17 @@
         return switch (t) {
             case null -> "NULL";
             case A -> "A";
-            case B -> "B";
-            default: break "other";
+            case B -> { break "B"; }
+            default -> { break "other"; }
         };
     }
 
     private String exhaustive1(T t) {
         return switch (t) {
             case A -> "A";
-            case B -> "B";
+            case B -> { break "B"; }
             case C -> "C";
-            case D: break "D";
+            case D -> "D";
         };
     }
 
@@ -68,7 +68,7 @@
             case A -> "A";
             case B -> "B";
             case C -> "C";
-            case D: break "D";
+            case D -> "D";
         };
     }
 
--- a/test/langtools/tools/javac/switchexpr/ExpressionSwitchBugs.java	Fri Apr 20 17:31:34 2018 +0200
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchBugs.java	Fri Apr 20 17:32:32 2018 +0200
@@ -56,7 +56,7 @@
         check(42, id(switch (42) {
             case 42: if (i == 0) {
                 break 41 + switch (true) {
-                    case true: break 1;
+                    case true -> 1;
                     default -> -1;
                 };
             }
--- a/test/langtools/tools/javac/switchexpr/ExpressionSwitchFallThrough.java	Fri Apr 20 17:31:34 2018 +0200
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchFallThrough.java	Fri Apr 20 17:32:32 2018 +0200
@@ -60,7 +60,7 @@
         return switch (t) {
             case A: help = "a";
             case B: help += "b";
-            default -> help;
+            default: break help;
         };
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitchFallThrough1.java	Fri Apr 20 17:32:32 2018 +0200
@@ -0,0 +1,79 @@
+
+import java.util.Objects;
+
+/*
+ * Copyright (c) 2017, 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.
+ */
+
+/**
+ * @test
+ * @compile ExpressionSwitchFallThrough1.java
+ * @run main ExpressionSwitchFallThrough1
+ */
+// * @compile/fail/ref=ExpressionSwitchFallThrough.out -XDrawDiagnistics ExpressionSwitchFallThrough.java
+
+public class ExpressionSwitchFallThrough1 {
+    public static void main(String... args) {
+        new ExpressionSwitchFallThrough1().test();
+    }
+
+    private void test() {
+        assertEquals("NULL01", printExprFallThrough(null));
+        assertEquals("01", printExprFallThrough(0));
+        assertEquals("1", printExprFallThrough(1));
+        assertEquals("other", printExprFallThrough(3));
+        assertEquals("NULL01", printStatementFallThrough(null));
+        assertEquals("01", printStatementFallThrough(0));
+        assertEquals("1", printStatementFallThrough(1));
+        assertEquals("other", printStatementFallThrough(3));
+    }
+
+    private String printExprFallThrough(Integer p) {
+        String result = "";
+        return switch (p) {
+            case null: result += "NULL";
+            case 0: result += "0";
+            case 1: result += "1";
+                break result;
+            default: break "other";
+        };
+    }
+
+    private String printStatementFallThrough(Integer p) {
+        String result = "";
+        switch (p) {
+            case null: result += "NULL";
+            case 0: result += "0";
+            case 1: result += "1";
+                break ;
+            default: result = "other";
+                break;
+        }
+        return result;
+    }
+
+    private static void assertEquals(Object expected, Object actual) {
+        if (!Objects.equals(actual, expected)) {
+            throw new AssertionError("Unexpected result: " + actual + ", expected: " + expected);
+        }
+    }
+}
--- a/test/langtools/tools/javac/switchextra/MultipleLabelsExpression.java	Fri Apr 20 17:31:34 2018 +0200
+++ b/test/langtools/tools/javac/switchextra/MultipleLabelsExpression.java	Fri Apr 20 17:32:32 2018 +0200
@@ -52,7 +52,7 @@
     private String expression1(T t) {
         return switch (t) {
             case null, A -> "NULL-A";
-            case B, C: break "B-C";
+            case B, C -> { break "B-C"; }
             case D -> "D";
             default -> "other";
         };
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/SwitchStatementArrow.java	Fri Apr 20 17:32:32 2018 +0200
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2018, 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.
+ */
+
+/**
+ * @test
+ * @compile SwitchStatementArrow.java
+ * @run main SwitchStatementArrow
+ */
+// * @compile/fail/ref=MultipleLabelsStatement-old.out -source 9 -Xlint:-options -XDrawDiagnostics MultipleLabelsStatement.java
+
+import java.util.Objects;
+import java.util.function.Function;
+
+public class SwitchStatementArrow {
+    public static void main(String... args) {
+        new SwitchStatementArrow().run();
+    }
+
+    private void run() {
+        runTest(this::statement1);
+    }
+
+    private void runTest(Function<T, String> print) {
+        check(null, print, "NULL-A");
+        check(T.A,  print, "NULL-A");
+        check(T.B,  print, "B-C");
+        check(T.C,  print, "B-C");
+        try {
+            print.apply(T.D);
+            throw new AssertionError();
+        } catch (IllegalStateException ex) {
+            if (!Objects.equals("D", ex.getMessage()))
+                throw new AssertionError(ex);
+        }
+        check(T.E,  print, "other");
+    }
+
+    private String statement1(T t) {
+        String res;
+
+        switch (t) {
+            case null, A -> { res = "NULL-A"; }
+            case B, C -> res = "B-C";
+            case D -> throw new IllegalStateException("D");
+            default -> { res = "other"; break; }
+        }
+
+        return res;
+    }
+
+    private void check(T t, Function<T, String> print, String expected) {
+        String result = print.apply(t);
+        if (!Objects.equals(result, expected)) {
+            throw new AssertionError("Unexpected result: " + result);
+        }
+    }
+
+    enum T {
+        A, B, C, D, E;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/SwitchStatementBroken.java	Fri Apr 20 17:32:32 2018 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2018, 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.
+ */
+
+/**
+ * @test
+ * @compile/fail/ref=SwitchStatementBroken.out -XDrawDiagnostics SwitchStatementBroken.java
+ */
+// * @compile/fail/ref=MultipleLabelsStatement-old.out -source 9 -Xlint:-options -XDrawDiagnostics MultipleLabelsStatement.java
+
+public class SwitchStatementBroken {
+
+    private void statementBroken(int i) {
+        String res;
+
+        switch (i) {
+            case 0 -> { res = "NULL-A"; }
+            case 1: { res = "NULL-A"; break; }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/switchextra/SwitchStatementBroken.out	Fri Apr 20 17:32:32 2018 +0200
@@ -0,0 +1,2 @@
+SwitchStatementBroken.java:37:13: compiler.err.switch.mixing.case.types
+1 error
--- a/test/langtools/tools/javac/tree/SourceTreeScannerTest.java	Fri Apr 20 17:31:34 2018 +0200
+++ b/test/langtools/tools/javac/tree/SourceTreeScannerTest.java	Fri Apr 20 17:32:32 2018 +0200
@@ -154,10 +154,10 @@
                             // but the embedded annotations will be.
                             reflectiveScan(((JCModuleDecl) tree).mods.annotations);
                         } else if (tree instanceof JCCase &&
-                                   ((JCCase) tree).getCaseKind() == CaseKind.VALUE &&
+                                   ((JCCase) tree).getCaseKind() == CaseKind.ARROW &&
                                    f.getName().equals("stats")) {
                             //value case, visit value:
-                            reflectiveScan(((JCCase) tree).getValue());
+                            reflectiveScan(((JCCase) tree).getBody());
                         } else {
                             reflectiveScan(f.get(tree));
                         }
--- a/test/langtools/tools/javac/tree/TreePosTest.java	Fri Apr 20 17:31:34 2018 +0200
+++ b/test/langtools/tools/javac/tree/TreePosTest.java	Fri Apr 20 17:32:32 2018 +0200
@@ -444,8 +444,8 @@
 
         @Override
         public void visitCase(JCCase tree) {
-            if (tree.getCaseKind() == CaseKind.VALUE) {
-                scan(tree.getValue());
+            if (tree.getCaseKind() == CaseKind.ARROW) {
+                scan(tree.getBody());
             } else {
                 super.visitCase(tree);
             }