OpenJDK / amber / amber
changeset 56794:424c4d694771 patterns-deconstruction
Support for deconstruction patterns in switches.
author | jlahoda |
---|---|
date | Fri, 14 Jun 2019 13:35:47 +0200 |
parents | a9a1999af6da |
children | e6e27550e2d5 |
files | src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java test/langtools/tools/javac/patterns/SwitchExpressionWithPatterns.java test/langtools/tools/javac/switchexpr/ExhaustiveSealedSwitch.java test/langtools/tools/javac/switchexpr/ExhaustiveSealedSwitchExtra.java |
diffstat | 6 files changed, 142 insertions(+), 6 deletions(-) [+] |
line wrap: on
line diff
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java Fri Jun 14 13:26:15 2019 +0200 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java Fri Jun 14 13:35:47 2019 +0200 @@ -1636,7 +1636,7 @@ addVars(c.stats, switchEnv.info.scope); } - c.completesNormally = flow.aliveAfter(caseEnv, c, make); + c.completesNormally = caseKind != JCCase.RULE && flow.aliveAfter(caseEnv, c, make); prevBindings = c.completesNormally ? matchBindings : null; } } finally {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java Fri Jun 14 13:26:15 2019 +0200 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java Fri Jun 14 13:35:47 2019 +0200 @@ -51,9 +51,12 @@ import static com.sun.tools.javac.code.Flags.*; import static com.sun.tools.javac.code.Flags.BLOCK; import static com.sun.tools.javac.code.Kinds.Kind.*; +import com.sun.tools.javac.code.Type.ClassType; import static com.sun.tools.javac.code.TypeTag.BOOLEAN; +import static com.sun.tools.javac.code.TypeTag.CLASS; import static com.sun.tools.javac.code.TypeTag.VOID; import static com.sun.tools.javac.tree.JCTree.Tag.*; +import java.util.Iterator; /** This pass implements dataflow analysis for Java programs though * different AST visitor steps. Liveness analysis (see AliveAnalyzer) checks that @@ -745,6 +748,9 @@ case LITERALPATTERN: { break; // does not dominate any other pattern. } + case DECONSTRUCTIONPATTERN: { + break; //TODO: domination for deconstruction patterns + } default: { Assert.check(false); break; @@ -800,6 +806,10 @@ constants.add(s.name); } } + Set<Type> permittedTypes = new HashSet<>(); + if (tree.selector.type.hasTag(CLASS) && ((ClassType) tree.selector.type).permitted.nonEmpty()) { + ((ClassType) tree.selector.type).permitted.stream().forEach(permittedTypes::add); + } boolean hasDefault = false; Liveness prevAlive = alive; for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) { @@ -817,6 +827,20 @@ if (lit.type != null) constants.remove(lit.type.constValue()); } + if (permittedTypes != null) { + if (pat.hasTag(BINDINGPATTERN)) { + JCPattern bindingPattern = pat; + Iterator<Type> permIt = permittedTypes.iterator(); + while (permIt.hasNext()) { + if (types.isSameType(permIt.next(), bindingPattern.type)) { + permIt.remove(); + break; + } + } + } else { + //TODO: deconstructor patterns? + } + } } } scanStats(c.stats); @@ -830,7 +854,7 @@ } } } - if ((constants == null || !constants.isEmpty()) && !hasDefault) { + if ((constants == null || !constants.isEmpty()) && (permittedTypes == null || !permittedTypes.isEmpty()) && !hasDefault) { log.error(tree, Errors.NotExhaustive); } alive = prevAlive;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java Fri Jun 14 13:26:15 2019 +0200 +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java Fri Jun 14 13:35:47 2019 +0200 @@ -306,11 +306,11 @@ for (int i = 0; i < ((JCDeconstructionPattern) patt).getNestedPatterns().size(); i++) { JCPattern nested = ((JCDeconstructionPattern) patt).getNestedPatterns().get(i); params[i + 1] = preparePatternExtractor(nested, nested.type, nestedBindings[i] = new ListBuffer<>()); - if (nested.hasTag(Tag.DECONSTRUCTIONPATTERN)) { - bindingVars.append(syms.lengthVar); - } else { + if (nested.hasTag(Tag.BINDINGPATTERN)) { bindingVars.appendList(nestedBindings[i].toList()); nestedBindings[i].clear(); + } else { + bindingVars.append(syms.lengthVar); } } @@ -622,10 +622,25 @@ List<JCStatement> stats = clause.stats; if (clause.completesNormally) { stats = stats.append(make.at(tree.pos).Exec(make.Assign(make.Ident(fallthroughSym), make.Literal(BOOLEAN, 1).setType(syms.booleanType)).setType(syms.booleanType))); + } else { + JCBreak stop = make.at(tree.pos).Break(null); + stop.target = pendingMatchLabel; + stats = stats.append(stop); } body = make.Block(0, stats); JCStatement translatedIf = translate(make.If(jcMatches, body, null)); - JCIf testStatement = translatedIf.hasTag(Tag.IF) ? (JCIf)translatedIf : (JCIf) ((JCBlock)translatedIf).stats.tail.head; + JCIf testStatement = null; + + if (translatedIf.hasTag(Tag.IF)) { + testStatement = (JCIf)translatedIf; + } else { + for (JCStatement st : ((JCBlock)translatedIf).stats) { + if (st.hasTag(Tag.IF)) { + testStatement = (JCIf) st; + break; + } + } + } testStatement.cond = makeBinary(Tag.OR, make.Ident(fallthroughSym),
--- a/test/langtools/tools/javac/patterns/SwitchExpressionWithPatterns.java Fri Jun 14 13:26:15 2019 +0200 +++ b/test/langtools/tools/javac/patterns/SwitchExpressionWithPatterns.java Fri Jun 14 13:35:47 2019 +0200 @@ -46,6 +46,8 @@ assertEquals(3, f.applyAsInt((long) 0)); assertEquals(3, f.applyAsInt((float) 0)); assertEquals(4, f.applyAsInt((byte) 13)); + assertEquals(105, f.applyAsInt(new R(0, 5))); + assertEquals(7, f.applyAsInt(new R(1, 6))); } } @@ -55,6 +57,8 @@ case 41: check++; //fall-through case Integer i: check++; break check; case Long l, Float f: break 3; + case R(0, var j): break 100 + j; + case R(var i, var j): break i + j; default: break 4; }; @@ -66,6 +70,8 @@ case 41 -> 2; case Integer j -> { break 1; } case Long l, Float f -> 3; + case R(0, var j) -> 100 + j; + case R(var i, var j) -> i + j; default -> { break 4; } }; } @@ -76,6 +82,8 @@ case 41: check++; //fall-through case Integer j: check++; break; case Long l, Float f: check = 3; break; + case R(0, var j): check = 100 + j; break; + case R(var i, var j): check = i + j; break; default: check = 4; break; } return check; @@ -87,6 +95,8 @@ case 41 -> check = 2; case Integer j -> { check = 1; } case Long l, Float f -> check = 3; + case R(0, var j) -> check = 100 + j; + case R(var i, var j) -> check = i + j; default -> { check = 4; } }; return check; @@ -96,4 +106,6 @@ if (expected != actual) throw new AssertionError("Expected: " + expected + ", actual: " + actual); } + + record R(int i, int j); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/langtools/tools/javac/switchexpr/ExhaustiveSealedSwitch.java Fri Jun 14 13:35:47 2019 +0200 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Verify that an switch expression over sealed type can be exhaustive without default. + * @compile --enable-preview -source ${jdk.version} ExhaustiveSealedSwitch.java + * @compile --enable-preview -source ${jdk.version} ExhaustiveSealedSwitchExtra.java + * @run main/othervm --enable-preview ExhaustiveSealedSwitch + */ + +public class ExhaustiveSealedSwitch { + public static void main(String... args) throws Exception { + new ExhaustiveSealedSwitch().run(); + } + + private void run() throws Exception { + ExhaustiveSealedSwitchIntf i = (ExhaustiveSealedSwitchIntf) Class.forName("ExhaustiveSealedSwitchC").newInstance(); + + try { + print(i); + throw new AssertionError("Expected exception did not occur."); + } catch (IncompatibleClassChangeError err) { + //ok + } + } + + private String print(ExhaustiveSealedSwitchIntf t) { + return switch (t) { + case ExhaustiveSealedSwitchA a -> "A"; + case ExhaustiveSealedSwitchB b -> "B"; + }; + } + +} +sealed interface ExhaustiveSealedSwitchIntf permits ExhaustiveSealedSwitchA, ExhaustiveSealedSwitchB { +} +class ExhaustiveSealedSwitchA implements ExhaustiveSealedSwitchIntf {} +class ExhaustiveSealedSwitchB implements ExhaustiveSealedSwitchIntf {}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/langtools/tools/javac/switchexpr/ExhaustiveSealedSwitchExtra.java Fri Jun 14 13:35:47 2019 +0200 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +sealed interface ExhaustiveSealedSwitchIntf permits ExhaustiveSealedSwitchA, ExhaustiveSealedSwitchB, ExhaustiveSealedSwitchC { +} +class ExhaustiveSealedSwitchC implements ExhaustiveSealedSwitchIntf {}