< prev index next >
src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java
Print this page
rev 51104 : imported patch switch
@@ -24,11 +24,15 @@
*/
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;
import com.sun.tools.javac.jvm.*;
import com.sun.tools.javac.main.Option.PkgInfo;
@@ -52,10 +56,14 @@
import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
import static com.sun.tools.javac.code.TypeTag.*;
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.*;
/** This pass translates away some syntactic sugar: inner classes,
* class literals, assertions, foreach loops, etc.
@@ -362,10 +370,17 @@
outerThisStack.head != null)
visitSymbol(outerThisStack.head);
}
super.visitApply(tree);
}
+
+ @Override
+ public void visitBreak(JCBreak tree) {
+ if (tree.isValueBreak())
+ scan(tree.value);
+ }
+
}
ClassSymbol ownerToCopyFreeVarsFrom(ClassSymbol c) {
if (!c.isLocal()) {
return null;
@@ -3338,10 +3353,44 @@
.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:
+ 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);
@@ -3369,14 +3418,14 @@
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.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);
}
}
JCSwitch enumSwitch = make.Switch(selector, cases.toList());
@@ -3440,14 +3489,14 @@
// Map of hash codes to the string case labels having that hashCode.
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
+ for(JCCase oneCase : caseList) {
+ 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);
int hashCode = labelExpr.hashCode();
@@ -3527,11 +3576,11 @@
ListBuffer<JCStatement> lb = new ListBuffer<>();
JCBreak breakStmt = make.Break(null);
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();
stmtList.append(switch1);
@@ -3544,31 +3593,88 @@
for(JCCase oneCase : caseList ) {
// Rewire up old unlabeled break statements to the
// 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();
stmtList.append(switch2);
return make.Block(0L, stmtList.toList());
}
}
+ @Override
+ public void visitSwitchExpression(JCSwitchExpression tree) {
+ 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)
if (t.head != null) t.head = translate(t.head, syms.intType);
tree.elems = translate(tree.elems, types.elemtype(tree.type));
@@ -3600,11 +3706,11 @@
else
result = access(tree.sym, tree, enclOp, qualifiedSuperAccess);
}
public void visitLetExpr(LetExpr tree) {
- tree.defs = translateVarDefs(tree.defs);
+ tree.defs = translate(tree.defs);
tree.expr = translate(tree.expr, tree.type);
result = tree;
}
// There ought to be nothing to rewrite here;
< prev index next >