Skip to content

Commit 0e8d911

Browse files
committedApr 19, 2022
Adding support for binding variables for the whole deconstruction pattern.
1 parent 48b6577 commit 0e8d911

15 files changed

+134
-8
lines changed
 

‎src/jdk.compiler/share/classes/com/sun/source/tree/DeconstructionPatternTree.java

+6
Original file line numberDiff line numberDiff line change
@@ -48,5 +48,11 @@ public interface DeconstructionPatternTree extends PatternTree {
4848
*/
4949
List<? extends PatternTree> getNestedPatterns();
5050

51+
/**
52+
* Returns the binding variable.
53+
* @return the binding variable
54+
*/
55+
VariableTree getVariable();
56+
5157
}
5258

‎src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java

+4-1
Original file line numberDiff line numberDiff line change
@@ -806,7 +806,10 @@ public R visitDefaultCaseLabel(DefaultCaseLabelTree node, P p) {
806806
@PreviewFeature(feature=PreviewFeature.Feature.DECONSTRUCTION_PATTERNS, reflective=true)
807807
public R visitDeconstructionPattern(DeconstructionPatternTree node, P p) {
808808
R r = scan(node.getDeconstructor(), p);
809-
return scanAndReduce(node.getNestedPatterns(), p, r);
809+
r = scanAndReduce(node.getNestedPatterns(), p, r);
810+
r = scanAndReduce(node.getVariable(), p, r);
811+
r = scanAndReduce(node.getGuard(), p, r);
812+
return r;
810813
}
811814

812815
/**

‎src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java

+15
Original file line numberDiff line numberDiff line change
@@ -4223,6 +4223,21 @@ public void visitDeconstructionPattern(JCDeconstructionPattern tree) {
42234223
Errors.IncorrectNumberOfNestedPatterns(expectedRecordTypes,
42244224
nestedTypes));
42254225
}
4226+
if (tree.var != null) {
4227+
BindingSymbol v = new BindingSymbol(tree.var.mods.flags, tree.var.name, tree.type, env.info.scope.owner);
4228+
v.pos = tree.pos;
4229+
tree.var.sym = v;
4230+
if (chk.checkUnique(tree.var.pos(), v, env.info.scope)) {
4231+
chk.checkTransparentVar(tree.var.pos(), v, env.info.scope);
4232+
}
4233+
if (tree.var.vartype != null) {
4234+
annotate.annotateLater(tree.var.mods.annotations, env, v, tree.pos());
4235+
annotate.queueScanTreeAndTypeAnnotate(tree.var.vartype, env, v, tree.var.pos());
4236+
annotate.flush();
4237+
}
4238+
outBindings.add(v);
4239+
}
4240+
chk.validate(tree.deconstructor, env, true);
42264241
result = tree.type;
42274242
matchBindings = new MatchBindings(outBindings.toList(), List.nil());
42284243
}

‎src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java

+21
Original file line numberDiff line numberDiff line change
@@ -2918,6 +2918,14 @@ public void visitBindingPattern(JCBindingPattern tree) {
29182918
scan(tree.guard);
29192919
}
29202920

2921+
@Override
2922+
public void visitDeconstructionPattern(JCDeconstructionPattern tree) {
2923+
super.visitDeconstructionPattern(tree);
2924+
if (tree.var != null) {
2925+
initParam(tree.var);
2926+
}
2927+
}
2928+
29212929
void referenced(Symbol sym) {
29222930
unrefdResources.remove(sym);
29232931
}
@@ -3105,6 +3113,19 @@ public void visitParenthesizedPattern(JCParenthesizedPattern tree) {
31053113
}
31063114
}
31073115

3116+
@Override
3117+
public void visitDeconstructionPattern(JCDeconstructionPattern tree) {
3118+
scan(tree.deconstructor);
3119+
scan(tree.nested);
3120+
JCTree prevTree = currentTree;
3121+
try {
3122+
currentTree = tree;
3123+
scan(tree.guard);
3124+
} finally {
3125+
currentTree = prevTree;
3126+
}
3127+
}
3128+
31083129
@Override
31093130
public void visitIdent(JCIdent tree) {
31103131
if (tree.sym.kind == VAR) {

‎src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java

+15
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,21 @@ public void visitDeconstructionPattern(JCDeconstructionPattern tree) {
318318
nestedFullComponentTypes = nestedFullComponentTypes.tail;
319319
nestedPatterns = nestedPatterns.tail;
320320
}
321+
322+
if (tree.var != null) {
323+
BindingSymbol binding = (BindingSymbol) tree.var.sym;
324+
Type castTargetType = principalType(tree);
325+
VarSymbol bindingVar = bindingContext.bindingDeclared(binding);
326+
327+
JCAssign fakeInit = (JCAssign)make.at(TreeInfo.getStartPos(tree)).Assign(
328+
make.Ident(bindingVar), convert(make.Ident(currentValue), castTargetType)).setType(bindingVar.erasure(types));
329+
LetExpr nestedLE = make.LetExpr(List.of(make.Exec(fakeInit)),
330+
make.Literal(true));
331+
nestedLE.needsCond = true;
332+
nestedLE.setType(syms.booleanType);
333+
test = test != null ? makeBinary(Tag.AND, test, nestedLE) : nestedLE;
334+
}
335+
321336
Assert.check(components.isEmpty() == nestedPatterns.isEmpty());
322337
Assert.check(components.isEmpty() == nestedFullComponentTypes.isEmpty());
323338
result = test != null ? test : makeLit(syms.booleanType, 1);

‎src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java

+16-2
Original file line numberDiff line numberDiff line change
@@ -794,7 +794,14 @@ public JCPattern parsePattern(int pos, JCModifiers mods, JCExpression parsedType
794794
nested.append(nestedPattern);
795795
} while (token.kind == COMMA);
796796
accept(RPAREN);
797-
pattern = toP(F.at(pos).DeconstructionPattern(e, nested.toList()));
797+
JCVariableDecl var;
798+
if (token.kind == IDENTIFIER) {
799+
var = to(F.at(pos).VarDef(F.Modifiers(0), token.name(), e, null));
800+
nextToken(); //TODO: tests!
801+
} else {
802+
var = null;
803+
}
804+
pattern = toP(F.at(pos).DeconstructionPattern(e, nested.toList(), var));
798805
} else {
799806
JCVariableDecl var = toP(F.at(token.pos).VarDef(mods, ident(), e, null));
800807
pattern = toP(F.at(pos).BindingPattern(var));
@@ -1003,7 +1010,14 @@ JCExpression term2Rest(JCExpression t, int minprec) {
10031010
nested.append(nestedPattern);
10041011
} while (token.kind == COMMA);
10051012
accept(RPAREN);
1006-
pattern = toP(F.at(type).DeconstructionPattern(type, nested.toList()));
1013+
JCVariableDecl var;
1014+
if (token.kind == IDENTIFIER) {
1015+
var = to(F.at(pos).VarDef(F.Modifiers(0), token.name(), type, null));
1016+
nextToken();
1017+
} else {
1018+
var = null;
1019+
}
1020+
pattern = toP(F.at(type).DeconstructionPattern(type, nested.toList(), var));
10071021
} else {
10081022
checkNoMods(typePos, mods.flags & ~Flags.DEPRECATED);
10091023
if (mods.annotations.nonEmpty()) {

‎src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java

+10-1
Original file line numberDiff line numberDiff line change
@@ -2374,12 +2374,15 @@ public static class JCDeconstructionPattern extends JCPattern
23742374
implements DeconstructionPatternTree {
23752375
public JCExpression deconstructor;
23762376
public List<JCPattern> nested;
2377+
public JCVariableDecl var;
23772378
public ClassSymbol record;
23782379
public List<Type> fullComponentTypes;
23792380

2380-
protected JCDeconstructionPattern(JCExpression deconstructor, List<JCPattern> nested) {
2381+
protected JCDeconstructionPattern(JCExpression deconstructor, List<JCPattern> nested,
2382+
JCVariableDecl var) {
23812383
this.deconstructor = deconstructor;
23822384
this.nested = nested;
2385+
this.var = var;
23832386
}
23842387

23852388
@DefinedBy(Api.COMPILER_TREE)
@@ -2417,6 +2420,12 @@ public <R, D> R accept(TreeVisitor<R, D> v, D d) {
24172420
public Tag getTag() {
24182421
return DECONSTRUCTIONPATTERN;
24192422
}
2423+
2424+
@Override @DefinedBy(Api.COMPILER_TREE)
2425+
public VariableTree getVariable() {
2426+
return var;
2427+
}
2428+
24202429
}
24212430

24222431
/**

‎src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java

+4
Original file line numberDiff line numberDiff line change
@@ -939,6 +939,10 @@ public void visitDeconstructionPattern(JCDeconstructionPattern tree) {
939939
print("(");
940940
printExprs(tree.nested);
941941
print(")");
942+
if (tree.var != null) {
943+
print(" ");
944+
print(tree.var.name);
945+
}
942946
} catch (IOException e) {
943947
throw new UncheckedIOException(e);
944948
}

‎src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -521,7 +521,8 @@ public JCTree visitDeconstructionPattern(DeconstructionPatternTree node, P p) {
521521
JCDeconstructionPattern t = (JCDeconstructionPattern) node;
522522
JCExpression deconstructor = copy(t.deconstructor, p);
523523
List<JCPattern> nested = copy(t.nested, p);
524-
return M.at(t.pos).DeconstructionPattern(deconstructor, nested);
524+
JCVariableDecl var = copy(t.var, p);
525+
return M.at(t.pos).DeconstructionPattern(deconstructor, nested, var);
525526
}
526527

527528
@DefinedBy(Api.COMPILER_TREE)

‎src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -500,8 +500,9 @@ public JCParenthesizedPattern ParenthesizedPattern(JCPattern pattern) {
500500
return tree;
501501
}
502502

503-
public JCDeconstructionPattern DeconstructionPattern(JCExpression deconstructor, List<JCPattern> nested) {
504-
JCDeconstructionPattern tree = new JCDeconstructionPattern(deconstructor, nested);
503+
public JCDeconstructionPattern DeconstructionPattern(JCExpression deconstructor, List<JCPattern> nested,
504+
JCVariableDecl var) {
505+
JCDeconstructionPattern tree = new JCDeconstructionPattern(deconstructor, nested, var);
505506
tree.pos = pos;
506507
return tree;
507508
}

‎src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java

+4
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,10 @@ public void visitParenthesizedPattern(JCParenthesizedPattern tree) {
322322
public void visitDeconstructionPattern(JCDeconstructionPattern that) {
323323
scan(that.deconstructor);
324324
scan(that.nested);
325+
if (that.var != null) {
326+
scan(that.var);
327+
}
328+
scan(that.guard);
325329
}
326330

327331
public void visitIndexed(JCArrayAccess tree) {

‎test/langtools/tools/javac/patterns/PrettyTest.java

+2
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ void run() throws Exception {
5555
" b = o instanceof R(var s);\n" +
5656
" b = o instanceof R2(R(var s), String t);\n" +
5757
" b = o instanceof R2(R(var s), var t);\n" +
58+
" b = o instanceof R(String s) r;\n" +
5859
" }\n" +
5960
" record R(String s) {}\n" +
6061
" record R2(R r, String s) {}\n" +
@@ -71,6 +72,7 @@ boolean t(Object o) {
7172
b = o instanceof R(/*missing*/ s);
7273
b = o instanceof R2(R(/*missing*/ s), String t);
7374
b = o instanceof R2(R(/*missing*/ s), /*missing*/ t);
75+
b = o instanceof R(String s) r;
7476
}
7577
\n\
7678
class R {

‎test/langtools/tools/javac/patterns/SimpleDeconstructionPattern.java

+7
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ public static void main(String... args) throws Throwable {
9494
if (!testC(new P6(new P3("")))) {
9595
throw new IllegalStateException();
9696
}
97+
if (!testD(new P4("test"))) {
98+
throw new IllegalStateException();
99+
}
97100
if (!testGen1(new GenRecord1<>(1L, ""))) {
98101
throw new IllegalStateException();
99102
}
@@ -171,6 +174,10 @@ private static boolean testC(Object o) throws Throwable {
171174
return o instanceof P6(P3(String s)) && s.isEmpty();
172175
}
173176

177+
private static boolean testD(Object o) throws Throwable {
178+
return o instanceof P4(String s) p && (s.isEmpty() || "test".equals(p.o()));
179+
}
180+
174181
private static boolean testGen1(Object o) throws Throwable {
175182
return o instanceof GenRecord1(var i, var s) && s.length() == 0;
176183
}
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
SimpleDeconstructionPattern.java:149:27: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.deconstruction.patterns)
1+
SimpleDeconstructionPattern.java:124:27: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.deconstruction.patterns)
22
1 error

