< prev index next >

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

Print this page
rev 52724 : imported patch 8214031

@@ -61,10 +61,11 @@
 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 com.sun.tools.javac.tree.JCTree.JCSwitchExpression;
 import static com.sun.tools.javac.tree.JCTree.Tag.*;
 
 /** This pass translates away some syntactic sugar: inner classes,
  *  class literals, assertions, foreach loops, etc.
  *

@@ -3360,99 +3361,131 @@
                                                 .restype.type));
         result = tree;
     }
 
     public void visitSwitch(JCSwitch tree) {
+        handleSwitch(tree, tree.selector, tree.cases);
+    }
+
+    @Override
+    public void visitSwitchExpression(JCSwitchExpression tree) {
+        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);
+            tree.cases = tree.cases.append(c);
+        }
+        handleSwitch(tree, tree.selector, tree.cases);
+    }
+
+    private void handleSwitch(JCTree tree, JCExpression selector, List<JCCase> cases) {
         //expand multiple label cases:
-        ListBuffer<JCCase> cases = new ListBuffer<>();
+        ListBuffer<JCCase> convertedCases = new ListBuffer<>();
 
-        for (JCCase c : tree.cases) {
+        for (JCCase c : cases) {
             switch (c.pats.size()) {
                 case 0: //default
                 case 1: //single label
-                    cases.append(c);
+                    convertedCases.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,
+                        convertedCases.append(make_at(c.pos()).Case(JCCase.STATEMENT,
                                                            List.of(patterns.head),
                                                            List.nil(),
                                                            null));
                         patterns = patterns.tail;
                     }
                     c.pats = patterns;
-                    cases.append(c);
+                    convertedCases.append(c);
                     break;
             }
         }
 
-        for (JCCase c : cases) {
+        for (JCCase c : convertedCases) {
             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();
+        cases = convertedCases.toList();
 
-        Type selsuper = types.supertype(tree.selector.type);
+        Type selsuper = types.supertype(selector.type);
         boolean enumSwitch = selsuper != null &&
-            (tree.selector.type.tsym.flags() & ENUM) != 0;
+            (selector.type.tsym.flags() & ENUM) != 0;
         boolean stringSwitch = selsuper != null &&
-            types.isSameType(tree.selector.type, syms.stringType);
-        Type target = enumSwitch ? tree.selector.type :
+            types.isSameType(selector.type, syms.stringType);
+        Type target = enumSwitch ? selector.type :
             (stringSwitch? syms.stringType : syms.intType);
-        tree.selector = translate(tree.selector, target);
-        tree.cases = translateCases(tree.cases);
+        selector = translate(selector, target);
+        cases = translateCases(cases);
+        if (tree.hasTag(SWITCH)) {
+            ((JCSwitch) tree).selector = selector;
+            ((JCSwitch) tree).cases = cases;
+        } else if (tree.hasTag(SWITCH_EXPRESSION)) {
+            ((JCSwitchExpression) tree).selector = selector;
+            ((JCSwitchExpression) tree).cases = cases;
+        } else {
+            Assert.error();
+        }
         if (enumSwitch) {
-            result = visitEnumSwitch(tree);
+            result = visitEnumSwitch(tree, selector, cases);
         } else if (stringSwitch) {
-            result = visitStringSwitch(tree);
+            result = visitStringSwitch(tree, selector, cases);
         } else {
             result = tree;
         }
     }
 
-    public JCTree visitEnumSwitch(JCSwitch tree) {
-        TypeSymbol enumSym = tree.selector.type.tsym;
+    public JCTree visitEnumSwitch(JCTree tree, JCExpression selector, List<JCCase> cases) {
+        TypeSymbol enumSym = selector.type.tsym;
         EnumMapping map = mapForEnum(tree.pos(), enumSym);
         make_at(tree.pos());
         Symbol ordinalMethod = lookupMethod(tree.pos(),
                                             names.ordinal,
-                                            tree.selector.type,
+                                            selector.type,
                                             List.nil());
-        JCArrayAccess selector = make.Indexed(map.mapVar,
-                                        make.App(make.Select(tree.selector,
+        JCArrayAccess newSelector = make.Indexed(map.mapVar,
+                                        make.App(make.Select(selector,
                                                              ordinalMethod)));
-        ListBuffer<JCCase> cases = new ListBuffer<>();
-        for (JCCase c : tree.cases) {
+        ListBuffer<JCCase> newCases = new ListBuffer<>();
+        for (JCCase c : cases) {
             if (c.pats.nonEmpty()) {
                 VarSymbol label = (VarSymbol)TreeInfo.symbol(c.pats.head);
                 JCLiteral pat = map.forConstant(label);
-                cases.append(make.Case(JCCase.STATEMENT, List.of(pat), c.stats, null));
+                newCases.append(make.Case(JCCase.STATEMENT, List.of(pat), c.stats, null));
             } else {
-                cases.append(c);
+                newCases.append(c);
             }
         }
-        JCSwitch enumSwitch = make.Switch(selector, cases.toList());
+        JCTree enumSwitch;
+        if (tree.hasTag(SWITCH)) {
+            enumSwitch = make.Switch(newSelector, newCases.toList());
+        } else if (tree.hasTag(SWITCH_EXPRESSION)) {
+            enumSwitch = make.SwitchExpression(newSelector, newCases.toList());
+            enumSwitch.setType(tree.type);
+        } else {
+            Assert.error();
+            throw new AssertionError();
+        }
         patchTargets(enumSwitch, tree, enumSwitch);
         return enumSwitch;
     }
 
-    public JCTree visitStringSwitch(JCSwitch tree) {
-        List<JCCase> caseList = tree.getCases();
+    public JCTree visitStringSwitch(JCTree tree, JCExpression selector, List<JCCase> caseList) {
         int alternatives = caseList.size();
 
-        if (alternatives == 0) { // Strange but legal possibility
-            return make.at(tree.pos()).Exec(attr.makeNullCheck(tree.getExpression()));
+        if (alternatives == 0) { // Strange but legal possibility (only legal for switch statement)
+            return make.at(tree.pos()).Exec(attr.makeNullCheck(selector));
         } else {
             /*
              * The general approach used is to translate a single
              * string switch statement into a series of two chained
              * switch statements: the first a synthesized statement

@@ -3549,11 +3582,11 @@
 
             VarSymbol dollar_s = new VarSymbol(FINAL|SYNTHETIC,
                                                names.fromString("s" + tree.pos + target.syntheticNameChar()),
                                                syms.stringType,
                                                currentMethodSym);
-            stmtList.append(make.at(tree.pos()).VarDef(dollar_s, tree.getExpression()).setType(dollar_s.type));
+            stmtList.append(make.at(tree.pos()).VarDef(dollar_s, selector).setType(dollar_s.type));
 
             VarSymbol dollar_tmp = new VarSymbol(SYNTHETIC,
                                                  names.fromString("tmp" + tree.pos + target.syntheticNameChar()),
                                                  syms.intType,
                                                  currentMethodSym);

@@ -3599,104 +3632,58 @@
             // Make isomorphic switch tree replacing string labels
             // with corresponding integer ones from the label to
             // position map.
 
             ListBuffer<JCCase> lb = new ListBuffer<>();
-            JCSwitch switch2 = make.Switch(make.Ident(dollar_tmp), lb.toList());
             for(JCCase oneCase : caseList ) {
-                // Rewire up old unlabeled break statements to the
-                // replacement switch being created.
-                patchTargets(oneCase, tree, switch2);
-
                 boolean isDefault = (oneCase.pats.isEmpty());
                 JCExpression caseExpr;
                 if (isDefault)
                     caseExpr = null;
                 else {
                     caseExpr = make.Literal(caseLabelToPosition.get((String)TreeInfo.skipParens(oneCase.pats.head).
                                                                     type.constValue()));
                 }
 
                 lb.append(make.Case(JCCase.STATEMENT, caseExpr == null ? List.nil() : List.of(caseExpr),
-                                    oneCase.getStatements(), null));
+                                    oneCase.stats, null));
             }
 
-            switch2.cases = lb.toList();
+            if (tree.hasTag(SWITCH)) {
+                JCSwitch switch2 = make.Switch(make.Ident(dollar_tmp), lb.toList());
+                // Rewire up old unlabeled break statements to the
+                // replacement switch being created.
+                patchTargets(switch2, tree, switch2);
+
             stmtList.append(switch2);
 
             return make.Block(0L, stmtList.toList());
-        }
-    }
+            } else {
+                JCSwitchExpression switch2 = make.SwitchExpression(make.Ident(dollar_tmp), lb.toList());
 
-    @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);
+                // Rewire up old unlabeled break statements to the
+                // replacement switch being created.
+                patchTargets(switch2, tree, switch2);
 
-        ListBuffer<JCStatement> stmtList = new ListBuffer<>();
+                switch2.setType(tree.type);
 
-        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);
-        }
+                LetExpr res = make.LetExpr(stmtList.toList(), switch2);
 
-        stmtList.append(translate(switchStatement));
+                res.needsCond = true;
+                res.setType(tree.type);
 
-        result = make.LetExpr(stmtList.toList(), make.Ident(dollar_switchexpr))
-                     .setType(dollar_switchexpr.type);
+                return res;
     }
-        //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;
-                    }
+        if (tree.isValueBreak()) {
+            tree.value = translate(tree.value, tree.target.type);
                 }
-            }.translate(c.stats));
-            return make.Case(JCCase.STATEMENT, c.pats, statements.toList(), null);
+        result = tree;
         }
 
     public void visitNewArray(JCNewArray tree) {
         tree.elemtype = translate(tree.elemtype);
         for (List<JCExpression> t = tree.dims; t.tail != null; t = t.tail)
< prev index next >