< prev index next >
src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java
Print this page
rev 52724 : imported patch 8214031
*** 61,70 ****
--- 61,71 ----
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,3458 ****
.restype.type));
result = tree;
}
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;
boolean stringSwitch = selsuper != null &&
! types.isSameType(tree.selector.type, syms.stringType);
! Type target = enumSwitch ? tree.selector.type :
(stringSwitch? syms.stringType : syms.intType);
! tree.selector = translate(tree.selector, target);
! tree.cases = translateCases(tree.cases);
if (enumSwitch) {
! result = visitEnumSwitch(tree);
} else if (stringSwitch) {
! result = visitStringSwitch(tree);
} else {
result = tree;
}
}
! public JCTree visitEnumSwitch(JCSwitch tree) {
! TypeSymbol enumSym = tree.selector.type.tsym;
EnumMapping map = mapForEnum(tree.pos(), enumSym);
make_at(tree.pos());
Symbol ordinalMethod = lookupMethod(tree.pos(),
names.ordinal,
! tree.selector.type,
List.nil());
! JCArrayAccess selector = make.Indexed(map.mapVar,
! make.App(make.Select(tree.selector,
ordinalMethod)));
! ListBuffer<JCCase> cases = new ListBuffer<>();
! for (JCCase c : tree.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));
} else {
! cases.append(c);
}
}
! JCSwitch enumSwitch = make.Switch(selector, cases.toList());
patchTargets(enumSwitch, tree, enumSwitch);
return enumSwitch;
}
! public JCTree visitStringSwitch(JCSwitch tree) {
! List<JCCase> caseList = tree.getCases();
int alternatives = caseList.size();
! if (alternatives == 0) { // Strange but legal possibility
! return make.at(tree.pos()).Exec(attr.makeNullCheck(tree.getExpression()));
} 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
--- 3361,3491 ----
.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> convertedCases = new ListBuffer<>();
! for (JCCase c : cases) {
switch (c.pats.size()) {
case 0: //default
case 1: //single label
! 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()) {
! convertedCases.append(make_at(c.pos()).Case(JCCase.STATEMENT,
List.of(patterns.head),
List.nil(),
null));
patterns = patterns.tail;
}
c.pats = patterns;
! convertedCases.append(c);
break;
}
}
! 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);
}
}
! cases = convertedCases.toList();
! Type selsuper = types.supertype(selector.type);
boolean enumSwitch = selsuper != null &&
! (selector.type.tsym.flags() & ENUM) != 0;
boolean stringSwitch = selsuper != null &&
! types.isSameType(selector.type, syms.stringType);
! Type target = enumSwitch ? selector.type :
(stringSwitch? syms.stringType : syms.intType);
! 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, selector, cases);
} else if (stringSwitch) {
! result = visitStringSwitch(tree, selector, cases);
} else {
result = tree;
}
}
! 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,
! selector.type,
List.nil());
! JCArrayAccess newSelector = make.Indexed(map.mapVar,
! make.App(make.Select(selector,
ordinalMethod)));
! 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);
! newCases.append(make.Case(JCCase.STATEMENT, List.of(pat), c.stats, null));
} else {
! newCases.append(c);
}
}
! 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(JCTree tree, JCExpression selector, List<JCCase> caseList) {
int alternatives = caseList.size();
! 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,3559 ****
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));
VarSymbol dollar_tmp = new VarSymbol(SYNTHETIC,
names.fromString("tmp" + tree.pos + target.syntheticNameChar()),
syms.intType,
currentMethodSym);
--- 3582,3592 ----
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, selector).setType(dollar_s.type));
VarSymbol dollar_tmp = new VarSymbol(SYNTHETIC,
names.fromString("tmp" + tree.pos + target.syntheticNameChar()),
syms.intType,
currentMethodSym);
*** 3599,3702 ****
// 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));
}
! switch2.cases = lb.toList();
stmtList.append(switch2);
return make.Block(0L, stmtList.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);
! 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)
--- 3632,3689 ----
// Make isomorphic switch tree replacing string labels
// with corresponding integer ones from the label to
// position map.
ListBuffer<JCCase> lb = new ListBuffer<>();
for(JCCase oneCase : caseList ) {
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.stats, null));
}
! 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());
! // Rewire up old unlabeled break statements to the
! // replacement switch being created.
! patchTargets(switch2, tree, switch2);
! switch2.setType(tree.type);
! LetExpr res = make.LetExpr(stmtList.toList(), switch2);
! res.needsCond = true;
! res.setType(tree.type);
! return res;
}
! }
! }
!
@Override
public void visitBreak(JCBreak tree) {
! if (tree.isValueBreak()) {
! tree.value = translate(tree.value, tree.target.type);
}
! 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 >