Skip to content

Commit 8aa5028

Browse files
biboudislahodaj
andcommitted
8302344: Compiler Implementation for Unnamed patterns and variables (Preview)
8307444: java.lang.AssertionError when using unnamed patterns 8307482: Compiler should accept var _ in nested patterns in switch case 8307007: Implementation for javax.lang.model for unnamed variables (Preview) 8308312: Compiler should fail when a local variable declaration does not include an Identifier and does not have an initializer 8308309: Compiler should accept mixed masked and unmasked variables in lambda parameters Co-authored-by: Jan Lahoda <jlahoda@openjdk.org> Co-authored-by: Aggelos Biboudis <abimpoudis@openjdk.org> Reviewed-by: vromero, darcy
1 parent b588797 commit 8aa5028

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+1636
-449
lines changed

src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java

+2
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ public enum Feature {
7070
FOREIGN,
7171
@JEP(number=430, title="String Templates", status="First Preview")
7272
STRING_TEMPLATES,
73+
@JEP(number=443, title="Unnamed Patterns and Variables")
74+
UNNAMED,
7375
/**
7476
* A key for testing.
7577
*/

src/java.compiler/share/classes/javax/lang/model/element/Element.java

+4-3
Original file line numberDiff line numberDiff line change
@@ -131,9 +131,10 @@ public interface Element extends javax.lang.model.AnnotatedConstruct {
131131
* {@code java.util.Set<E>} is {@code "Set"}.
132132
*
133133
* If this element represents an unnamed {@linkplain
134-
* PackageElement#getSimpleName package} or unnamed {@linkplain
135-
* ModuleElement#getSimpleName module}, an {@linkplain
136-
* Name##empty_name empty name} is returned.
134+
* PackageElement#getSimpleName package}, an unnamed {@linkplain
135+
* ModuleElement#getSimpleName module} or an unnamed {@linkplain
136+
* VariableElement#getSimpleName variable}, an {@linkplain Name##empty_name empty name}
137+
* is returned.
137138
*
138139
* If it represents a {@linkplain ExecutableElement#getSimpleName
139140
* constructor}, the name "{@code <init>}" is returned. If it

src/java.compiler/share/classes/javax/lang/model/element/VariableElement.java

+22
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525

2626
package javax.lang.model.element;
2727

28+
import jdk.internal.javac.PreviewFeature;
29+
2830
import javax.lang.model.util.Elements;
2931
import javax.lang.model.type.TypeMirror;
3032
import javax.lang.model.type.TypeKind;
@@ -81,6 +83,9 @@ public interface VariableElement extends Element {
8183
* parameters of the same executable. If the original source
8284
* names are not available, an implementation may synthesize names
8385
* subject to the distinctness requirement above.
86+
*
87+
* <p>For variables, the name of each variable is returned, or an empty name
88+
* if the variable is unnamed.
8489
*/
8590
@Override
8691
Name getSimpleName();
@@ -93,4 +98,21 @@ public interface VariableElement extends Element {
9398
*/
9499
@Override
95100
Element getEnclosingElement();
101+
102+
/**
103+
* {@return {@code true} if this is an unnamed variable and {@code
104+
* false} otherwise}
105+
*
106+
* @implSpec
107+
* The default implementation of this method calls {@code
108+
* getSimpleName()} and returns {@code true} if the result is
109+
* empty and {@code false} otherwise.
110+
*
111+
* @jls 6.1 Declarations
112+
* @jls 14.4 Local Variable Declarations
113+
*
114+
* @since 21
115+
*/
116+
@PreviewFeature(feature=PreviewFeature.Feature.UNNAMED, reflective = true)
117+
default boolean isUnnamed() { return getSimpleName().isEmpty(); }
96118
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
package com.sun.source.tree;
26+
27+
import jdk.internal.javac.PreviewFeature;
28+
29+
/**
30+
* A tree node for a binding pattern that matches a pattern
31+
* with a variable of any name and a type of the match candidate;
32+
* an unnamed pattern.
33+
*
34+
* For example the use of underscore {@code _} below:
35+
* <pre>
36+
* if (r instanceof R(_)) {}
37+
* </pre>
38+
*
39+
* @jls 14.30.1 Kinds of Patterns
40+
*
41+
* @since 21
42+
*/
43+
@PreviewFeature(feature=PreviewFeature.Feature.UNNAMED)
44+
public interface AnyPatternTree extends PatternTree {
45+
}

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

+8
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,14 @@ public enum Kind {
227227
*/
228228
PARENTHESIZED(ParenthesizedTree.class),
229229

230+
/**
231+
* Used for instances of {@link BindingPatternTree}.
232+
*
233+
* @since 21
234+
*/
235+
@PreviewFeature(feature=PreviewFeature.Feature.UNNAMED)
236+
ANY_PATTERN(AnyPatternTree.class),
237+
230238
/**
231239
* Used for instances of {@link BindingPatternTree}.
232240
*

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

+10
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,16 @@ public interface TreeVisitor<R,P> {
268268
@PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES, reflective=true)
269269
R visitStringTemplate(StringTemplateTree node, P p);
270270

271+
/**
272+
* Visits a {@code AnyPatternTree} node.
273+
* @param node the node being visited
274+
* @param p a parameter value
275+
* @return a result value
276+
* @since 21
277+
*/
278+
@PreviewFeature(feature=PreviewFeature.Feature.UNNAMED)
279+
R visitAnyPattern(AnyPatternTree node, P p);
280+
271281
/**
272282
* Visits a {@code BindingPatternTree} node.
273283
* @param node the node being visited

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ public interface VariableTree extends StatementTree {
5151
ModifiersTree getModifiers();
5252

5353
/**
54-
* Returns the name of the variable being declared.
54+
* Returns the name of the variable being declared or empty name if both the variable
55+
* is unnamed and the preview features are enabled (Unnamed Patterns and Variables).
5556
* @return the name
5657
*/
5758
Name getName();

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

+16
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,22 @@ public R visitStringTemplate(StringTemplateTree node, P p) {
641641
return defaultAction(node, p);
642642
}
643643

644+
/**
645+
* {@inheritDoc}
646+
*
647+
* @implSpec This implementation calls {@code defaultAction}.
648+
*
649+
* @param node {@inheritDoc}
650+
* @param p {@inheritDoc}
651+
* @return the result of {@code defaultAction}
652+
* @since 21
653+
*/
654+
@Override
655+
@PreviewFeature(feature=PreviewFeature.Feature.UNNAMED)
656+
public R visitAnyPattern(AnyPatternTree node, P p) {
657+
return defaultAction(node, p);
658+
}
659+
644660
/**
645661
* {@inheritDoc}
646662
*

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

+15
Original file line numberDiff line numberDiff line change
@@ -760,6 +760,21 @@ public R visitInstanceOf(InstanceOfTree node, P p) {
760760
return r;
761761
}
762762

763+
/**
764+
* {@inheritDoc}
765+
*
766+
* @implSpec This implementation returns {@code null}.
767+
*
768+
* @param node {@inheritDoc}
769+
* @param p {@inheritDoc}
770+
* @return the result of scanning
771+
* @since 21
772+
*/
773+
@Override
774+
public R visitAnyPattern(AnyPatternTree node, P p) {
775+
return null;
776+
}
777+
763778
/**
764779
* {@inheritDoc}
765780
*

src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ public boolean isEnabled() {
210210
public boolean isPreview(Feature feature) {
211211
return switch (feature) {
212212
case STRING_TEMPLATES -> true;
213-
213+
case UNNAMED_VARIABLES -> true;
214214
//Note: this is a backdoor which allows to optionally treat all features as 'preview' (for testing).
215215
//When real preview features will be added, this method can be implemented to return 'true'
216216
//for those selected features, and 'false' for all the others.

src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java

+1
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ public enum Feature {
239239
RECORD_PATTERNS(JDK21, Fragments.FeatureDeconstructionPatterns, DiagKind.PLURAL),
240240
STRING_TEMPLATES(JDK21, Fragments.FeatureStringTemplates, DiagKind.PLURAL),
241241
WARN_ON_ILLEGAL_UTF8(MIN, JDK21),
242+
UNNAMED_VARIABLES(JDK21, Fragments.FeatureUnnamedVariables, DiagKind.PLURAL),
242243
;
243244

244245
enum DiagKind {

src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java

+5
Original file line numberDiff line numberDiff line change
@@ -1641,6 +1641,7 @@ public List<Type> getPermittedSubclasses() {
16411641

16421642
/** A class for variable symbols
16431643
*/
1644+
@SuppressWarnings("preview")
16441645
public static class VarSymbol extends Symbol implements VariableElement {
16451646

16461647
/** The variable's declaration position.
@@ -1783,6 +1784,10 @@ public void setData(Object data) {
17831784
public <R, P> R accept(Symbol.Visitor<R, P> v, P p) {
17841785
return v.visitVarSymbol(this, p);
17851786
}
1787+
1788+
public boolean isUnnamedVariable() {
1789+
return name.isEmpty();
1790+
}
17861791
}
17871792

17881793
public static class RecordComponent extends VarSymbol implements RecordComponentElement {

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

+19-4
Original file line numberDiff line numberDiff line change
@@ -1688,7 +1688,7 @@ private void handleSwitch(JCTree switchTree,
16881688
wasError = true;
16891689
}
16901690
MatchBindings currentBindings = null;
1691-
boolean wasUnconditionalPattern = hasUnconditionalPattern;
1691+
MatchBindings guardBindings = null;
16921692
for (List<JCCaseLabel> labels = c.labels; labels.nonEmpty(); labels = labels.tail) {
16931693
JCCaseLabel label = labels.head;
16941694
if (label instanceof JCConstantCaseLabel constLabel) {
@@ -1761,15 +1761,17 @@ private void handleSwitch(JCTree switchTree,
17611761
checkCastablePattern(pat.pos(), seltype, primaryType);
17621762
Type patternType = types.erasure(primaryType);
17631763
JCExpression guard = c.guard;
1764-
if (labels.tail.isEmpty() && guard != null) {
1764+
if (guardBindings == null && guard != null) {
17651765
MatchBindings afterPattern = matchBindings;
17661766
Env<AttrContext> bodyEnv = bindingEnv(switchEnv, matchBindings.bindingsWhenTrue);
17671767
try {
17681768
attribExpr(guard, bodyEnv, syms.booleanType);
17691769
} finally {
17701770
bodyEnv.info.scope.leave();
17711771
}
1772-
matchBindings = matchBindingsComputer.caseGuard(c, afterPattern, matchBindings);
1772+
1773+
guardBindings = matchBindings;
1774+
matchBindings = afterPattern;
17731775

17741776
if (TreeInfo.isBooleanWithValue(guard, 0)) {
17751777
log.error(guard.pos(), Errors.GuardHasConstantExpressionFalse);
@@ -1796,6 +1798,10 @@ private void handleSwitch(JCTree switchTree,
17961798
currentBindings = matchBindingsComputer.switchCase(label, currentBindings, matchBindings);
17971799
}
17981800

1801+
if (guardBindings != null) {
1802+
currentBindings = matchBindingsComputer.caseGuard(c, currentBindings, guardBindings);
1803+
}
1804+
17991805
Env<AttrContext> caseEnv =
18001806
bindingEnv(switchEnv, c, currentBindings.bindingsWhenTrue);
18011807
try {
@@ -4145,6 +4151,11 @@ private boolean checkCastablePattern(DiagnosticPosition pos,
41454151
}
41464152
}
41474153

4154+
@Override
4155+
public void visitAnyPattern(JCAnyPattern tree) {
4156+
result = tree.type = resultInfo.pt;
4157+
}
4158+
41484159
public void visitBindingPattern(JCBindingPattern tree) {
41494160
Type type;
41504161
if (tree.var.vartype != null) {
@@ -4166,7 +4177,11 @@ public void visitBindingPattern(JCBindingPattern tree) {
41664177
}
41674178
chk.validate(tree.var.vartype, env, true);
41684179
result = tree.type;
4169-
matchBindings = new MatchBindings(List.of(v), List.nil());
4180+
if (v.isUnnamedVariable()) {
4181+
matchBindings = MatchBindingsComputer.EMPTY;
4182+
} else {
4183+
matchBindings = new MatchBindings(List.of(v), List.nil());
4184+
}
41704185
}
41714186

41724187
@Override

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

+6-3
Original file line numberDiff line numberDiff line change
@@ -4572,8 +4572,11 @@ void checkSwitchCaseStructure(List<JCCase> cases) {
45724572
}
45734573
}
45744574
}
4575-
} else {
4576-
if (c.labels.tail.nonEmpty()) {
4575+
} else if (c.labels.tail.nonEmpty()) {
4576+
var patterCaseLabels = c.labels.stream().filter(ll -> ll instanceof JCPatternCaseLabel).map(cl -> (JCPatternCaseLabel)cl);
4577+
var allUnderscore = patterCaseLabels.allMatch(pcl -> !hasBindings(pcl.getPattern()));
4578+
4579+
if (!allUnderscore) {
45774580
log.error(c.labels.tail.head.pos(), Errors.FlowsThroughFromPattern);
45784581
}
45794582
}
@@ -4608,7 +4611,7 @@ boolean hasBindings(JCPattern p) {
46084611
new TreeScanner() {
46094612
@Override
46104613
public void visitBindingPattern(JCBindingPattern tree) {
4611-
bindings[0] = true;
4614+
bindings[0] = !tree.var.sym.isUnnamedVariable();
46124615
super.visitBindingPattern(tree);
46134616
}
46144617
}.scan(p);

0 commit comments

Comments
 (0)