< 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 >