46 import com.sun.tools.javac.code.Symbol.OperatorSymbol.AccessCode;
47 import com.sun.tools.javac.resources.CompilerProperties.Errors;
48 import com.sun.tools.javac.tree.JCTree.*;
49 import com.sun.tools.javac.code.Type.*;
50
51 import com.sun.tools.javac.jvm.Target;
52 import com.sun.tools.javac.tree.EndPosTable;
53
54 import static com.sun.tools.javac.code.Flags.*;
55 import static com.sun.tools.javac.code.Flags.BLOCK;
56 import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
57 import static com.sun.tools.javac.code.TypeTag.*;
58 import static com.sun.tools.javac.code.Kinds.Kind.*;
59 import static com.sun.tools.javac.code.Symbol.OperatorSymbol.AccessCode.DEREF;
60 import static com.sun.tools.javac.jvm.ByteCodes.*;
61 import com.sun.tools.javac.tree.JCTree.JCBreak;
62 import com.sun.tools.javac.tree.JCTree.JCCase;
63 import com.sun.tools.javac.tree.JCTree.JCExpression;
64 import com.sun.tools.javac.tree.JCTree.JCExpressionStatement;
65 import static com.sun.tools.javac.tree.JCTree.JCOperatorExpression.OperandPos.LEFT;
66 import static com.sun.tools.javac.tree.JCTree.Tag.*;
67
68 /** This pass translates away some syntactic sugar: inner classes,
69 * class literals, assertions, foreach loops, etc.
70 *
71 * <p><b>This is NOT part of any supported API.
72 * If you write code that depends on this, you do so at your own risk.
73 * This code and its internal interfaces are subject to change or
74 * deletion without notice.</b>
75 */
76 public class Lower extends TreeTranslator {
77 protected static final Context.Key<Lower> lowerKey = new Context.Key<>();
78
79 public static Lower instance(Context context) {
80 Lower instance = context.get(lowerKey);
81 if (instance == null)
82 instance = new Lower(context);
83 return instance;
84 }
85
3345 }
3346
3347 public void visitForLoop(JCForLoop tree) {
3348 tree.init = translate(tree.init);
3349 if (tree.cond != null)
3350 tree.cond = translate(tree.cond, syms.booleanType);
3351 tree.step = translate(tree.step);
3352 tree.body = translate(tree.body);
3353 result = tree;
3354 }
3355
3356 public void visitReturn(JCReturn tree) {
3357 if (tree.expr != null)
3358 tree.expr = translate(tree.expr,
3359 types.erasure(currentMethodDef
3360 .restype.type));
3361 result = tree;
3362 }
3363
3364 public void visitSwitch(JCSwitch tree) {
3365 //expand multiple label cases:
3366 ListBuffer<JCCase> cases = new ListBuffer<>();
3367
3368 for (JCCase c : tree.cases) {
3369 switch (c.pats.size()) {
3370 case 0: //default
3371 case 1: //single label
3372 cases.append(c);
3373 break;
3374 default: //multiple labels, expand:
3375 //case C1, C2, C3: ...
3376 //=>
3377 //case C1:
3378 //case C2:
3379 //case C3: ...
3380 List<JCExpression> patterns = c.pats;
3381 while (patterns.tail.nonEmpty()) {
3382 cases.append(make_at(c.pos()).Case(JCCase.STATEMENT,
3383 List.of(patterns.head),
3384 List.nil(),
3385 null));
3386 patterns = patterns.tail;
3387 }
3388 c.pats = patterns;
3389 cases.append(c);
3390 break;
3391 }
3392 }
3393
3394 for (JCCase c : cases) {
3395 if (c.caseKind == JCCase.RULE && c.completesNormally) {
3396 JCBreak b = make_at(c.pos()).Break(null);
3397 b.target = tree;
3398 c.stats = c.stats.append(b);
3399 }
3400 }
3401
3402 tree.cases = cases.toList();
3403
3404 Type selsuper = types.supertype(tree.selector.type);
3405 boolean enumSwitch = selsuper != null &&
3406 (tree.selector.type.tsym.flags() & ENUM) != 0;
3407 boolean stringSwitch = selsuper != null &&
3408 types.isSameType(tree.selector.type, syms.stringType);
3409 Type target = enumSwitch ? tree.selector.type :
3410 (stringSwitch? syms.stringType : syms.intType);
3411 tree.selector = translate(tree.selector, target);
3412 tree.cases = translateCases(tree.cases);
3413 if (enumSwitch) {
3414 result = visitEnumSwitch(tree);
3415 } else if (stringSwitch) {
3416 result = visitStringSwitch(tree);
3417 } else {
3418 result = tree;
3419 }
3420 }
3421
3422 public JCTree visitEnumSwitch(JCSwitch tree) {
3423 TypeSymbol enumSym = tree.selector.type.tsym;
3424 EnumMapping map = mapForEnum(tree.pos(), enumSym);
3425 make_at(tree.pos());
3426 Symbol ordinalMethod = lookupMethod(tree.pos(),
3427 names.ordinal,
3428 tree.selector.type,
3429 List.nil());
3430 JCArrayAccess selector = make.Indexed(map.mapVar,
3431 make.App(make.Select(tree.selector,
3432 ordinalMethod)));
3433 ListBuffer<JCCase> cases = new ListBuffer<>();
3434 for (JCCase c : tree.cases) {
3435 if (c.pats.nonEmpty()) {
3436 VarSymbol label = (VarSymbol)TreeInfo.symbol(c.pats.head);
3437 JCLiteral pat = map.forConstant(label);
3438 cases.append(make.Case(JCCase.STATEMENT, List.of(pat), c.stats, null));
3439 } else {
3440 cases.append(c);
3441 }
3442 }
3443 JCSwitch enumSwitch = make.Switch(selector, cases.toList());
3444 patchTargets(enumSwitch, tree, enumSwitch);
3445 return enumSwitch;
3446 }
3447
3448 public JCTree visitStringSwitch(JCSwitch tree) {
3449 List<JCCase> caseList = tree.getCases();
3450 int alternatives = caseList.size();
3451
3452 if (alternatives == 0) { // Strange but legal possibility
3453 return make.at(tree.pos()).Exec(attr.makeNullCheck(tree.getExpression()));
3454 } else {
3455 /*
3456 * The general approach used is to translate a single
3457 * string switch statement into a series of two chained
3458 * switch statements: the first a synthesized statement
3459 * switching on the argument string's hash value and
3460 * computing a string's position in the list of original
3461 * case labels, if any, followed by a second switch on the
3462 * computed integer value. The second switch has the same
3463 * code structure as the original string switch statement
3464 * except that the string case labels are replaced with
3465 * positional integer constants starting at 0.
3466 *
3467 * The first switch statement can be thought of as an
3468 * inlined map from strings to their position in the case
3469 * label list. An alternate implementation would use an
3470 * actual Map for this purpose, as done for enum switches.
3471 *
3472 * With some additional effort, it would be possible to
3473 * use a single switch statement on the hash code of the
3534
3535 /*
3536 * s$ = top of stack;
3537 * tmp$ = -1;
3538 * switch($s.hashCode()) {
3539 * case caseLabel.hashCode:
3540 * if (s$.equals("caseLabel_1")
3541 * tmp$ = caseLabelToPosition("caseLabel_1");
3542 * else if (s$.equals("caseLabel_2"))
3543 * tmp$ = caseLabelToPosition("caseLabel_2");
3544 * ...
3545 * break;
3546 * ...
3547 * }
3548 */
3549
3550 VarSymbol dollar_s = new VarSymbol(FINAL|SYNTHETIC,
3551 names.fromString("s" + tree.pos + target.syntheticNameChar()),
3552 syms.stringType,
3553 currentMethodSym);
3554 stmtList.append(make.at(tree.pos()).VarDef(dollar_s, tree.getExpression()).setType(dollar_s.type));
3555
3556 VarSymbol dollar_tmp = new VarSymbol(SYNTHETIC,
3557 names.fromString("tmp" + tree.pos + target.syntheticNameChar()),
3558 syms.intType,
3559 currentMethodSym);
3560 JCVariableDecl dollar_tmp_def =
3561 (JCVariableDecl)make.VarDef(dollar_tmp, make.Literal(INT, -1)).setType(dollar_tmp.type);
3562 dollar_tmp_def.init.type = dollar_tmp.type = syms.intType;
3563 stmtList.append(dollar_tmp_def);
3564 ListBuffer<JCCase> caseBuffer = new ListBuffer<>();
3565 // hashCode will trigger nullcheck on original switch expression
3566 JCMethodInvocation hashCodeCall = makeCall(make.Ident(dollar_s),
3567 names.hashCode,
3568 List.nil()).setType(syms.intType);
3569 JCSwitch switch1 = make.Switch(hashCodeCall,
3570 caseBuffer.toList());
3571 for(Map.Entry<Integer, Set<String>> entry : hashToString.entrySet()) {
3572 int hashCode = entry.getKey();
3573 Set<String> stringsWithHashCode = entry.getValue();
3574 Assert.check(stringsWithHashCode.size() >= 1);
3584 setType(dollar_tmp.type)),
3585 elsepart);
3586 }
3587
3588 ListBuffer<JCStatement> lb = new ListBuffer<>();
3589 JCBreak breakStmt = make.Break(null);
3590 breakStmt.target = switch1;
3591 lb.append(elsepart).append(breakStmt);
3592
3593 caseBuffer.append(make.Case(JCCase.STATEMENT, List.of(make.Literal(hashCode)), lb.toList(), null));
3594 }
3595
3596 switch1.cases = caseBuffer.toList();
3597 stmtList.append(switch1);
3598
3599 // Make isomorphic switch tree replacing string labels
3600 // with corresponding integer ones from the label to
3601 // position map.
3602
3603 ListBuffer<JCCase> lb = new ListBuffer<>();
3604 JCSwitch switch2 = make.Switch(make.Ident(dollar_tmp), lb.toList());
3605 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());
3611 JCExpression caseExpr;
3612 if (isDefault)
3613 caseExpr = null;
3614 else {
3615 caseExpr = make.Literal(caseLabelToPosition.get((String)TreeInfo.skipParens(oneCase.pats.head).
3616 type.constValue()));
3617 }
3618
3619 lb.append(make.Case(JCCase.STATEMENT, caseExpr == null ? List.nil() : List.of(caseExpr),
3620 oneCase.getStatements(), null));
3621 }
3622
3623 switch2.cases = lb.toList();
3624 stmtList.append(switch2);
3625
3626 return make.Block(0L, stmtList.toList());
3627 }
3628 }
3629
3630 @Override
3631 public void visitSwitchExpression(JCSwitchExpression tree) {
3632 //translates switch expression to statement switch:
3633 //switch (selector) {
3634 // case C: break value;
3635 // ...
3636 //}
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
3700 public void visitNewArray(JCNewArray tree) {
3701 tree.elemtype = translate(tree.elemtype);
3702 for (List<JCExpression> t = tree.dims; t.tail != null; t = t.tail)
3703 if (t.head != null) t.head = translate(t.head, syms.intType);
3704 tree.elems = translate(tree.elems, types.elemtype(tree.type));
3705 result = tree;
3706 }
3707
3708 public void visitSelect(JCFieldAccess tree) {
3709 // need to special case-access of the form C.super.x
3710 // these will always need an access method, unless C
3711 // is a default interface subclassed by the current class.
3712 boolean qualifiedSuperAccess =
3713 tree.selected.hasTag(SELECT) &&
3714 TreeInfo.name(tree.selected) == names._super &&
3715 !types.isDirectSuperInterface(((JCFieldAccess)tree.selected).selected.type.tsym, currentClass);
3716 tree.selected = translate(tree.selected);
3717 if (tree.name == names._class) {
|
46 import com.sun.tools.javac.code.Symbol.OperatorSymbol.AccessCode;
47 import com.sun.tools.javac.resources.CompilerProperties.Errors;
48 import com.sun.tools.javac.tree.JCTree.*;
49 import com.sun.tools.javac.code.Type.*;
50
51 import com.sun.tools.javac.jvm.Target;
52 import com.sun.tools.javac.tree.EndPosTable;
53
54 import static com.sun.tools.javac.code.Flags.*;
55 import static com.sun.tools.javac.code.Flags.BLOCK;
56 import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
57 import static com.sun.tools.javac.code.TypeTag.*;
58 import static com.sun.tools.javac.code.Kinds.Kind.*;
59 import static com.sun.tools.javac.code.Symbol.OperatorSymbol.AccessCode.DEREF;
60 import static com.sun.tools.javac.jvm.ByteCodes.*;
61 import com.sun.tools.javac.tree.JCTree.JCBreak;
62 import com.sun.tools.javac.tree.JCTree.JCCase;
63 import com.sun.tools.javac.tree.JCTree.JCExpression;
64 import com.sun.tools.javac.tree.JCTree.JCExpressionStatement;
65 import static com.sun.tools.javac.tree.JCTree.JCOperatorExpression.OperandPos.LEFT;
66 import com.sun.tools.javac.tree.JCTree.JCSwitchExpression;
67 import static com.sun.tools.javac.tree.JCTree.Tag.*;
68
69 /** This pass translates away some syntactic sugar: inner classes,
70 * class literals, assertions, foreach loops, etc.
71 *
72 * <p><b>This is NOT part of any supported API.
73 * If you write code that depends on this, you do so at your own risk.
74 * This code and its internal interfaces are subject to change or
75 * deletion without notice.</b>
76 */
77 public class Lower extends TreeTranslator {
78 protected static final Context.Key<Lower> lowerKey = new Context.Key<>();
79
80 public static Lower instance(Context context) {
81 Lower instance = context.get(lowerKey);
82 if (instance == null)
83 instance = new Lower(context);
84 return instance;
85 }
86
3346 }
3347
3348 public void visitForLoop(JCForLoop tree) {
3349 tree.init = translate(tree.init);
3350 if (tree.cond != null)
3351 tree.cond = translate(tree.cond, syms.booleanType);
3352 tree.step = translate(tree.step);
3353 tree.body = translate(tree.body);
3354 result = tree;
3355 }
3356
3357 public void visitReturn(JCReturn tree) {
3358 if (tree.expr != null)
3359 tree.expr = translate(tree.expr,
3360 types.erasure(currentMethodDef
3361 .restype.type));
3362 result = tree;
3363 }
3364
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) {
3381 //expand multiple label cases:
3382 ListBuffer<JCCase> convertedCases = new ListBuffer<>();
3383
3384 for (JCCase c : cases) {
3385 switch (c.pats.size()) {
3386 case 0: //default
3387 case 1: //single label
3388 convertedCases.append(c);
3389 break;
3390 default: //multiple labels, expand:
3391 //case C1, C2, C3: ...
3392 //=>
3393 //case C1:
3394 //case C2:
3395 //case C3: ...
3396 List<JCExpression> patterns = c.pats;
3397 while (patterns.tail.nonEmpty()) {
3398 convertedCases.append(make_at(c.pos()).Case(JCCase.STATEMENT,
3399 List.of(patterns.head),
3400 List.nil(),
3401 null));
3402 patterns = patterns.tail;
3403 }
3404 c.pats = patterns;
3405 convertedCases.append(c);
3406 break;
3407 }
3408 }
3409
3410 for (JCCase c : convertedCases) {
3411 if (c.caseKind == JCCase.RULE && c.completesNormally) {
3412 JCBreak b = make_at(c.pos()).Break(null);
3413 b.target = tree;
3414 c.stats = c.stats.append(b);
3415 }
3416 }
3417
3418 cases = convertedCases.toList();
3419
3420 Type selsuper = types.supertype(selector.type);
3421 boolean enumSwitch = selsuper != null &&
3422 (selector.type.tsym.flags() & ENUM) != 0;
3423 boolean stringSwitch = selsuper != null &&
3424 types.isSameType(selector.type, syms.stringType);
3425 Type target = enumSwitch ? selector.type :
3426 (stringSwitch? syms.stringType : syms.intType);
3427 selector = translate(selector, target);
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 }
3438 if (enumSwitch) {
3439 result = visitEnumSwitch(tree, selector, cases);
3440 } else if (stringSwitch) {
3441 result = visitStringSwitch(tree, selector, cases);
3442 } else {
3443 result = tree;
3444 }
3445 }
3446
3447 public JCTree visitEnumSwitch(JCTree tree, JCExpression selector, List<JCCase> cases) {
3448 TypeSymbol enumSym = selector.type.tsym;
3449 EnumMapping map = mapForEnum(tree.pos(), enumSym);
3450 make_at(tree.pos());
3451 Symbol ordinalMethod = lookupMethod(tree.pos(),
3452 names.ordinal,
3453 selector.type,
3454 List.nil());
3455 JCArrayAccess newSelector = make.Indexed(map.mapVar,
3456 make.App(make.Select(selector,
3457 ordinalMethod)));
3458 ListBuffer<JCCase> newCases = new ListBuffer<>();
3459 for (JCCase c : cases) {
3460 if (c.pats.nonEmpty()) {
3461 VarSymbol label = (VarSymbol)TreeInfo.symbol(c.pats.head);
3462 JCLiteral pat = map.forConstant(label);
3463 newCases.append(make.Case(JCCase.STATEMENT, List.of(pat), c.stats, null));
3464 } else {
3465 newCases.append(c);
3466 }
3467 }
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 }
3478 patchTargets(enumSwitch, tree, enumSwitch);
3479 return enumSwitch;
3480 }
3481
3482 public JCTree visitStringSwitch(JCTree tree, JCExpression selector, List<JCCase> caseList) {
3483 int alternatives = caseList.size();
3484
3485 if (alternatives == 0) { // Strange but legal possibility (only legal for switch statement)
3486 return make.at(tree.pos()).Exec(attr.makeNullCheck(selector));
3487 } else {
3488 /*
3489 * The general approach used is to translate a single
3490 * string switch statement into a series of two chained
3491 * switch statements: the first a synthesized statement
3492 * switching on the argument string's hash value and
3493 * computing a string's position in the list of original
3494 * case labels, if any, followed by a second switch on the
3495 * computed integer value. The second switch has the same
3496 * code structure as the original string switch statement
3497 * except that the string case labels are replaced with
3498 * positional integer constants starting at 0.
3499 *
3500 * The first switch statement can be thought of as an
3501 * inlined map from strings to their position in the case
3502 * label list. An alternate implementation would use an
3503 * actual Map for this purpose, as done for enum switches.
3504 *
3505 * With some additional effort, it would be possible to
3506 * use a single switch statement on the hash code of the
3567
3568 /*
3569 * s$ = top of stack;
3570 * tmp$ = -1;
3571 * switch($s.hashCode()) {
3572 * case caseLabel.hashCode:
3573 * if (s$.equals("caseLabel_1")
3574 * tmp$ = caseLabelToPosition("caseLabel_1");
3575 * else if (s$.equals("caseLabel_2"))
3576 * tmp$ = caseLabelToPosition("caseLabel_2");
3577 * ...
3578 * break;
3579 * ...
3580 * }
3581 */
3582
3583 VarSymbol dollar_s = new VarSymbol(FINAL|SYNTHETIC,
3584 names.fromString("s" + tree.pos + target.syntheticNameChar()),
3585 syms.stringType,
3586 currentMethodSym);
3587 stmtList.append(make.at(tree.pos()).VarDef(dollar_s, selector).setType(dollar_s.type));
3588
3589 VarSymbol dollar_tmp = new VarSymbol(SYNTHETIC,
3590 names.fromString("tmp" + tree.pos + target.syntheticNameChar()),
3591 syms.intType,
3592 currentMethodSym);
3593 JCVariableDecl dollar_tmp_def =
3594 (JCVariableDecl)make.VarDef(dollar_tmp, make.Literal(INT, -1)).setType(dollar_tmp.type);
3595 dollar_tmp_def.init.type = dollar_tmp.type = syms.intType;
3596 stmtList.append(dollar_tmp_def);
3597 ListBuffer<JCCase> caseBuffer = new ListBuffer<>();
3598 // hashCode will trigger nullcheck on original switch expression
3599 JCMethodInvocation hashCodeCall = makeCall(make.Ident(dollar_s),
3600 names.hashCode,
3601 List.nil()).setType(syms.intType);
3602 JCSwitch switch1 = make.Switch(hashCodeCall,
3603 caseBuffer.toList());
3604 for(Map.Entry<Integer, Set<String>> entry : hashToString.entrySet()) {
3605 int hashCode = entry.getKey();
3606 Set<String> stringsWithHashCode = entry.getValue();
3607 Assert.check(stringsWithHashCode.size() >= 1);
3617 setType(dollar_tmp.type)),
3618 elsepart);
3619 }
3620
3621 ListBuffer<JCStatement> lb = new ListBuffer<>();
3622 JCBreak breakStmt = make.Break(null);
3623 breakStmt.target = switch1;
3624 lb.append(elsepart).append(breakStmt);
3625
3626 caseBuffer.append(make.Case(JCCase.STATEMENT, List.of(make.Literal(hashCode)), lb.toList(), null));
3627 }
3628
3629 switch1.cases = caseBuffer.toList();
3630 stmtList.append(switch1);
3631
3632 // Make isomorphic switch tree replacing string labels
3633 // with corresponding integer ones from the label to
3634 // position map.
3635
3636 ListBuffer<JCCase> lb = new ListBuffer<>();
3637 for(JCCase oneCase : caseList ) {
3638 boolean isDefault = (oneCase.pats.isEmpty());
3639 JCExpression caseExpr;
3640 if (isDefault)
3641 caseExpr = null;
3642 else {
3643 caseExpr = make.Literal(caseLabelToPosition.get((String)TreeInfo.skipParens(oneCase.pats.head).
3644 type.constValue()));
3645 }
3646
3647 lb.append(make.Case(JCCase.STATEMENT, caseExpr == null ? List.nil() : List.of(caseExpr),
3648 oneCase.stats, null));
3649 }
3650
3651 if (tree.hasTag(SWITCH)) {
3652 JCSwitch switch2 = make.Switch(make.Ident(dollar_tmp), lb.toList());
3653 // Rewire up old unlabeled break statements to the
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 }
3676 }
3677 }
3678
3679 @Override
3680 public void visitBreak(JCBreak tree) {
3681 if (tree.isValueBreak()) {
3682 tree.value = translate(tree.value, tree.target.type);
3683 }
3684 result = tree;
3685 }
3686
3687 public void visitNewArray(JCNewArray tree) {
3688 tree.elemtype = translate(tree.elemtype);
3689 for (List<JCExpression> t = tree.dims; t.tail != null; t = t.tail)
3690 if (t.head != null) t.head = translate(t.head, syms.intType);
3691 tree.elems = translate(tree.elems, types.elemtype(tree.type));
3692 result = tree;
3693 }
3694
3695 public void visitSelect(JCFieldAccess tree) {
3696 // need to special case-access of the form C.super.x
3697 // these will always need an access method, unless C
3698 // is a default interface subclassed by the current class.
3699 boolean qualifiedSuperAccess =
3700 tree.selected.hasTag(SELECT) &&
3701 TreeInfo.name(tree.selected) == names._super &&
3702 !types.isDirectSuperInterface(((JCFieldAccess)tree.selected).selected.type.tsym, currentClass);
3703 tree.selected = translate(tree.selected);
3704 if (tree.name == names._class) {
|