src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java
changeset 51563 de411d537aae
parent 50735 2f2af62dfac7
child 51757 5b033f23aced
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java	Tue Aug 28 09:01:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java	Wed Aug 29 09:36:17 2018 +0200
@@ -26,7 +26,11 @@
 package com.sun.tools.javac.comp;
 
 import java.util.*;
-
+import java.util.Map.Entry;
+import java.util.function.Function;
+import java.util.stream.Stream;
+
+import com.sun.source.tree.CaseTree.CaseKind;
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.code.Kinds.KindSelector;
 import com.sun.tools.javac.code.Scope.WriteableScope;
@@ -54,6 +58,10 @@
 import static com.sun.tools.javac.code.Kinds.Kind.*;
 import static com.sun.tools.javac.code.Symbol.OperatorSymbol.AccessCode.DEREF;
 import static com.sun.tools.javac.jvm.ByteCodes.*;
+import com.sun.tools.javac.tree.JCTree.JCBreak;
+import com.sun.tools.javac.tree.JCTree.JCCase;
+import com.sun.tools.javac.tree.JCTree.JCExpression;
+import com.sun.tools.javac.tree.JCTree.JCExpressionStatement;
 import static com.sun.tools.javac.tree.JCTree.JCOperatorExpression.OperandPos.LEFT;
 import static com.sun.tools.javac.tree.JCTree.Tag.*;
 
@@ -263,6 +271,13 @@
             }
             super.visitApply(tree);
         }
+
+        @Override
+        public void visitBreak(JCBreak tree) {
+            if (tree.isValueBreak())
+                scan(tree.value);
+        }
+
     }
 
     /**
@@ -364,6 +379,7 @@
             }
             super.visitApply(tree);
         }
+
     }
 
     ClassSymbol ownerToCopyFreeVarsFrom(ClassSymbol c) {
@@ -3340,6 +3356,45 @@
     }
 
     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:
+                    //case C1, C2, C3: ...
+                    //=>
+                    //case C1:
+                    //case C2:
+                    //case C3: ...
+                    List<JCExpression> patterns = c.pats;
+                    while (patterns.tail.nonEmpty()) {
+                        cases.append(make_at(c.pos()).Case(JCCase.STATEMENT,
+                                                           List.of(patterns.head),
+                                                           List.nil(),
+                                                           null));
+                        patterns = patterns.tail;
+                    }
+                    c.pats = patterns;
+                    cases.append(c);
+                    break;
+            }
+        }
+
+        for (JCCase c : cases) {
+            if (c.caseKind == JCCase.RULE && c.completesNormally) {
+                JCBreak b = make_at(c.pos()).Break(null);
+                b.target = tree;
+                c.stats = c.stats.append(b);
+            }
+        }
+
+        tree.cases = cases.toList();
+
         Type selsuper = types.supertype(tree.selector.type);
         boolean enumSwitch = selsuper != null &&
             (tree.selector.type.tsym.flags() & ENUM) != 0;
@@ -3371,10 +3426,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(pat, c.stats));
+                cases.append(make.Case(JCCase.STATEMENT, List.of(pat), c.stats, null));
             } else {
                 cases.append(c);
             }
@@ -3442,10 +3497,10 @@
             Map<Integer, Set<String>> hashToString = new LinkedHashMap<>(alternatives + 1, 1.0f);
 
             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);
@@ -3529,7 +3584,7 @@
                 breakStmt.target = switch1;
                 lb.append(elsepart).append(breakStmt);
 
-                caseBuffer.append(make.Case(make.Literal(hashCode), lb.toList()));
+                caseBuffer.append(make.Case(JCCase.STATEMENT, List.of(make.Literal(hashCode)), lb.toList(), null));
             }
 
             switch1.cases = caseBuffer.toList();
@@ -3546,18 +3601,17 @@
                 // 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(caseExpr,
-                                    oneCase.getStatements()));
+                lb.append(make.Case(JCCase.STATEMENT, caseExpr == null ? List.nil() : List.of(caseExpr),
+                                    oneCase.getStatements(), null));
             }
 
             switch2.cases = lb.toList();
@@ -3567,6 +3621,76 @@
         }
     }
 
+    @Override
+    public void visitSwitchExpression(JCSwitchExpression tree) {
+        //translates switch expression to statement switch:
+        //switch (selector) {
+        //    case C: break value;
+        //    ...
+        //}
+        //=>
+        //(letexpr T exprswitch$;
+        //         switch (selector) {
+        //             case C: { exprswitch$ = value; break; }
+        //         }
+        //         exprswitch$
+        //)
+        VarSymbol dollar_switchexpr = new VarSymbol(Flags.FINAL|Flags.SYNTHETIC,
+                           names.fromString("exprswitch" + tree.pos + target.syntheticNameChar()),
+                           tree.type,
+                           currentMethodSym);
+
+        ListBuffer<JCStatement> stmtList = new ListBuffer<>();
+
+        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.pats.isEmpty())) {
+            JCThrow thr = make.Throw(makeNewClass(syms.incompatibleClassChangeErrorType,
+                                                  List.nil()));
+            JCCase c = make.Case(JCCase.STATEMENT, List.nil(), List.of(thr), null);
+            switchStatement.cases = switchStatement.cases.append(c);
+        }
+
+        stmtList.append(translate(switchStatement));
+
+        result = make.LetExpr(stmtList.toList(), make.Ident(dollar_switchexpr))
+                     .setType(dollar_switchexpr.type);
+    }
+        //where:
+        private JCCase convertCase(VarSymbol dollar_switchexpr, JCSwitch switchStatement,
+                                   JCSwitchExpression switchExpr, JCCase c) {
+            make.at(c.pos());
+            ListBuffer<JCStatement> statements = new ListBuffer<>();
+            statements.addAll(new TreeTranslator() {
+                @Override
+                public void visitLambda(JCLambda tree) {}
+                @Override
+                public void visitClassDef(JCClassDecl tree) {}
+                @Override
+                public void visitMethodDef(JCMethodDecl tree) {}
+                @Override
+                public void visitBreak(JCBreak tree) {
+                    if (tree.target == switchExpr) {
+                        tree.target = switchStatement;
+                        JCExpressionStatement assignment =
+                                make.Exec(make.Assign(make.Ident(dollar_switchexpr),
+                                                      translate(tree.value))
+                                              .setType(dollar_switchexpr.type));
+                        result = make.Block(0, List.of(assignment,
+                                                       tree));
+                        tree.value = null;
+                    } else {
+                        result = tree;
+                    }
+                }
+            }.translate(c.stats));
+            return make.Case(JCCase.STATEMENT, c.pats, statements.toList(), null);
+        }
+
     public void visitNewArray(JCNewArray tree) {
         tree.elemtype = translate(tree.elemtype);
         for (List<JCExpression> t = tree.dims; t.tail != null; t = t.tail)
@@ -3602,7 +3726,7 @@
     }
 
     public void visitLetExpr(LetExpr tree) {
-        tree.defs = translateVarDefs(tree.defs);
+        tree.defs = translate(tree.defs);
         tree.expr = translate(tree.expr, tree.type);
         result = tree;
     }