src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java
changeset 52794 e4ba5414c8b4
parent 52038 957de5be48bc
child 54568 b2ed96c35687
equal deleted inserted replaced
52793:df065f8356d7 52794:e4ba5414c8b4
    61 import com.sun.tools.javac.tree.JCTree.JCBreak;
    61 import com.sun.tools.javac.tree.JCTree.JCBreak;
    62 import com.sun.tools.javac.tree.JCTree.JCCase;
    62 import com.sun.tools.javac.tree.JCTree.JCCase;
    63 import com.sun.tools.javac.tree.JCTree.JCExpression;
    63 import com.sun.tools.javac.tree.JCTree.JCExpression;
    64 import com.sun.tools.javac.tree.JCTree.JCExpressionStatement;
    64 import com.sun.tools.javac.tree.JCTree.JCExpressionStatement;
    65 import static com.sun.tools.javac.tree.JCTree.JCOperatorExpression.OperandPos.LEFT;
    65 import static com.sun.tools.javac.tree.JCTree.JCOperatorExpression.OperandPos.LEFT;
       
    66 import com.sun.tools.javac.tree.JCTree.JCSwitchExpression;
    66 import static com.sun.tools.javac.tree.JCTree.Tag.*;
    67 import static com.sun.tools.javac.tree.JCTree.Tag.*;
    67 
    68 
    68 /** This pass translates away some syntactic sugar: inner classes,
    69 /** This pass translates away some syntactic sugar: inner classes,
    69  *  class literals, assertions, foreach loops, etc.
    70  *  class literals, assertions, foreach loops, etc.
    70  *
    71  *
  3360                                                 .restype.type));
  3361                                                 .restype.type));
  3361         result = tree;
  3362         result = tree;
  3362     }
  3363     }
  3363 
  3364 
  3364     public void visitSwitch(JCSwitch tree) {
  3365     public void visitSwitch(JCSwitch tree) {
       
  3366         handleSwitch(tree, tree.selector, tree.cases);
       
  3367     }
       
  3368 
       
  3369     @Override
       
  3370     public void visitSwitchExpression(JCSwitchExpression tree) {
       
  3371         if (tree.cases.stream().noneMatch(c -> c.pats.isEmpty())) {
       
  3372             JCThrow thr = make.Throw(makeNewClass(syms.incompatibleClassChangeErrorType,
       
  3373                                                   List.nil()));
       
  3374             JCCase c = make.Case(JCCase.STATEMENT, List.nil(), List.of(thr), null);
       
  3375             tree.cases = tree.cases.append(c);
       
  3376         }
       
  3377         handleSwitch(tree, tree.selector, tree.cases);
       
  3378     }
       
  3379 
       
  3380     private void handleSwitch(JCTree tree, JCExpression selector, List<JCCase> cases) {
  3365         //expand multiple label cases:
  3381         //expand multiple label cases:
  3366         ListBuffer<JCCase> cases = new ListBuffer<>();
  3382         ListBuffer<JCCase> convertedCases = new ListBuffer<>();
  3367 
  3383 
  3368         for (JCCase c : tree.cases) {
  3384         for (JCCase c : cases) {
  3369             switch (c.pats.size()) {
  3385             switch (c.pats.size()) {
  3370                 case 0: //default
  3386                 case 0: //default
  3371                 case 1: //single label
  3387                 case 1: //single label
  3372                     cases.append(c);
  3388                     convertedCases.append(c);
  3373                     break;
  3389                     break;
  3374                 default: //multiple labels, expand:
  3390                 default: //multiple labels, expand:
  3375                     //case C1, C2, C3: ...
  3391                     //case C1, C2, C3: ...
  3376                     //=>
  3392                     //=>
  3377                     //case C1:
  3393                     //case C1:
  3378                     //case C2:
  3394                     //case C2:
  3379                     //case C3: ...
  3395                     //case C3: ...
  3380                     List<JCExpression> patterns = c.pats;
  3396                     List<JCExpression> patterns = c.pats;
  3381                     while (patterns.tail.nonEmpty()) {
  3397                     while (patterns.tail.nonEmpty()) {
  3382                         cases.append(make_at(c.pos()).Case(JCCase.STATEMENT,
  3398                         convertedCases.append(make_at(c.pos()).Case(JCCase.STATEMENT,
  3383                                                            List.of(patterns.head),
  3399                                                            List.of(patterns.head),
  3384                                                            List.nil(),
  3400                                                            List.nil(),
  3385                                                            null));
  3401                                                            null));
  3386                         patterns = patterns.tail;
  3402                         patterns = patterns.tail;
  3387                     }
  3403                     }
  3388                     c.pats = patterns;
  3404                     c.pats = patterns;
  3389                     cases.append(c);
  3405                     convertedCases.append(c);
  3390                     break;
  3406                     break;
  3391             }
  3407             }
  3392         }
  3408         }
  3393 
  3409 
  3394         for (JCCase c : cases) {
  3410         for (JCCase c : convertedCases) {
  3395             if (c.caseKind == JCCase.RULE && c.completesNormally) {
  3411             if (c.caseKind == JCCase.RULE && c.completesNormally) {
  3396                 JCBreak b = make_at(c.pos()).Break(null);
  3412                 JCBreak b = make_at(c.pos()).Break(null);
  3397                 b.target = tree;
  3413                 b.target = tree;
  3398                 c.stats = c.stats.append(b);
  3414                 c.stats = c.stats.append(b);
  3399             }
  3415             }
  3400         }
  3416         }
  3401 
  3417 
  3402         tree.cases = cases.toList();
  3418         cases = convertedCases.toList();
  3403 
  3419 
  3404         Type selsuper = types.supertype(tree.selector.type);
  3420         Type selsuper = types.supertype(selector.type);
  3405         boolean enumSwitch = selsuper != null &&
  3421         boolean enumSwitch = selsuper != null &&
  3406             (tree.selector.type.tsym.flags() & ENUM) != 0;
  3422             (selector.type.tsym.flags() & ENUM) != 0;
  3407         boolean stringSwitch = selsuper != null &&
  3423         boolean stringSwitch = selsuper != null &&
  3408             types.isSameType(tree.selector.type, syms.stringType);
  3424             types.isSameType(selector.type, syms.stringType);
  3409         Type target = enumSwitch ? tree.selector.type :
  3425         Type target = enumSwitch ? selector.type :
  3410             (stringSwitch? syms.stringType : syms.intType);
  3426             (stringSwitch? syms.stringType : syms.intType);
  3411         tree.selector = translate(tree.selector, target);
  3427         selector = translate(selector, target);
  3412         tree.cases = translateCases(tree.cases);
  3428         cases = translateCases(cases);
       
  3429         if (tree.hasTag(SWITCH)) {
       
  3430             ((JCSwitch) tree).selector = selector;
       
  3431             ((JCSwitch) tree).cases = cases;
       
  3432         } else if (tree.hasTag(SWITCH_EXPRESSION)) {
       
  3433             ((JCSwitchExpression) tree).selector = selector;
       
  3434             ((JCSwitchExpression) tree).cases = cases;
       
  3435         } else {
       
  3436             Assert.error();
       
  3437         }
  3413         if (enumSwitch) {
  3438         if (enumSwitch) {
  3414             result = visitEnumSwitch(tree);
  3439             result = visitEnumSwitch(tree, selector, cases);
  3415         } else if (stringSwitch) {
  3440         } else if (stringSwitch) {
  3416             result = visitStringSwitch(tree);
  3441             result = visitStringSwitch(tree, selector, cases);
  3417         } else {
  3442         } else {
  3418             result = tree;
  3443             result = tree;
  3419         }
  3444         }
  3420     }
  3445     }
  3421 
  3446 
  3422     public JCTree visitEnumSwitch(JCSwitch tree) {
  3447     public JCTree visitEnumSwitch(JCTree tree, JCExpression selector, List<JCCase> cases) {
  3423         TypeSymbol enumSym = tree.selector.type.tsym;
  3448         TypeSymbol enumSym = selector.type.tsym;
  3424         EnumMapping map = mapForEnum(tree.pos(), enumSym);
  3449         EnumMapping map = mapForEnum(tree.pos(), enumSym);
  3425         make_at(tree.pos());
  3450         make_at(tree.pos());
  3426         Symbol ordinalMethod = lookupMethod(tree.pos(),
  3451         Symbol ordinalMethod = lookupMethod(tree.pos(),
  3427                                             names.ordinal,
  3452                                             names.ordinal,
  3428                                             tree.selector.type,
  3453                                             selector.type,
  3429                                             List.nil());
  3454                                             List.nil());
  3430         JCArrayAccess selector = make.Indexed(map.mapVar,
  3455         JCArrayAccess newSelector = make.Indexed(map.mapVar,
  3431                                         make.App(make.Select(tree.selector,
  3456                                         make.App(make.Select(selector,
  3432                                                              ordinalMethod)));
  3457                                                              ordinalMethod)));
  3433         ListBuffer<JCCase> cases = new ListBuffer<>();
  3458         ListBuffer<JCCase> newCases = new ListBuffer<>();
  3434         for (JCCase c : tree.cases) {
  3459         for (JCCase c : cases) {
  3435             if (c.pats.nonEmpty()) {
  3460             if (c.pats.nonEmpty()) {
  3436                 VarSymbol label = (VarSymbol)TreeInfo.symbol(c.pats.head);
  3461                 VarSymbol label = (VarSymbol)TreeInfo.symbol(c.pats.head);
  3437                 JCLiteral pat = map.forConstant(label);
  3462                 JCLiteral pat = map.forConstant(label);
  3438                 cases.append(make.Case(JCCase.STATEMENT, List.of(pat), c.stats, null));
  3463                 newCases.append(make.Case(JCCase.STATEMENT, List.of(pat), c.stats, null));
  3439             } else {
  3464             } else {
  3440                 cases.append(c);
  3465                 newCases.append(c);
  3441             }
  3466             }
  3442         }
  3467         }
  3443         JCSwitch enumSwitch = make.Switch(selector, cases.toList());
  3468         JCTree enumSwitch;
       
  3469         if (tree.hasTag(SWITCH)) {
       
  3470             enumSwitch = make.Switch(newSelector, newCases.toList());
       
  3471         } else if (tree.hasTag(SWITCH_EXPRESSION)) {
       
  3472             enumSwitch = make.SwitchExpression(newSelector, newCases.toList());
       
  3473             enumSwitch.setType(tree.type);
       
  3474         } else {
       
  3475             Assert.error();
       
  3476             throw new AssertionError();
       
  3477         }
  3444         patchTargets(enumSwitch, tree, enumSwitch);
  3478         patchTargets(enumSwitch, tree, enumSwitch);
  3445         return enumSwitch;
  3479         return enumSwitch;
  3446     }
  3480     }
  3447 
  3481 
  3448     public JCTree visitStringSwitch(JCSwitch tree) {
  3482     public JCTree visitStringSwitch(JCTree tree, JCExpression selector, List<JCCase> caseList) {
  3449         List<JCCase> caseList = tree.getCases();
       
  3450         int alternatives = caseList.size();
  3483         int alternatives = caseList.size();
  3451 
  3484 
  3452         if (alternatives == 0) { // Strange but legal possibility
  3485         if (alternatives == 0) { // Strange but legal possibility (only legal for switch statement)
  3453             return make.at(tree.pos()).Exec(attr.makeNullCheck(tree.getExpression()));
  3486             return make.at(tree.pos()).Exec(attr.makeNullCheck(selector));
  3454         } else {
  3487         } else {
  3455             /*
  3488             /*
  3456              * The general approach used is to translate a single
  3489              * The general approach used is to translate a single
  3457              * string switch statement into a series of two chained
  3490              * string switch statement into a series of two chained
  3458              * switch statements: the first a synthesized statement
  3491              * switch statements: the first a synthesized statement
  3549 
  3582 
  3550             VarSymbol dollar_s = new VarSymbol(FINAL|SYNTHETIC,
  3583             VarSymbol dollar_s = new VarSymbol(FINAL|SYNTHETIC,
  3551                                                names.fromString("s" + tree.pos + target.syntheticNameChar()),
  3584                                                names.fromString("s" + tree.pos + target.syntheticNameChar()),
  3552                                                syms.stringType,
  3585                                                syms.stringType,
  3553                                                currentMethodSym);
  3586                                                currentMethodSym);
  3554             stmtList.append(make.at(tree.pos()).VarDef(dollar_s, tree.getExpression()).setType(dollar_s.type));
  3587             stmtList.append(make.at(tree.pos()).VarDef(dollar_s, selector).setType(dollar_s.type));
  3555 
  3588 
  3556             VarSymbol dollar_tmp = new VarSymbol(SYNTHETIC,
  3589             VarSymbol dollar_tmp = new VarSymbol(SYNTHETIC,
  3557                                                  names.fromString("tmp" + tree.pos + target.syntheticNameChar()),
  3590                                                  names.fromString("tmp" + tree.pos + target.syntheticNameChar()),
  3558                                                  syms.intType,
  3591                                                  syms.intType,
  3559                                                  currentMethodSym);
  3592                                                  currentMethodSym);
  3599             // Make isomorphic switch tree replacing string labels
  3632             // Make isomorphic switch tree replacing string labels
  3600             // with corresponding integer ones from the label to
  3633             // with corresponding integer ones from the label to
  3601             // position map.
  3634             // position map.
  3602 
  3635 
  3603             ListBuffer<JCCase> lb = new ListBuffer<>();
  3636             ListBuffer<JCCase> lb = new ListBuffer<>();
  3604             JCSwitch switch2 = make.Switch(make.Ident(dollar_tmp), lb.toList());
       
  3605             for(JCCase oneCase : caseList ) {
  3637             for(JCCase oneCase : caseList ) {
  3606                 // Rewire up old unlabeled break statements to the
       
  3607                 // replacement switch being created.
       
  3608                 patchTargets(oneCase, tree, switch2);
       
  3609 
       
  3610                 boolean isDefault = (oneCase.pats.isEmpty());
  3638                 boolean isDefault = (oneCase.pats.isEmpty());
  3611                 JCExpression caseExpr;
  3639                 JCExpression caseExpr;
  3612                 if (isDefault)
  3640                 if (isDefault)
  3613                     caseExpr = null;
  3641                     caseExpr = null;
  3614                 else {
  3642                 else {
  3615                     caseExpr = make.Literal(caseLabelToPosition.get((String)TreeInfo.skipParens(oneCase.pats.head).
  3643                     caseExpr = make.Literal(caseLabelToPosition.get((String)TreeInfo.skipParens(oneCase.pats.head).
  3616                                                                     type.constValue()));
  3644                                                                     type.constValue()));
  3617                 }
  3645                 }
  3618 
  3646 
  3619                 lb.append(make.Case(JCCase.STATEMENT, caseExpr == null ? List.nil() : List.of(caseExpr),
  3647                 lb.append(make.Case(JCCase.STATEMENT, caseExpr == null ? List.nil() : List.of(caseExpr),
  3620                                     oneCase.getStatements(), null));
  3648                                     oneCase.stats, null));
  3621             }
  3649             }
  3622 
  3650 
  3623             switch2.cases = lb.toList();
  3651             if (tree.hasTag(SWITCH)) {
  3624             stmtList.append(switch2);
  3652                 JCSwitch switch2 = make.Switch(make.Ident(dollar_tmp), lb.toList());
  3625 
  3653                 // Rewire up old unlabeled break statements to the
  3626             return make.Block(0L, stmtList.toList());
  3654                 // replacement switch being created.
       
  3655                 patchTargets(switch2, tree, switch2);
       
  3656 
       
  3657                 stmtList.append(switch2);
       
  3658 
       
  3659                 return make.Block(0L, stmtList.toList());
       
  3660             } else {
       
  3661                 JCSwitchExpression switch2 = make.SwitchExpression(make.Ident(dollar_tmp), lb.toList());
       
  3662 
       
  3663                 // Rewire up old unlabeled break statements to the
       
  3664                 // replacement switch being created.
       
  3665                 patchTargets(switch2, tree, switch2);
       
  3666 
       
  3667                 switch2.setType(tree.type);
       
  3668 
       
  3669                 LetExpr res = make.LetExpr(stmtList.toList(), switch2);
       
  3670 
       
  3671                 res.needsCond = true;
       
  3672                 res.setType(tree.type);
       
  3673 
       
  3674                 return res;
       
  3675             }
  3627         }
  3676         }
  3628     }
  3677     }
  3629 
  3678 
  3630     @Override
  3679     @Override
  3631     public void visitSwitchExpression(JCSwitchExpression tree) {
  3680     public void visitBreak(JCBreak tree) {
  3632         //translates switch expression to statement switch:
  3681         if (tree.isValueBreak()) {
  3633         //switch (selector) {
  3682             tree.value = translate(tree.value, tree.target.type);
  3634         //    case C: break value;
  3683         }
  3635         //    ...
  3684         result = tree;
  3636         //}
  3685     }
  3637         //=>
       
  3638         //(letexpr T exprswitch$;
       
  3639         //         switch (selector) {
       
  3640         //             case C: { exprswitch$ = value; break; }
       
  3641         //         }
       
  3642         //         exprswitch$
       
  3643         //)
       
  3644         VarSymbol dollar_switchexpr = new VarSymbol(Flags.FINAL|Flags.SYNTHETIC,
       
  3645                            names.fromString("exprswitch" + tree.pos + target.syntheticNameChar()),
       
  3646                            tree.type,
       
  3647                            currentMethodSym);
       
  3648 
       
  3649         ListBuffer<JCStatement> stmtList = new ListBuffer<>();
       
  3650 
       
  3651         stmtList.append(make.at(tree.pos()).VarDef(dollar_switchexpr, null).setType(dollar_switchexpr.type));
       
  3652         JCSwitch switchStatement = make.Switch(tree.selector, null);
       
  3653         switchStatement.cases =
       
  3654                 tree.cases.stream()
       
  3655                           .map(c -> convertCase(dollar_switchexpr, switchStatement, tree, c))
       
  3656                           .collect(List.collector());
       
  3657         if (tree.cases.stream().noneMatch(c -> c.pats.isEmpty())) {
       
  3658             JCThrow thr = make.Throw(makeNewClass(syms.incompatibleClassChangeErrorType,
       
  3659                                                   List.nil()));
       
  3660             JCCase c = make.Case(JCCase.STATEMENT, List.nil(), List.of(thr), null);
       
  3661             switchStatement.cases = switchStatement.cases.append(c);
       
  3662         }
       
  3663 
       
  3664         stmtList.append(translate(switchStatement));
       
  3665 
       
  3666         result = make.LetExpr(stmtList.toList(), make.Ident(dollar_switchexpr))
       
  3667                      .setType(dollar_switchexpr.type);
       
  3668     }
       
  3669         //where:
       
  3670         private JCCase convertCase(VarSymbol dollar_switchexpr, JCSwitch switchStatement,
       
  3671                                    JCSwitchExpression switchExpr, JCCase c) {
       
  3672             make.at(c.pos());
       
  3673             ListBuffer<JCStatement> statements = new ListBuffer<>();
       
  3674             statements.addAll(new TreeTranslator() {
       
  3675                 @Override
       
  3676                 public void visitLambda(JCLambda tree) {}
       
  3677                 @Override
       
  3678                 public void visitClassDef(JCClassDecl tree) {}
       
  3679                 @Override
       
  3680                 public void visitMethodDef(JCMethodDecl tree) {}
       
  3681                 @Override
       
  3682                 public void visitBreak(JCBreak tree) {
       
  3683                     if (tree.target == switchExpr) {
       
  3684                         tree.target = switchStatement;
       
  3685                         JCExpressionStatement assignment =
       
  3686                                 make.Exec(make.Assign(make.Ident(dollar_switchexpr),
       
  3687                                                       translate(tree.value))
       
  3688                                               .setType(dollar_switchexpr.type));
       
  3689                         result = make.Block(0, List.of(assignment,
       
  3690                                                        tree));
       
  3691                         tree.value = null;
       
  3692                     } else {
       
  3693                         result = tree;
       
  3694                     }
       
  3695                 }
       
  3696             }.translate(c.stats));
       
  3697             return make.Case(JCCase.STATEMENT, c.pats, statements.toList(), null);
       
  3698         }
       
  3699 
  3686 
  3700     public void visitNewArray(JCNewArray tree) {
  3687     public void visitNewArray(JCNewArray tree) {
  3701         tree.elemtype = translate(tree.elemtype);
  3688         tree.elemtype = translate(tree.elemtype);
  3702         for (List<JCExpression> t = tree.dims; t.tail != null; t = t.tail)
  3689         for (List<JCExpression> t = tree.dims; t.tail != null; t = t.tail)
  3703             if (t.head != null) t.head = translate(t.head, syms.intType);
  3690             if (t.head != null) t.head = translate(t.head, syms.intType);