‎test/langtools/tools/javac/patterns/Switches.java

+24
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,12 @@ void run() {
8888
assertEquals(5, switchOverPrimitiveInt(0));
8989
assertEquals(7, switchOverPrimitiveInt(1));
9090
assertEquals(9, switchOverPrimitiveInt(2));
91+
assertEquals("a", deconstructStatement(new R("a")));
92+
assertEquals("1", deconstructStatement(new R(1)));
93+
assertEquals("other", deconstructStatement(""));
94+
assertEquals("a", deconstructExpression(new R("a")));
95+
assertEquals("1", deconstructExpression(new R(1)));
96+
assertEquals("other", deconstructExpression(""));
9197
}
9298

9399
void run(Function<Object, Integer> mapper) {
@@ -611,6 +617,22 @@ private int switchOverPrimitiveInt(Integer i) {
611617
};
612618
}
613619

620+
String deconstructStatement(Object o) {
621+
switch (o) {
622+
case R(String s) -> {return s;}
623+
case R(Integer i) r -> {return r.o().toString();}
624+
case Object x -> {return "other";}
625+
}
626+
}
627+
628+
String deconstructExpression(Object o) {
629+
return switch (o) {
630+
case R(String s) -> s;
631+
case R(Integer i) r -> r.o().toString();
632+
case Object x -> "other";
633+
};
634+
}
635+
614636
//verify that for cases like:
615637
//case ConstantClassClash ->
616638
//ConstantClassClash is interpreted as a field, not as a class
@@ -650,4 +672,6 @@ public enum E implements Runnable {
650672

651673
@Override public void run() {}
652674
}
675+
676+
record R(Object o) {}
653677
}

0 commit comments

Comments
 (0)
Please sign in to comment.