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
This commit is contained in:
parent
b588797900
commit
8aa50288a1
@ -70,6 +70,8 @@ public @interface PreviewFeature {
|
||||
FOREIGN,
|
||||
@JEP(number=430, title="String Templates", status="First Preview")
|
||||
STRING_TEMPLATES,
|
||||
@JEP(number=443, title="Unnamed Patterns and Variables")
|
||||
UNNAMED,
|
||||
/**
|
||||
* A key for testing.
|
||||
*/
|
||||
|
@ -131,9 +131,10 @@ public interface Element extends javax.lang.model.AnnotatedConstruct {
|
||||
* {@code java.util.Set<E>} is {@code "Set"}.
|
||||
*
|
||||
* If this element represents an unnamed {@linkplain
|
||||
* PackageElement#getSimpleName package} or unnamed {@linkplain
|
||||
* ModuleElement#getSimpleName module}, an {@linkplain
|
||||
* Name##empty_name empty name} is returned.
|
||||
* PackageElement#getSimpleName package}, an unnamed {@linkplain
|
||||
* ModuleElement#getSimpleName module} or an unnamed {@linkplain
|
||||
* VariableElement#getSimpleName variable}, an {@linkplain Name##empty_name empty name}
|
||||
* is returned.
|
||||
*
|
||||
* If it represents a {@linkplain ExecutableElement#getSimpleName
|
||||
* constructor}, the name "{@code <init>}" is returned. If it
|
||||
|
@ -25,6 +25,8 @@
|
||||
|
||||
package javax.lang.model.element;
|
||||
|
||||
import jdk.internal.javac.PreviewFeature;
|
||||
|
||||
import javax.lang.model.util.Elements;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
import javax.lang.model.type.TypeKind;
|
||||
@ -81,6 +83,9 @@ public interface VariableElement extends Element {
|
||||
* parameters of the same executable. If the original source
|
||||
* names are not available, an implementation may synthesize names
|
||||
* subject to the distinctness requirement above.
|
||||
*
|
||||
* <p>For variables, the name of each variable is returned, or an empty name
|
||||
* if the variable is unnamed.
|
||||
*/
|
||||
@Override
|
||||
Name getSimpleName();
|
||||
@ -93,4 +98,21 @@ public interface VariableElement extends Element {
|
||||
*/
|
||||
@Override
|
||||
Element getEnclosingElement();
|
||||
|
||||
/**
|
||||
* {@return {@code true} if this is an unnamed variable and {@code
|
||||
* false} otherwise}
|
||||
*
|
||||
* @implSpec
|
||||
* The default implementation of this method calls {@code
|
||||
* getSimpleName()} and returns {@code true} if the result is
|
||||
* empty and {@code false} otherwise.
|
||||
*
|
||||
* @jls 6.1 Declarations
|
||||
* @jls 14.4 Local Variable Declarations
|
||||
*
|
||||
* @since 21
|
||||
*/
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.UNNAMED, reflective = true)
|
||||
default boolean isUnnamed() { return getSimpleName().isEmpty(); }
|
||||
}
|
||||
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2023, 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package com.sun.source.tree;
|
||||
|
||||
import jdk.internal.javac.PreviewFeature;
|
||||
|
||||
/**
|
||||
* A tree node for a binding pattern that matches a pattern
|
||||
* with a variable of any name and a type of the match candidate;
|
||||
* an unnamed pattern.
|
||||
*
|
||||
* For example the use of underscore {@code _} below:
|
||||
* <pre>
|
||||
* if (r instanceof R(_)) {}
|
||||
* </pre>
|
||||
*
|
||||
* @jls 14.30.1 Kinds of Patterns
|
||||
*
|
||||
* @since 21
|
||||
*/
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.UNNAMED)
|
||||
public interface AnyPatternTree extends PatternTree {
|
||||
}
|
@ -227,6 +227,14 @@ public interface Tree {
|
||||
*/
|
||||
PARENTHESIZED(ParenthesizedTree.class),
|
||||
|
||||
/**
|
||||
* Used for instances of {@link BindingPatternTree}.
|
||||
*
|
||||
* @since 21
|
||||
*/
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.UNNAMED)
|
||||
ANY_PATTERN(AnyPatternTree.class),
|
||||
|
||||
/**
|
||||
* Used for instances of {@link BindingPatternTree}.
|
||||
*
|
||||
|
@ -268,6 +268,16 @@ public interface TreeVisitor<R,P> {
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES, reflective=true)
|
||||
R visitStringTemplate(StringTemplateTree node, P p);
|
||||
|
||||
/**
|
||||
* Visits a {@code AnyPatternTree} node.
|
||||
* @param node the node being visited
|
||||
* @param p a parameter value
|
||||
* @return a result value
|
||||
* @since 21
|
||||
*/
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.UNNAMED)
|
||||
R visitAnyPattern(AnyPatternTree node, P p);
|
||||
|
||||
/**
|
||||
* Visits a {@code BindingPatternTree} node.
|
||||
* @param node the node being visited
|
||||
|
@ -51,7 +51,8 @@ public interface VariableTree extends StatementTree {
|
||||
ModifiersTree getModifiers();
|
||||
|
||||
/**
|
||||
* Returns the name of the variable being declared.
|
||||
* Returns the name of the variable being declared or empty name if both the variable
|
||||
* is unnamed and the preview features are enabled (Unnamed Patterns and Variables).
|
||||
* @return the name
|
||||
*/
|
||||
Name getName();
|
||||
|
@ -641,6 +641,22 @@ public class SimpleTreeVisitor <R,P> implements TreeVisitor<R,P> {
|
||||
return defaultAction(node, p);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @implSpec This implementation calls {@code defaultAction}.
|
||||
*
|
||||
* @param node {@inheritDoc}
|
||||
* @param p {@inheritDoc}
|
||||
* @return the result of {@code defaultAction}
|
||||
* @since 21
|
||||
*/
|
||||
@Override
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.UNNAMED)
|
||||
public R visitAnyPattern(AnyPatternTree node, P p) {
|
||||
return defaultAction(node, p);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
|
@ -760,6 +760,21 @@ public class TreeScanner<R,P> implements TreeVisitor<R,P> {
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @implSpec This implementation returns {@code null}.
|
||||
*
|
||||
* @param node {@inheritDoc}
|
||||
* @param p {@inheritDoc}
|
||||
* @return the result of scanning
|
||||
* @since 21
|
||||
*/
|
||||
@Override
|
||||
public R visitAnyPattern(AnyPatternTree node, P p) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
|
@ -210,7 +210,7 @@ public class Preview {
|
||||
public boolean isPreview(Feature feature) {
|
||||
return switch (feature) {
|
||||
case STRING_TEMPLATES -> true;
|
||||
|
||||
case UNNAMED_VARIABLES -> true;
|
||||
//Note: this is a backdoor which allows to optionally treat all features as 'preview' (for testing).
|
||||
//When real preview features will be added, this method can be implemented to return 'true'
|
||||
//for those selected features, and 'false' for all the others.
|
||||
|
@ -239,6 +239,7 @@ public enum Source {
|
||||
RECORD_PATTERNS(JDK21, Fragments.FeatureDeconstructionPatterns, DiagKind.PLURAL),
|
||||
STRING_TEMPLATES(JDK21, Fragments.FeatureStringTemplates, DiagKind.PLURAL),
|
||||
WARN_ON_ILLEGAL_UTF8(MIN, JDK21),
|
||||
UNNAMED_VARIABLES(JDK21, Fragments.FeatureUnnamedVariables, DiagKind.PLURAL),
|
||||
;
|
||||
|
||||
enum DiagKind {
|
||||
|
@ -1641,6 +1641,7 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
|
||||
|
||||
/** A class for variable symbols
|
||||
*/
|
||||
@SuppressWarnings("preview")
|
||||
public static class VarSymbol extends Symbol implements VariableElement {
|
||||
|
||||
/** The variable's declaration position.
|
||||
@ -1783,6 +1784,10 @@ public abstract class Symbol extends AnnoConstruct implements PoolConstant, Elem
|
||||
public <R, P> R accept(Symbol.Visitor<R, P> v, P p) {
|
||||
return v.visitVarSymbol(this, p);
|
||||
}
|
||||
|
||||
public boolean isUnnamedVariable() {
|
||||
return name.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
public static class RecordComponent extends VarSymbol implements RecordComponentElement {
|
||||
|
@ -1688,7 +1688,7 @@ public class Attr extends JCTree.Visitor {
|
||||
wasError = true;
|
||||
}
|
||||
MatchBindings currentBindings = null;
|
||||
boolean wasUnconditionalPattern = hasUnconditionalPattern;
|
||||
MatchBindings guardBindings = null;
|
||||
for (List<JCCaseLabel> labels = c.labels; labels.nonEmpty(); labels = labels.tail) {
|
||||
JCCaseLabel label = labels.head;
|
||||
if (label instanceof JCConstantCaseLabel constLabel) {
|
||||
@ -1761,7 +1761,7 @@ public class Attr extends JCTree.Visitor {
|
||||
checkCastablePattern(pat.pos(), seltype, primaryType);
|
||||
Type patternType = types.erasure(primaryType);
|
||||
JCExpression guard = c.guard;
|
||||
if (labels.tail.isEmpty() && guard != null) {
|
||||
if (guardBindings == null && guard != null) {
|
||||
MatchBindings afterPattern = matchBindings;
|
||||
Env<AttrContext> bodyEnv = bindingEnv(switchEnv, matchBindings.bindingsWhenTrue);
|
||||
try {
|
||||
@ -1769,7 +1769,9 @@ public class Attr extends JCTree.Visitor {
|
||||
} finally {
|
||||
bodyEnv.info.scope.leave();
|
||||
}
|
||||
matchBindings = matchBindingsComputer.caseGuard(c, afterPattern, matchBindings);
|
||||
|
||||
guardBindings = matchBindings;
|
||||
matchBindings = afterPattern;
|
||||
|
||||
if (TreeInfo.isBooleanWithValue(guard, 0)) {
|
||||
log.error(guard.pos(), Errors.GuardHasConstantExpressionFalse);
|
||||
@ -1796,6 +1798,10 @@ public class Attr extends JCTree.Visitor {
|
||||
currentBindings = matchBindingsComputer.switchCase(label, currentBindings, matchBindings);
|
||||
}
|
||||
|
||||
if (guardBindings != null) {
|
||||
currentBindings = matchBindingsComputer.caseGuard(c, currentBindings, guardBindings);
|
||||
}
|
||||
|
||||
Env<AttrContext> caseEnv =
|
||||
bindingEnv(switchEnv, c, currentBindings.bindingsWhenTrue);
|
||||
try {
|
||||
@ -4145,6 +4151,11 @@ public class Attr extends JCTree.Visitor {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAnyPattern(JCAnyPattern tree) {
|
||||
result = tree.type = resultInfo.pt;
|
||||
}
|
||||
|
||||
public void visitBindingPattern(JCBindingPattern tree) {
|
||||
Type type;
|
||||
if (tree.var.vartype != null) {
|
||||
@ -4166,7 +4177,11 @@ public class Attr extends JCTree.Visitor {
|
||||
}
|
||||
chk.validate(tree.var.vartype, env, true);
|
||||
result = tree.type;
|
||||
matchBindings = new MatchBindings(List.of(v), List.nil());
|
||||
if (v.isUnnamedVariable()) {
|
||||
matchBindings = MatchBindingsComputer.EMPTY;
|
||||
} else {
|
||||
matchBindings = new MatchBindings(List.of(v), List.nil());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -4572,8 +4572,11 @@ public class Check {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (c.labels.tail.nonEmpty()) {
|
||||
} else if (c.labels.tail.nonEmpty()) {
|
||||
var patterCaseLabels = c.labels.stream().filter(ll -> ll instanceof JCPatternCaseLabel).map(cl -> (JCPatternCaseLabel)cl);
|
||||
var allUnderscore = patterCaseLabels.allMatch(pcl -> !hasBindings(pcl.getPattern()));
|
||||
|
||||
if (!allUnderscore) {
|
||||
log.error(c.labels.tail.head.pos(), Errors.FlowsThroughFromPattern);
|
||||
}
|
||||
}
|
||||
@ -4608,7 +4611,7 @@ public class Check {
|
||||
new TreeScanner() {
|
||||
@Override
|
||||
public void visitBindingPattern(JCBindingPattern tree) {
|
||||
bindings[0] = true;
|
||||
bindings[0] = !tree.var.sym.isUnnamedVariable();
|
||||
super.visitBindingPattern(tree);
|
||||
}
|
||||
}.scan(p);
|
||||
|
@ -742,87 +742,6 @@ public class Flow {
|
||||
alive = alive.or(resolveYields(tree, prevPendingExits));
|
||||
}
|
||||
|
||||
sealed interface PatternDescription {
|
||||
public static PatternDescription from(Types types, Type selectorType, JCPattern pattern) {
|
||||
if (pattern instanceof JCBindingPattern binding) {
|
||||
Type type = types.isSubtype(selectorType, binding.type)
|
||||
? selectorType : binding.type;
|
||||
return new BindingPattern(type);
|
||||
} else if (pattern instanceof JCRecordPattern record) {
|
||||
Type[] componentTypes = ((ClassSymbol) record.type.tsym).getRecordComponents()
|
||||
.map(r -> types.memberType(record.type, r))
|
||||
.toArray(s -> new Type[s]);
|
||||
PatternDescription[] nestedDescriptions =
|
||||
new PatternDescription[record.nested.size()];
|
||||
int i = 0;
|
||||
for (List<JCPattern> it = record.nested;
|
||||
it.nonEmpty();
|
||||
it = it.tail, i++) {
|
||||
nestedDescriptions[i] = PatternDescription.from(types, componentTypes[i], it.head);
|
||||
}
|
||||
return new RecordPattern(record.type, componentTypes, nestedDescriptions);
|
||||
} else {
|
||||
throw Assert.error();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
record BindingPattern(Type type) implements PatternDescription {
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return type.tsym.hashCode();
|
||||
}
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof BindingPattern other &&
|
||||
type.tsym == other.type.tsym;
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return type.tsym + " _";
|
||||
}
|
||||
}
|
||||
|
||||
record RecordPattern(Type recordType, int _hashCode, Type[] fullComponentTypes, PatternDescription... nested) implements PatternDescription {
|
||||
|
||||
public RecordPattern(Type recordType, Type[] fullComponentTypes, PatternDescription[] nested) {
|
||||
this(recordType, hashCode(-1, recordType, nested), fullComponentTypes, nested);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return _hashCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof RecordPattern other &&
|
||||
recordType.tsym == other.recordType.tsym &&
|
||||
Arrays.equals(nested, other.nested);
|
||||
}
|
||||
|
||||
public int hashCode(int excludeComponent) {
|
||||
return hashCode(excludeComponent, recordType, nested);
|
||||
}
|
||||
|
||||
public static int hashCode(int excludeComponent, Type recordType, PatternDescription... nested) {
|
||||
int hash = 5;
|
||||
hash = 41 * hash + recordType.tsym.hashCode();
|
||||
for (int i = 0; i < nested.length; i++) {
|
||||
if (i != excludeComponent) {
|
||||
hash = 41 * hash + nested[i].hashCode();
|
||||
}
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return recordType.tsym + "(" + Arrays.stream(nested)
|
||||
.map(pd -> pd.toString())
|
||||
.collect(Collectors.joining(", ")) + ")";
|
||||
}
|
||||
}
|
||||
|
||||
private boolean exhausts(JCExpression selector, List<JCCase> cases) {
|
||||
Set<PatternDescription> patternSet = new HashSet<>();
|
||||
Map<Symbol, Set<Symbol>> enum2Constants = new HashMap<>();
|
||||
@ -833,7 +752,7 @@ public class Flow {
|
||||
for (var l : c.labels) {
|
||||
if (l instanceof JCPatternCaseLabel patternLabel) {
|
||||
for (Type component : components(selector.type)) {
|
||||
patternSet.add(PatternDescription.from(types, component, patternLabel.pat));
|
||||
patternSet.add(makePatternDescription(component, patternLabel.pat));
|
||||
}
|
||||
} else if (l instanceof JCConstantCaseLabel constantLabel) {
|
||||
Symbol s = TreeInfo.symbol(constantLabel.expr);
|
||||
@ -2905,7 +2824,7 @@ public class Flow {
|
||||
if (!resourceVarDecls.isEmpty() &&
|
||||
lint.isEnabled(Lint.LintCategory.TRY)) {
|
||||
for (JCVariableDecl resVar : resourceVarDecls) {
|
||||
if (unrefdResources.includes(resVar.sym)) {
|
||||
if (unrefdResources.includes(resVar.sym) && !resVar.sym.isUnnamedVariable()) {
|
||||
log.warning(Lint.LintCategory.TRY, resVar.pos(),
|
||||
Warnings.TryResourceNotReferenced(resVar.sym));
|
||||
unrefdResources.remove(resVar.sym);
|
||||
@ -3554,4 +3473,85 @@ public class Flow {
|
||||
}
|
||||
}
|
||||
|
||||
sealed interface PatternDescription { }
|
||||
public PatternDescription makePatternDescription(Type selectorType, JCPattern pattern) {
|
||||
if (pattern instanceof JCBindingPattern binding) {
|
||||
Type type = types.isSubtype(selectorType, binding.type)
|
||||
? selectorType : binding.type;
|
||||
return new BindingPattern(type);
|
||||
} else if (pattern instanceof JCRecordPattern record) {
|
||||
Type[] componentTypes = ((ClassSymbol) record.type.tsym).getRecordComponents()
|
||||
.map(r -> types.memberType(record.type, r))
|
||||
.toArray(s -> new Type[s]);
|
||||
PatternDescription[] nestedDescriptions =
|
||||
new PatternDescription[record.nested.size()];
|
||||
int i = 0;
|
||||
for (List<JCPattern> it = record.nested;
|
||||
it.nonEmpty();
|
||||
it = it.tail, i++) {
|
||||
nestedDescriptions[i] = makePatternDescription(types.erasure(componentTypes[i]), it.head);
|
||||
}
|
||||
return new RecordPattern(record.type, componentTypes, nestedDescriptions);
|
||||
} else if (pattern instanceof JCAnyPattern) {
|
||||
Type type = types.isSubtype(selectorType, syms.objectType)
|
||||
? selectorType : syms.objectType;
|
||||
return new BindingPattern(type);
|
||||
} else {
|
||||
throw Assert.error();
|
||||
}
|
||||
}
|
||||
record BindingPattern(Type type) implements PatternDescription {
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return type.tsym.hashCode();
|
||||
}
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof BindingPattern other &&
|
||||
type.tsym == other.type.tsym;
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return type.tsym + " _";
|
||||
}
|
||||
}
|
||||
record RecordPattern(Type recordType, int _hashCode, Type[] fullComponentTypes, PatternDescription... nested) implements PatternDescription {
|
||||
|
||||
public RecordPattern(Type recordType, Type[] fullComponentTypes, PatternDescription[] nested) {
|
||||
this(recordType, hashCode(-1, recordType, nested), fullComponentTypes, nested);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return _hashCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof RecordPattern other &&
|
||||
recordType.tsym == other.recordType.tsym &&
|
||||
Arrays.equals(nested, other.nested);
|
||||
}
|
||||
|
||||
public int hashCode(int excludeComponent) {
|
||||
return hashCode(excludeComponent, recordType, nested);
|
||||
}
|
||||
|
||||
public static int hashCode(int excludeComponent, Type recordType, PatternDescription... nested) {
|
||||
int hash = 5;
|
||||
hash = 41 * hash + recordType.tsym.hashCode();
|
||||
for (int i = 0; i < nested.length; i++) {
|
||||
if (i != excludeComponent) {
|
||||
hash = 41 * hash + nested[i].hashCode();
|
||||
}
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return recordType.tsym + "(" + Arrays.stream(nested)
|
||||
.map(pd -> pd.toString())
|
||||
.collect(Collectors.joining(", ")) + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ import com.sun.tools.javac.tree.*;
|
||||
import com.sun.tools.javac.util.*;
|
||||
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
|
||||
import com.sun.tools.javac.util.JCDiagnostic.Error;
|
||||
import com.sun.tools.javac.code.Source.Feature;
|
||||
|
||||
import com.sun.tools.javac.code.Symbol.*;
|
||||
import com.sun.tools.javac.code.Type.*;
|
||||
@ -55,6 +56,8 @@ import static com.sun.tools.javac.code.TypeTag.TYPEVAR;
|
||||
public class MemberEnter extends JCTree.Visitor {
|
||||
protected static final Context.Key<MemberEnter> memberEnterKey = new Context.Key<>();
|
||||
|
||||
/** The Source language setting. */
|
||||
private final Source source;
|
||||
private final Enter enter;
|
||||
private final Log log;
|
||||
private final Check chk;
|
||||
@ -62,6 +65,7 @@ public class MemberEnter extends JCTree.Visitor {
|
||||
private final Symtab syms;
|
||||
private final Annotate annotate;
|
||||
private final Types types;
|
||||
private final Names names;
|
||||
private final DeferredLintHandler deferredLintHandler;
|
||||
|
||||
public static MemberEnter instance(Context context) {
|
||||
@ -81,6 +85,8 @@ public class MemberEnter extends JCTree.Visitor {
|
||||
syms = Symtab.instance(context);
|
||||
annotate = Annotate.instance(context);
|
||||
types = Types.instance(context);
|
||||
source = Source.instance(context);
|
||||
names = Names.instance(context);
|
||||
deferredLintHandler = DeferredLintHandler.instance(context);
|
||||
}
|
||||
|
||||
@ -285,7 +291,8 @@ public class MemberEnter extends JCTree.Visitor {
|
||||
Type vartype = tree.isImplicitlyTyped()
|
||||
? env.info.scope.owner.kind == MTH ? Type.noType : syms.errType
|
||||
: tree.vartype.type;
|
||||
VarSymbol v = new VarSymbol(0, tree.name, vartype, enclScope.owner);
|
||||
Name name = tree.name;
|
||||
VarSymbol v = new VarSymbol(0, name, vartype, enclScope.owner);
|
||||
v.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, v, tree);
|
||||
tree.sym = v;
|
||||
if (tree.init != null) {
|
||||
@ -297,12 +304,15 @@ public class MemberEnter extends JCTree.Visitor {
|
||||
v.setLazyConstValue(initEnv(tree, initEnv), attr, tree);
|
||||
}
|
||||
}
|
||||
if (chk.checkUnique(tree.pos(), v, enclScope)) {
|
||||
chk.checkTransparentVar(tree.pos(), v, enclScope);
|
||||
enclScope.enter(v);
|
||||
} else if (v.owner.kind == MTH || (v.flags_field & (Flags.PRIVATE | Flags.FINAL | Flags.GENERATED_MEMBER | Flags.RECORD)) != 0) {
|
||||
// if this is a parameter or a field obtained from a record component, enter it
|
||||
enclScope.enter(v);
|
||||
|
||||
if(!(Feature.UNNAMED_VARIABLES.allowedInSource(source) && tree.sym.isUnnamedVariable())) {
|
||||
if (chk.checkUnique(tree.pos(), v, enclScope)) {
|
||||
chk.checkTransparentVar(tree.pos(), v, enclScope);
|
||||
enclScope.enter(v);
|
||||
} else if (v.owner.kind == MTH || (v.flags_field & (Flags.PRIVATE | Flags.FINAL | Flags.GENERATED_MEMBER | Flags.RECORD)) != 0) {
|
||||
// if this is a parameter or a field obtained from a record component, enter it
|
||||
enclScope.enter(v);
|
||||
}
|
||||
}
|
||||
|
||||
annotate.annotateLater(tree.mods.annotations, localEnv, v, tree.pos());
|
||||
|
@ -45,6 +45,7 @@ import com.sun.tools.javac.code.Type.MethodType;
|
||||
import com.sun.tools.javac.code.Type.WildcardType;
|
||||
import com.sun.tools.javac.code.Types;
|
||||
import com.sun.tools.javac.tree.JCTree.JCAssign;
|
||||
import com.sun.tools.javac.tree.JCTree.JCAnyPattern;
|
||||
import com.sun.tools.javac.tree.JCTree.JCBinary;
|
||||
import com.sun.tools.javac.tree.JCTree.JCConditional;
|
||||
import com.sun.tools.javac.tree.JCTree.JCExpression;
|
||||
@ -261,6 +262,11 @@ public class TransPatterns extends TreeTranslator {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAnyPattern(JCTree.JCAnyPattern that) {
|
||||
result = make.Literal(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitBindingPattern(JCBindingPattern tree) {
|
||||
//it is assumed the primary type has already been checked:
|
||||
@ -268,7 +274,7 @@ public class TransPatterns extends TreeTranslator {
|
||||
Type castTargetType = types.erasure(TreeInfo.primaryPatternType(tree));
|
||||
VarSymbol bindingVar = bindingContext.bindingDeclared(binding);
|
||||
|
||||
if (bindingVar != null) {
|
||||
if (bindingVar != null && !bindingVar.isUnnamedVariable()) {
|
||||
JCAssign fakeInit = (JCAssign)make.at(TreeInfo.getStartPos(tree)).Assign(
|
||||
make.Ident(bindingVar), convert(make.Ident(currentValue), castTargetType)).setType(bindingVar.erasure(types));
|
||||
LetExpr nestedLE = make.LetExpr(List.of(make.Exec(fakeInit)),
|
||||
@ -311,7 +317,7 @@ public class TransPatterns extends TreeTranslator {
|
||||
RecordComponent component = components.head;
|
||||
Type componentType = types.erasure(nestedFullComponentTypes.head);
|
||||
JCPattern nestedPattern = nestedPatterns.head;
|
||||
JCBindingPattern nestedBinding;
|
||||
JCPattern nestedBinding;
|
||||
boolean allowNull;
|
||||
if (nestedPattern instanceof JCRecordPattern nestedRecordPattern) {
|
||||
UnrolledRecordPattern nestedDesugared = unrollRecordPattern(nestedRecordPattern);
|
||||
@ -325,7 +331,11 @@ public class TransPatterns extends TreeTranslator {
|
||||
}
|
||||
nestedBinding = nestedDesugared.primaryPattern();
|
||||
allowNull = false;
|
||||
} else {
|
||||
} else if (nestedPattern instanceof JCAnyPattern nestedAnyPattern) {
|
||||
allowNull = true;
|
||||
nestedBinding = nestedAnyPattern;
|
||||
}
|
||||
else {
|
||||
nestedBinding = (JCBindingPattern) nestedPattern;
|
||||
allowNull = types.isSubtype(componentType,
|
||||
types.boxedTypeOrType(types.erasure(nestedBinding.type)));
|
||||
@ -437,12 +447,11 @@ public class TransPatterns extends TreeTranslator {
|
||||
if (pattern instanceof JCRecordPattern recordPattern) {
|
||||
UnrolledRecordPattern deconstructed = unrollRecordPattern(recordPattern);
|
||||
JCExpression guard = deconstructed.newGuard();
|
||||
if (cse.guard != null) {
|
||||
cse.guard = mergeConditions(guard, cse.guard);
|
||||
} else {
|
||||
cse.guard = guard;
|
||||
}
|
||||
return make.PatternCaseLabel(deconstructed.primaryPattern());
|
||||
|
||||
JCPatternCaseLabel newPatternCaseLabel = make.PatternCaseLabel(deconstructed.primaryPattern());
|
||||
newPatternCaseLabel.syntheticGuard = guard;
|
||||
|
||||
return newPatternCaseLabel;
|
||||
}
|
||||
}
|
||||
return l;
|
||||
@ -524,23 +533,61 @@ public class TransPatterns extends TreeTranslator {
|
||||
.filter(l -> !TreeInfo.isNullCaseLabel(l))
|
||||
.collect(List.collector());
|
||||
}
|
||||
if (clearedPatterns.size() == 1 && clearedPatterns.head.hasTag(Tag.PATTERNCASELABEL) && !previousCompletesNormally) {
|
||||
JCPatternCaseLabel label = (JCPatternCaseLabel) clearedPatterns.head;
|
||||
|
||||
boolean validCaseLabelList;
|
||||
if (clearedPatterns.size() > 1) {
|
||||
validCaseLabelList = clearedPatterns.stream().allMatch(cP -> cP.hasTag(Tag.PATTERNCASELABEL));
|
||||
} else {
|
||||
validCaseLabelList = clearedPatterns.head.hasTag(Tag.PATTERNCASELABEL);
|
||||
}
|
||||
|
||||
if (validCaseLabelList && !previousCompletesNormally) {
|
||||
List<JCPatternCaseLabel> labels = clearedPatterns.stream().map(cp -> (JCPatternCaseLabel)cp).collect(List.collector());
|
||||
bindingContext = new BasicBindingContext();
|
||||
VarSymbol prevCurrentValue = currentValue;
|
||||
try {
|
||||
currentValue = temp;
|
||||
JCExpression test = (JCExpression) this.<JCTree>translate(label.pat);
|
||||
if (c.guard != null) {
|
||||
JCExpression guard = translate(c.guard);
|
||||
test = makeBinary(Tag.AND, test, guard);
|
||||
JCExpression test = null;
|
||||
JCExpression accTest = null;
|
||||
boolean first = true;
|
||||
|
||||
// if all patterns are the same we do not need an extra test for the first (it is covered by the BSM)
|
||||
boolean multiplePatternsAndDifferent = labels.size() > 1 &&
|
||||
!labels.stream().map(l -> l.pat.type.tsym).allMatch(labels.get(0).pat.type.tsym::equals);
|
||||
|
||||
for (JCPatternCaseLabel label: labels) {
|
||||
test = (JCExpression) this.<JCTree>translate(label.pat);
|
||||
|
||||
if (multiplePatternsAndDifferent) {
|
||||
test = makeBinary(Tag.AND, makeTypeTest(make.Ident(temp), make.Type(label.pat.type)), test);
|
||||
}
|
||||
|
||||
if (label.syntheticGuard != null) {
|
||||
JCExpression guard = translate(label.syntheticGuard);
|
||||
test = makeBinary(Tag.AND, test, guard);
|
||||
}
|
||||
|
||||
if (!first) {
|
||||
accTest = makeBinary(Tag.OR, accTest, test);
|
||||
} else {
|
||||
accTest = test;
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (c.guard != null) {
|
||||
test = makeBinary(Tag.AND, accTest, translate(c.guard));
|
||||
c.guard = null;
|
||||
} else {
|
||||
test = accTest;
|
||||
}
|
||||
|
||||
c.stats = translate(c.stats);
|
||||
JCContinue continueSwitch = make.at(clearedPatterns.head.pos()).Continue(null);
|
||||
continueSwitch.target = tree;
|
||||
c.stats = c.stats.prepend(make.If(makeUnary(Tag.NOT, test).setType(syms.booleanType),
|
||||
make.Block(0, List.of(make.Exec(make.Assign(make.Ident(index),
|
||||
makeLit(syms.intType, i + 1))
|
||||
makeLit(syms.intType, i + labels.length()))
|
||||
.setType(syms.intType)),
|
||||
continueSwitch)),
|
||||
null));
|
||||
@ -556,16 +603,20 @@ public class TransPatterns extends TreeTranslator {
|
||||
fixupContinue(tree, c, index, i);
|
||||
|
||||
ListBuffer<JCCaseLabel> translatedLabels = new ListBuffer<>();
|
||||
for (var p : c.labels) {
|
||||
List<JCCaseLabel> labels = c.labels;
|
||||
boolean defaultAdded = false;
|
||||
for (int j = 0; j < labels.size() && !defaultAdded; j++) {
|
||||
var p = labels.get(j);
|
||||
if (p.hasTag(Tag.DEFAULTCASELABEL)) {
|
||||
translatedLabels.add(p);
|
||||
hasDefault = true;
|
||||
} else if (hasUnconditionalPattern && !hasDefault &&
|
||||
c == lastCase && p.hasTag(Tag.PATTERNCASELABEL)) {
|
||||
c == lastCase && p.hasTag(Tag.PATTERNCASELABEL)) {
|
||||
//If the switch has unconditional pattern,
|
||||
//the last case will contain it.
|
||||
//Convert the unconditional pattern to default:
|
||||
translatedLabels.add(make.DefaultCaseLabel());
|
||||
defaultAdded = true;
|
||||
} else {
|
||||
int value;
|
||||
if (TreeInfo.isNullCaseLabel(p)) {
|
||||
@ -698,7 +749,7 @@ public class TransPatterns extends TreeTranslator {
|
||||
"commonNestedExpression: " + commonNestedExpression +
|
||||
"commonNestedBinding: " + commonNestedBinding);
|
||||
ListBuffer<JCCase> nestedCases = new ListBuffer<>();
|
||||
JCExpression lastGuard = null;
|
||||
boolean hasGuard = false;
|
||||
|
||||
for(List<JCCase> accList = accummulator.toList(); accList.nonEmpty(); accList = accList.tail) {
|
||||
var accummulated = accList.head;
|
||||
@ -713,29 +764,33 @@ public class TransPatterns extends TreeTranslator {
|
||||
replaceNested.scan(accummulated);
|
||||
JCExpression newGuard;
|
||||
JCInstanceOf instanceofCheck;
|
||||
if (accummulated.guard instanceof JCBinary binOp) {
|
||||
if (accummulatedFirstLabel.syntheticGuard instanceof JCBinary binOp) {
|
||||
newGuard = binOp.rhs;
|
||||
instanceofCheck = (JCInstanceOf) binOp.lhs;
|
||||
} else {
|
||||
newGuard = null;
|
||||
instanceofCheck = (JCInstanceOf) accummulated.guard;
|
||||
instanceofCheck = (JCInstanceOf) accummulatedFirstLabel.syntheticGuard;
|
||||
}
|
||||
JCBindingPattern binding = (JCBindingPattern) instanceofCheck.pattern;
|
||||
hasUnconditional =
|
||||
instanceofCheck.allowNull &&
|
||||
accList.tail.isEmpty();
|
||||
List<JCCaseLabel> newLabel;
|
||||
|
||||
JCPatternCaseLabel jcPatternCaseLabelWithGuard = make.PatternCaseLabel(binding);
|
||||
jcPatternCaseLabelWithGuard.syntheticGuard = newGuard;
|
||||
|
||||
if (hasUnconditional) {
|
||||
newLabel = List.of(make.ConstantCaseLabel(makeNull()),
|
||||
make.PatternCaseLabel(binding));
|
||||
jcPatternCaseLabelWithGuard);
|
||||
} else {
|
||||
newLabel = List.of(make.PatternCaseLabel(binding));
|
||||
newLabel = List.of(jcPatternCaseLabelWithGuard);
|
||||
}
|
||||
nestedCases.add(make.Case(CaseKind.STATEMENT, newLabel, newGuard,
|
||||
nestedCases.add(make.Case(CaseKind.STATEMENT, newLabel, accummulated.guard,
|
||||
accummulated.stats, null));
|
||||
lastGuard = newGuard;
|
||||
hasGuard = newGuard != null || accummulated.guard != null;
|
||||
}
|
||||
if (lastGuard != null || !hasUnconditional) {
|
||||
if (hasGuard || !hasUnconditional) {
|
||||
JCContinue continueSwitch = make.Continue(null);
|
||||
continueSwitch.target = currentSwitch;
|
||||
nestedCases.add(make.Case(CaseKind.STATEMENT,
|
||||
@ -751,6 +806,7 @@ public class TransPatterns extends TreeTranslator {
|
||||
newSwitch.patternSwitch = true;
|
||||
JCPatternCaseLabel leadingTest =
|
||||
(JCPatternCaseLabel) accummulator.first().labels.head;
|
||||
leadingTest.syntheticGuard = null;
|
||||
result.add(make.Case(CaseKind.STATEMENT,
|
||||
List.of(leadingTest),
|
||||
null,
|
||||
@ -775,14 +831,14 @@ public class TransPatterns extends TreeTranslator {
|
||||
|
||||
if (c.head.labels.size() == 1 &&
|
||||
c.head.labels.head instanceof JCPatternCaseLabel patternLabel) {
|
||||
if (c.head.guard instanceof JCBinary binOp &&
|
||||
if (patternLabel.syntheticGuard instanceof JCBinary binOp &&
|
||||
binOp.lhs instanceof JCInstanceOf instanceofCheck &&
|
||||
instanceofCheck.pattern instanceof JCBindingPattern binding) {
|
||||
currentBinding = ((JCBindingPattern) patternLabel.pat).var.sym;
|
||||
currentNullable = instanceofCheck.allowNull;
|
||||
currentNestedExpression = instanceofCheck.expr;
|
||||
currentNestedBinding = binding.var.sym;
|
||||
} else if (c.head.guard instanceof JCInstanceOf instanceofCheck &&
|
||||
} else if (patternLabel.syntheticGuard instanceof JCInstanceOf instanceofCheck &&
|
||||
instanceofCheck.pattern instanceof JCBindingPattern binding) {
|
||||
currentBinding = ((JCBindingPattern) patternLabel.pat).var.sym;
|
||||
currentNullable = instanceofCheck.allowNull;
|
||||
@ -1373,5 +1429,11 @@ public class TransPatterns extends TreeTranslator {
|
||||
tree.sym = fromTo.getOrDefault(tree.sym, tree.sym);
|
||||
super.visitIdent(tree);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPatternCaseLabel(JCPatternCaseLabel tree) {
|
||||
super.visitPatternCaseLabel(tree);
|
||||
scan(tree.syntheticGuard);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -556,6 +556,11 @@ public class TransTypes extends TreeTranslator {
|
||||
result = tree;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAnyPattern(JCAnyPattern tree) {
|
||||
result = tree;
|
||||
}
|
||||
|
||||
public void visitBindingPattern(JCBindingPattern tree) {
|
||||
tree.var = translate(tree.var, null);
|
||||
result = tree;
|
||||
|
@ -62,7 +62,6 @@ import static com.sun.tools.javac.resources.CompilerProperties.Fragments.Implici
|
||||
import static com.sun.tools.javac.resources.CompilerProperties.Fragments.VarAndExplicitNotAllowed;
|
||||
import static com.sun.tools.javac.resources.CompilerProperties.Fragments.VarAndImplicitNotAllowed;
|
||||
import com.sun.tools.javac.util.JCDiagnostic.SimpleDiagnosticPosition;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
/**
|
||||
* The parser maps a token sequence into an abstract syntax tree.
|
||||
@ -590,6 +589,14 @@ public class JavacParser implements Parser {
|
||||
}
|
||||
|
||||
protected Name ident(boolean allowClass) {
|
||||
return ident(allowClass, false);
|
||||
}
|
||||
|
||||
public Name identOrUnderscore() {
|
||||
return ident(false, true);
|
||||
}
|
||||
|
||||
protected Name ident(boolean allowClass, boolean asVariable) {
|
||||
if (token.kind == IDENTIFIER) {
|
||||
Name name = token.name();
|
||||
nextToken();
|
||||
@ -615,8 +622,14 @@ public class JavacParser implements Parser {
|
||||
} else if (token.kind == UNDERSCORE) {
|
||||
if (Feature.UNDERSCORE_IDENTIFIER.allowedInSource(source)) {
|
||||
log.warning(token.pos, Warnings.UnderscoreAsIdentifier);
|
||||
} else if (asVariable) {
|
||||
checkSourceLevel(Feature.UNNAMED_VARIABLES);
|
||||
} else {
|
||||
log.error(DiagnosticFlag.SYNTAX, token.pos, Errors.UnderscoreAsIdentifier);
|
||||
if (preview.isEnabled() && Feature.UNNAMED_VARIABLES.allowedInSource(source)) {
|
||||
log.error(DiagnosticFlag.SYNTAX, token.pos, Errors.UseOfUnderscoreNotAllowed);
|
||||
} else {
|
||||
log.error(DiagnosticFlag.SYNTAX, token.pos, Errors.UnderscoreAsIdentifier);
|
||||
}
|
||||
}
|
||||
Name name = token.name();
|
||||
nextToken();
|
||||
@ -830,57 +843,65 @@ public class JavacParser implements Parser {
|
||||
|
||||
/** parses patterns.
|
||||
*/
|
||||
|
||||
public JCPattern parsePattern(int pos, JCModifiers mods, JCExpression parsedType,
|
||||
boolean allowVar, boolean checkGuard) {
|
||||
JCPattern pattern;
|
||||
mods = mods != null ? mods : optFinal(0);
|
||||
JCExpression e;
|
||||
if (parsedType == null) {
|
||||
boolean var = token.kind == IDENTIFIER && token.name() == names.var;
|
||||
e = unannotatedType(allowVar, TYPE | NOLAMBDA);
|
||||
if (var) {
|
||||
e = null;
|
||||
}
|
||||
} else {
|
||||
e = parsedType;
|
||||
if (token.kind == UNDERSCORE && parsedType == null) {
|
||||
nextToken();
|
||||
pattern = toP(F.at(token.pos).AnyPattern());
|
||||
}
|
||||
if (token.kind == LPAREN) {
|
||||
//deconstruction pattern:
|
||||
checkSourceLevel(Feature.RECORD_PATTERNS);
|
||||
ListBuffer<JCPattern> nested = new ListBuffer<>();
|
||||
if (!peekToken(RPAREN)) {
|
||||
do {
|
||||
nextToken();
|
||||
JCPattern nestedPattern = parsePattern(token.pos, null, null, true, false);
|
||||
nested.append(nestedPattern);
|
||||
} while (token.kind == COMMA);
|
||||
} else {
|
||||
nextToken();
|
||||
}
|
||||
accept(RPAREN);
|
||||
pattern = toP(F.at(pos).RecordPattern(e, nested.toList()));
|
||||
if (mods.annotations.nonEmpty()) {
|
||||
log.error(mods.annotations.head.pos(), Errors.RecordPatternsAnnotationsNotAllowed);
|
||||
}
|
||||
new TreeScanner() {
|
||||
@Override
|
||||
public void visitAnnotatedType(JCAnnotatedType tree) {
|
||||
log.error(tree.pos(), Errors.RecordPatternsAnnotationsNotAllowed);
|
||||
else {
|
||||
if (parsedType == null) {
|
||||
boolean var = token.kind == IDENTIFIER && token.name() == names.var;
|
||||
e = unannotatedType(allowVar, TYPE | NOLAMBDA);
|
||||
if (var) {
|
||||
e = null;
|
||||
}
|
||||
}.scan(e);
|
||||
} else {
|
||||
//type test pattern:
|
||||
JCVariableDecl var = toP(F.at(token.pos).VarDef(mods, ident(), e, null));
|
||||
if (e == null) {
|
||||
var.startPos = pos;
|
||||
} else {
|
||||
e = parsedType;
|
||||
}
|
||||
if (token.kind == LPAREN) {
|
||||
//deconstruction pattern:
|
||||
checkSourceLevel(Feature.RECORD_PATTERNS);
|
||||
ListBuffer<JCPattern> nested = new ListBuffer<>();
|
||||
if (!peekToken(RPAREN)) {
|
||||
do {
|
||||
nextToken();
|
||||
JCPattern nestedPattern = parsePattern(token.pos, null, null, true, false);
|
||||
nested.append(nestedPattern);
|
||||
} while (token.kind == COMMA);
|
||||
} else {
|
||||
nextToken();
|
||||
}
|
||||
accept(RPAREN);
|
||||
pattern = toP(F.at(pos).RecordPattern(e, nested.toList()));
|
||||
if (mods.annotations.nonEmpty()) {
|
||||
log.error(mods.annotations.head.pos(), Errors.RecordPatternsAnnotationsNotAllowed);
|
||||
}
|
||||
new TreeScanner() {
|
||||
@Override
|
||||
public void visitAnnotatedType(JCAnnotatedType tree) {
|
||||
log.error(tree.pos(), Errors.RecordPatternsAnnotationsNotAllowed);
|
||||
}
|
||||
}.scan(e);
|
||||
} else {
|
||||
//type test pattern:
|
||||
int varPos = token.pos;
|
||||
JCVariableDecl var = variableDeclaratorRest(varPos, mods, e, identOrUnderscore(), false, null, false, false, true);
|
||||
if (e == null) {
|
||||
var.startPos = pos;
|
||||
if (var.name == names.underscore && !allowVar) {
|
||||
log.error(DiagnosticFlag.SYNTAX, varPos, Errors.UseOfUnderscoreNotAllowed);
|
||||
}
|
||||
}
|
||||
pattern = toP(F.at(pos).BindingPattern(var));
|
||||
}
|
||||
pattern = toP(F.at(pos).BindingPattern(var));
|
||||
}
|
||||
return pattern;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* parses (optional) type annotations followed by a type. If the
|
||||
* annotations are present before the type and are not consumed during array
|
||||
@ -1077,6 +1098,9 @@ public class JavacParser implements Parser {
|
||||
pattern = parsePattern(patternPos, mods, type, false, false);
|
||||
} else if (token.kind == LPAREN) {
|
||||
pattern = parsePattern(patternPos, mods, type, false, false);
|
||||
} else if (token.kind == UNDERSCORE) {
|
||||
checkSourceLevel(token.pos, Feature.UNNAMED_VARIABLES);
|
||||
pattern = parsePattern(patternPos, mods, type, false, false);
|
||||
} else {
|
||||
checkNoMods(typePos, mods.flags & ~Flags.DEPRECATED);
|
||||
if (mods.annotations.nonEmpty()) {
|
||||
@ -2052,23 +2076,31 @@ public class JavacParser implements Parser {
|
||||
};
|
||||
|
||||
class LambdaClassifier {
|
||||
|
||||
LambdaParameterKind kind;
|
||||
Fragment diagFragment;
|
||||
List<JCVariableDecl> params;
|
||||
|
||||
/**
|
||||
* analyzeParens() has already classified the lambda as EXPLICIT_LAMBDA, due to
|
||||
* two consecutive identifiers. Because of that {@code (<explicit lambda>)}, the
|
||||
* parser will always attempt to parse a type, followed by a name. If the lambda
|
||||
* contains an illegal mix of implicit and explicit parameters, it is possible
|
||||
* for the parser to see a {@code ,} when expecting a name, in which case the
|
||||
* variable is created with an erroneous name. The logic below makes sure that
|
||||
* the lambda parameters are all declared with either an explicit type (e.g.
|
||||
* {@code String x}), or with an inferred type (using {@code var x}). Any other
|
||||
* combination is rejected.
|
||||
* */
|
||||
void addParameter(JCVariableDecl param) {
|
||||
if (param.vartype != null && param.name != names.empty) {
|
||||
if (restrictedTypeName(param.vartype, false) != null) {
|
||||
reduce(LambdaParameterKind.VAR);
|
||||
} else {
|
||||
reduce(LambdaParameterKind.EXPLICIT);
|
||||
}
|
||||
}
|
||||
if (param.vartype == null && param.name != names.empty ||
|
||||
param.vartype != null && param.name == names.empty) {
|
||||
Assert.check(param.vartype != null);
|
||||
|
||||
if (param.name == names.error) {
|
||||
reduce(LambdaParameterKind.IMPLICIT);
|
||||
}
|
||||
else if (restrictedTypeName(param.vartype, false) != null) {
|
||||
reduce(LambdaParameterKind.VAR);
|
||||
} else {
|
||||
reduce(LambdaParameterKind.EXPLICIT);
|
||||
}
|
||||
}
|
||||
|
||||
private void reduce(LambdaParameterKind newKind) {
|
||||
@ -3074,7 +3106,7 @@ public class JavacParser implements Parser {
|
||||
JCExpression paramType = catchTypes.size() > 1 ?
|
||||
toP(F.at(catchTypes.head.getStartPosition()).TypeUnion(catchTypes)) :
|
||||
catchTypes.head;
|
||||
JCVariableDecl formal = variableDeclaratorId(mods, paramType);
|
||||
JCVariableDecl formal = variableDeclaratorId(mods, paramType, true, false, false);
|
||||
accept(RPAREN);
|
||||
JCBlock body = block();
|
||||
return F.at(pos).Catch(formal, body);
|
||||
@ -3240,7 +3272,7 @@ public class JavacParser implements Parser {
|
||||
switch (token) {
|
||||
case BYTE: case SHORT: case INT: case LONG: case FLOAT:
|
||||
case DOUBLE: case BOOLEAN: case CHAR: case VOID:
|
||||
case ASSERT, ENUM, IDENTIFIER, UNDERSCORE:
|
||||
case ASSERT, ENUM, IDENTIFIER:
|
||||
if (typeDepth == 0 && peekToken(lookahead, LAX_IDENTIFIER)) {
|
||||
if (parenDepth == 0) {
|
||||
return PatternResult.PATTERN;
|
||||
@ -3249,6 +3281,18 @@ public class JavacParser implements Parser {
|
||||
}
|
||||
}
|
||||
break;
|
||||
case UNDERSCORE:
|
||||
// TODO: REFACTOR to remove the code duplication
|
||||
if (typeDepth == 0 && peekToken(lookahead, tk -> tk == RPAREN || tk == COMMA)) {
|
||||
return PatternResult.PATTERN;
|
||||
} else if (typeDepth == 0 && peekToken(lookahead, LAX_IDENTIFIER)) {
|
||||
if (parenDepth == 0) {
|
||||
return PatternResult.PATTERN;
|
||||
} else {
|
||||
pendingResult = PatternResult.PATTERN;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DOT, QUES, EXTENDS, SUPER, COMMA: break;
|
||||
case LT: typeDepth++; break;
|
||||
case GTGTGT: typeDepth--;
|
||||
@ -3556,7 +3600,7 @@ public class JavacParser implements Parser {
|
||||
T vdefs,
|
||||
boolean localDecl)
|
||||
{
|
||||
return variableDeclaratorsRest(token.pos, mods, type, ident(), false, null, vdefs, localDecl);
|
||||
return variableDeclaratorsRest(token.pos, mods, type, identOrUnderscore(), false, null, vdefs, localDecl);
|
||||
}
|
||||
|
||||
/** VariableDeclaratorsRest = VariableDeclaratorRest { "," VariableDeclarator }
|
||||
@ -3574,7 +3618,7 @@ public class JavacParser implements Parser {
|
||||
T vdefs,
|
||||
boolean localDecl)
|
||||
{
|
||||
JCVariableDecl head = variableDeclaratorRest(pos, mods, type, name, reqInit, dc, localDecl, false);
|
||||
JCVariableDecl head = variableDeclaratorRest(pos, mods, type, name, reqInit, dc, localDecl, false, false);
|
||||
vdefs.append(head);
|
||||
while (token.kind == COMMA) {
|
||||
// All but last of multiple declarators subsume a comma
|
||||
@ -3589,7 +3633,7 @@ public class JavacParser implements Parser {
|
||||
* ConstantDeclarator = Ident ConstantDeclaratorRest
|
||||
*/
|
||||
JCVariableDecl variableDeclarator(JCModifiers mods, JCExpression type, boolean reqInit, Comment dc, boolean localDecl) {
|
||||
return variableDeclaratorRest(token.pos, mods, type, ident(), reqInit, dc, localDecl, true);
|
||||
return variableDeclaratorRest(token.pos, mods, type, identOrUnderscore(), reqInit, dc, localDecl, true, false);
|
||||
}
|
||||
|
||||
/** VariableDeclaratorRest = BracketsOpt ["=" VariableInitializer]
|
||||
@ -3599,42 +3643,63 @@ public class JavacParser implements Parser {
|
||||
* @param dc The documentation comment for the variable declarations, or null.
|
||||
*/
|
||||
JCVariableDecl variableDeclaratorRest(int pos, JCModifiers mods, JCExpression type, Name name,
|
||||
boolean reqInit, Comment dc, boolean localDecl, boolean compound) {
|
||||
boolean reqInit, Comment dc, boolean localDecl, boolean compound, boolean isTypePattern) {
|
||||
boolean declaredUsingVar = false;
|
||||
type = bracketsOpt(type);
|
||||
JCExpression init = null;
|
||||
|
||||
if (Feature.UNNAMED_VARIABLES.allowedInSource(source) && name == names.underscore) {
|
||||
if (!localDecl && !isTypePattern) {
|
||||
log.error(DiagnosticFlag.SYNTAX, pos, Errors.UseOfUnderscoreNotAllowed);
|
||||
}
|
||||
name = names.empty;
|
||||
}
|
||||
|
||||
if (token.kind == EQ) {
|
||||
nextToken();
|
||||
init = variableInitializer();
|
||||
}
|
||||
else if (reqInit) syntaxError(token.pos, Errors.Expected(EQ));
|
||||
JCTree elemType = TreeInfo.innermostType(type, true);
|
||||
int startPos = Position.NOPOS;
|
||||
if (elemType.hasTag(IDENT)) {
|
||||
Name typeName = ((JCIdent)elemType).name;
|
||||
if (restrictedTypeNameStartingAtSource(typeName, pos, !compound && localDecl) != null) {
|
||||
if (typeName != names.var) {
|
||||
reportSyntaxError(elemType.pos, Errors.RestrictedTypeNotAllowedHere(typeName));
|
||||
} else if (type.hasTag(TYPEARRAY) && !compound) {
|
||||
//error - 'var' and arrays
|
||||
reportSyntaxError(elemType.pos, Errors.RestrictedTypeNotAllowedArray(typeName));
|
||||
} else {
|
||||
declaredUsingVar = true;
|
||||
if(compound)
|
||||
//error - 'var' in compound local var decl
|
||||
reportSyntaxError(elemType.pos, Errors.RestrictedTypeNotAllowedCompound(typeName));
|
||||
startPos = TreeInfo.getStartPos(mods);
|
||||
if (startPos == Position.NOPOS)
|
||||
startPos = TreeInfo.getStartPos(type);
|
||||
//implicit type
|
||||
type = null;
|
||||
|
||||
if (Feature.UNNAMED_VARIABLES.allowedInSource(source) && name == names.empty
|
||||
&& localDecl
|
||||
&& init == null
|
||||
&& token.kind != COLON) { // if its unnamed local variable, it needs to have an init unless in enhanced-for
|
||||
syntaxError(token.pos, Errors.Expected(EQ));
|
||||
}
|
||||
|
||||
JCVariableDecl result;
|
||||
if (!isTypePattern) {
|
||||
int startPos = Position.NOPOS;
|
||||
JCTree elemType = TreeInfo.innermostType(type, true);
|
||||
if (elemType.hasTag(IDENT)) {
|
||||
Name typeName = ((JCIdent) elemType).name;
|
||||
if (restrictedTypeNameStartingAtSource(typeName, pos, !compound && localDecl) != null) {
|
||||
if (typeName != names.var) {
|
||||
reportSyntaxError(elemType.pos, Errors.RestrictedTypeNotAllowedHere(typeName));
|
||||
} else if (type.hasTag(TYPEARRAY) && !compound) {
|
||||
//error - 'var' and arrays
|
||||
reportSyntaxError(elemType.pos, Errors.RestrictedTypeNotAllowedArray(typeName));
|
||||
} else {
|
||||
declaredUsingVar = true;
|
||||
if (compound)
|
||||
//error - 'var' in compound local var decl
|
||||
reportSyntaxError(elemType.pos, Errors.RestrictedTypeNotAllowedCompound(typeName));
|
||||
startPos = TreeInfo.getStartPos(mods);
|
||||
if (startPos == Position.NOPOS)
|
||||
startPos = TreeInfo.getStartPos(type);
|
||||
//implicit type
|
||||
type = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
result = toP(F.at(pos).VarDef(mods, name, type, init, declaredUsingVar));
|
||||
attach(result, dc);
|
||||
result.startPos = startPos;
|
||||
} else {
|
||||
result = toP(F.at(pos).VarDef(mods, name, type, null));
|
||||
}
|
||||
JCVariableDecl result =
|
||||
toP(F.at(pos).VarDef(mods, name, type, init, declaredUsingVar));
|
||||
attach(result, dc);
|
||||
result.startPos = startPos;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -3690,55 +3755,50 @@ public class JavacParser implements Parser {
|
||||
|
||||
/** VariableDeclaratorId = Ident BracketsOpt
|
||||
*/
|
||||
JCVariableDecl variableDeclaratorId(JCModifiers mods, JCExpression type) {
|
||||
return variableDeclaratorId(mods, type, false, false);
|
||||
}
|
||||
//where
|
||||
JCVariableDecl variableDeclaratorId(JCModifiers mods, JCExpression type, boolean lambdaParameter, boolean recordComponent) {
|
||||
JCVariableDecl variableDeclaratorId(JCModifiers mods, JCExpression type, boolean catchParameter, boolean lambdaParameter, boolean recordComponent) {
|
||||
int pos = token.pos;
|
||||
Name name;
|
||||
if (lambdaParameter && token.kind == UNDERSCORE) {
|
||||
log.error(pos, Errors.UnderscoreAsIdentifierInLambda);
|
||||
name = token.name();
|
||||
nextToken();
|
||||
} else {
|
||||
if (allowThisIdent ||
|
||||
!lambdaParameter ||
|
||||
LAX_IDENTIFIER.test(token.kind) ||
|
||||
mods.flags != Flags.PARAMETER ||
|
||||
mods.annotations.nonEmpty()) {
|
||||
JCExpression pn = qualident(false);
|
||||
if (pn.hasTag(Tag.IDENT) && ((JCIdent)pn).name != names._this) {
|
||||
name = ((JCIdent)pn).name;
|
||||
} else if (lambdaParameter && type == null) {
|
||||
// we have a lambda parameter that is not an identifier this is a syntax error
|
||||
type = pn;
|
||||
name = names.empty;
|
||||
reportSyntaxError(pos, Errors.Expected(IDENTIFIER));
|
||||
} else {
|
||||
if (allowThisIdent) {
|
||||
if ((mods.flags & Flags.VARARGS) != 0) {
|
||||
log.error(token.pos, Errors.VarargsAndReceiver);
|
||||
}
|
||||
if (token.kind == LBRACKET) {
|
||||
log.error(token.pos, Errors.ArrayAndReceiver);
|
||||
}
|
||||
if (pn.hasTag(Tag.SELECT) && ((JCFieldAccess)pn).name != names._this) {
|
||||
log.error(token.pos, Errors.WrongReceiver);
|
||||
}
|
||||
}
|
||||
return toP(F.at(pos).ReceiverVarDef(mods, pn, type));
|
||||
}
|
||||
if (allowThisIdent ||
|
||||
!lambdaParameter ||
|
||||
LAX_IDENTIFIER.test(token.kind) ||
|
||||
mods.flags != Flags.PARAMETER ||
|
||||
mods.annotations.nonEmpty()) {
|
||||
JCExpression pn;
|
||||
if (token.kind == UNDERSCORE && (catchParameter || lambdaParameter)) {
|
||||
pn = toP(F.at(token.pos).Ident(identOrUnderscore()));
|
||||
} else {
|
||||
/** if it is a lambda parameter and the token kind is not an identifier,
|
||||
* and there are no modifiers or annotations, then this means that the compiler
|
||||
* supposed the lambda to be explicit but it can contain a mix of implicit,
|
||||
* var or explicit parameters. So we assign the error name to the parameter name
|
||||
* instead of issuing an error and analyze the lambda parameters as a whole at
|
||||
* a higher level.
|
||||
*/
|
||||
name = names.empty;
|
||||
pn = qualident(false);
|
||||
}
|
||||
if (pn.hasTag(Tag.IDENT) && ((JCIdent)pn).name != names._this) {
|
||||
name = ((JCIdent)pn).name;
|
||||
} else if (lambdaParameter && type == null) {
|
||||
// we have a lambda parameter that is not an identifier this is a syntax error
|
||||
type = pn;
|
||||
name = names.empty;
|
||||
reportSyntaxError(pos, Errors.Expected(IDENTIFIER));
|
||||
} else {
|
||||
if (allowThisIdent) {
|
||||
if ((mods.flags & Flags.VARARGS) != 0) {
|
||||
log.error(token.pos, Errors.VarargsAndReceiver);
|
||||
}
|
||||
if (token.kind == LBRACKET) {
|
||||
log.error(token.pos, Errors.ArrayAndReceiver);
|
||||
}
|
||||
if (pn.hasTag(Tag.SELECT) && ((JCFieldAccess)pn).name != names._this) {
|
||||
log.error(token.pos, Errors.WrongReceiver);
|
||||
}
|
||||
}
|
||||
return toP(F.at(pos).ReceiverVarDef(mods, pn, type));
|
||||
}
|
||||
} else {
|
||||
/** if it is a lambda parameter and the token kind is not an identifier,
|
||||
* and there are no modifiers or annotations, then this means that the compiler
|
||||
* supposed the lambda to be explicit but it can contain a mix of implicit,
|
||||
* var or explicit parameters. So we assign the error name to the parameter name
|
||||
* instead of issuing an error and analyze the lambda parameters as a whole at
|
||||
* a higher level.
|
||||
*/
|
||||
name = names.error;
|
||||
}
|
||||
if ((mods.flags & Flags.VARARGS) != 0 &&
|
||||
token.kind == LBRACKET) {
|
||||
@ -3749,6 +3809,10 @@ public class JavacParser implements Parser {
|
||||
}
|
||||
type = bracketsOpt(type);
|
||||
|
||||
if (Feature.UNNAMED_VARIABLES.allowedInSource(source) && name == names.underscore) {
|
||||
name = names.empty;
|
||||
}
|
||||
|
||||
return toP(F.at(pos).VarDef(mods, name, type, null,
|
||||
type != null && type.hasTag(IDENT) && ((JCIdent)type).name == names.var));
|
||||
}
|
||||
@ -3779,12 +3843,12 @@ public class JavacParser implements Parser {
|
||||
if (token.kind == FINAL || token.kind == MONKEYS_AT) {
|
||||
JCModifiers mods = optFinal(0);
|
||||
JCExpression t = parseType(true);
|
||||
return variableDeclaratorRest(token.pos, mods, t, ident(), true, null, true, false);
|
||||
return variableDeclaratorRest(token.pos, mods, t, ident(), true, null, true, false, false);
|
||||
}
|
||||
JCExpression t = term(EXPR | TYPE);
|
||||
if (wasTypeMode() && LAX_IDENTIFIER.test(token.kind)) {
|
||||
JCModifiers mods = F.Modifiers(0);
|
||||
return variableDeclaratorRest(token.pos, mods, t, ident(), true, null, true, false);
|
||||
return variableDeclaratorRest(token.pos, mods, t, identOrUnderscore(), true, null, true, false, false);
|
||||
} else {
|
||||
checkSourceLevel(Feature.EFFECTIVELY_FINAL_VARIABLES_IN_TRY_WITH_RESOURCES);
|
||||
if (!t.hasTag(IDENT) && !t.hasTag(SELECT)) {
|
||||
@ -4936,12 +5000,12 @@ public class JavacParser implements Parser {
|
||||
}
|
||||
typeAnnotationsPushedBack = List.nil();
|
||||
}
|
||||
return variableDeclaratorId(mods, type, lambdaParameter, recordComponent);
|
||||
return variableDeclaratorId(mods, type, false, lambdaParameter, recordComponent);
|
||||
}
|
||||
|
||||
protected JCVariableDecl implicitParameter() {
|
||||
JCModifiers mods = F.at(token.pos).Modifiers(Flags.PARAMETER);
|
||||
return variableDeclaratorId(mods, null, true, false);
|
||||
return variableDeclaratorId(mods, null, false, true, false);
|
||||
}
|
||||
|
||||
/* ---------- auxiliary methods -------------- */
|
||||
|
@ -297,7 +297,7 @@ public class PrintingProcessor extends AbstractProcessor {
|
||||
if (kind == ENUM_CONSTANT)
|
||||
writer.print(e.getSimpleName());
|
||||
else {
|
||||
writer.print(e.asType().toString() + " " + e.getSimpleName() );
|
||||
writer.print(e.asType().toString() + " " + (e.getSimpleName().isEmpty() ? "_" : e.getSimpleName()));
|
||||
Object constantValue = e.getConstantValue();
|
||||
if (constantValue != null) {
|
||||
writer.print(" = ");
|
||||
|
@ -3131,6 +3131,9 @@ compiler.misc.feature.reifiable.types.instanceof=\
|
||||
compiler.misc.feature.deconstruction.patterns=\
|
||||
deconstruction patterns
|
||||
|
||||
compiler.misc.feature.unnamed.variables=\
|
||||
unnamed variables
|
||||
|
||||
compiler.misc.feature.records=\
|
||||
records
|
||||
|
||||
@ -3155,9 +3158,9 @@ compiler.warn.underscore.as.identifier=\
|
||||
compiler.err.underscore.as.identifier=\
|
||||
as of release 9, ''_'' is a keyword, and may not be used as an identifier
|
||||
|
||||
compiler.err.underscore.as.identifier.in.lambda=\
|
||||
''_'' used as an identifier\n\
|
||||
(use of ''_'' as an identifier is forbidden for lambda parameters)
|
||||
compiler.err.use.of.underscore.not.allowed=\
|
||||
as of release 21, the underscore keyword ''_'' is only allowed to declare\n\
|
||||
unnamed patterns, local variables, exception parameters or lambda parameters
|
||||
|
||||
compiler.err.enum.as.identifier=\
|
||||
as of release 5, ''enum'' is a keyword, and may not be used as an identifier
|
||||
|
@ -239,6 +239,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
|
||||
|
||||
/** Patterns.
|
||||
*/
|
||||
ANYPATTERN,
|
||||
BINDINGPATTERN,
|
||||
RECORDPATTERN,
|
||||
|
||||
@ -2263,6 +2264,34 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
|
||||
implements PatternTree {
|
||||
}
|
||||
|
||||
public static class JCAnyPattern extends JCPattern
|
||||
implements AnyPatternTree {
|
||||
|
||||
protected JCAnyPattern() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Visitor v) {
|
||||
v.visitAnyPattern(this);
|
||||
}
|
||||
|
||||
@DefinedBy(Api.COMPILER_TREE)
|
||||
public Kind getKind() {
|
||||
return Kind.ANY_PATTERN;
|
||||
}
|
||||
|
||||
@Override
|
||||
@DefinedBy(Api.COMPILER_TREE)
|
||||
public <R, D> R accept(TreeVisitor<R, D> v, D d) {
|
||||
return v.visitAnyPattern(this, d);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag getTag() {
|
||||
return ANYPATTERN;
|
||||
}
|
||||
}
|
||||
|
||||
public static class JCBindingPattern extends JCPattern
|
||||
implements BindingPatternTree {
|
||||
public JCVariableDecl var;
|
||||
@ -2368,6 +2397,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
|
||||
implements PatternCaseLabelTree {
|
||||
|
||||
public JCPattern pat;
|
||||
public JCExpression syntheticGuard;
|
||||
|
||||
protected JCPatternCaseLabel(JCPattern pat) {
|
||||
this.pat = pat;
|
||||
@ -3545,6 +3575,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition {
|
||||
public void visitBinary(JCBinary that) { visitTree(that); }
|
||||
public void visitTypeCast(JCTypeCast that) { visitTree(that); }
|
||||
public void visitTypeTest(JCInstanceOf that) { visitTree(that); }
|
||||
public void visitAnyPattern(JCAnyPattern that) { visitTree(that); }
|
||||
public void visitBindingPattern(JCBindingPattern that) { visitTree(that); }
|
||||
public void visitDefaultCaseLabel(JCDefaultCaseLabel that) { visitTree(that); }
|
||||
public void visitConstantCaseLabel(JCConstantCaseLabel that) { visitTree(that); }
|
||||
|
@ -715,7 +715,11 @@ public class Pretty extends JCTree.Visitor {
|
||||
} else {
|
||||
printExpr(tree.vartype);
|
||||
print(' ');
|
||||
print(tree.name);
|
||||
if (tree.name.isEmpty()) {
|
||||
print('_');
|
||||
} else {
|
||||
print(tree.name);
|
||||
}
|
||||
}
|
||||
if (tree.init != null) {
|
||||
print(" = ");
|
||||
@ -941,6 +945,14 @@ public class Pretty extends JCTree.Visitor {
|
||||
}
|
||||
}
|
||||
|
||||
public void visitAnyPattern(JCAnyPattern patt) {
|
||||
try {
|
||||
print('_');
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitRecordPattern(JCRecordPattern tree) {
|
||||
try {
|
||||
|
@ -499,6 +499,12 @@ public class TreeCopier<P> implements TreeVisitor<JCTree,P> {
|
||||
return M.at(t.pos).TypeTest(expr, pattern);
|
||||
}
|
||||
|
||||
@DefinedBy(Api.COMPILER_TREE)
|
||||
public JCTree visitAnyPattern(AnyPatternTree node, P p) {
|
||||
JCAnyPattern t = (JCAnyPattern) node;
|
||||
return M.at(t.pos).AnyPattern();
|
||||
}
|
||||
|
||||
@DefinedBy(Api.COMPILER_TREE)
|
||||
public JCTree visitBindingPattern(BindingPatternTree node, P p) {
|
||||
JCBindingPattern t = (JCBindingPattern) node;
|
||||
|
@ -1346,6 +1346,7 @@ public class TreeInfo {
|
||||
return switch (pat.getTag()) {
|
||||
case BINDINGPATTERN -> pat.type;
|
||||
case RECORDPATTERN -> ((JCRecordPattern) pat).type;
|
||||
case ANYPATTERN -> ((JCAnyPattern) pat).type;
|
||||
default -> throw new AssertionError();
|
||||
};
|
||||
}
|
||||
|
@ -483,6 +483,12 @@ public class TreeMaker implements JCTree.Factory {
|
||||
return tree;
|
||||
}
|
||||
|
||||
public JCAnyPattern AnyPattern() {
|
||||
JCAnyPattern tree = new JCAnyPattern();
|
||||
tree.pos = pos;
|
||||
return tree;
|
||||
}
|
||||
|
||||
public JCBindingPattern BindingPattern(JCVariableDecl var) {
|
||||
JCBindingPattern tree = new JCBindingPattern(var);
|
||||
tree.pos = pos;
|
||||
|
@ -27,6 +27,7 @@ package com.sun.tools.javac.tree;
|
||||
|
||||
import com.sun.tools.javac.util.*;
|
||||
import com.sun.tools.javac.tree.JCTree.*;
|
||||
import jdk.internal.javac.PreviewFeature;
|
||||
|
||||
/** A subclass of Tree.Visitor, this class defines
|
||||
* a general tree scanner pattern. Translation proceeds recursively in
|
||||
@ -322,6 +323,11 @@ public class TreeScanner extends Visitor {
|
||||
scan(tree.pat);
|
||||
}
|
||||
|
||||
@Override
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.UNNAMED)
|
||||
public void visitAnyPattern(JCAnyPattern that) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitRecordPattern(JCRecordPattern that) {
|
||||
scan(that.deconstructor);
|
||||
|
@ -364,6 +364,10 @@ public class TreeTranslator extends JCTree.Visitor {
|
||||
result = tree;
|
||||
}
|
||||
|
||||
public void visitAnyPattern(JCAnyPattern tree) {
|
||||
result = tree;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitDefaultCaseLabel(JCDefaultCaseLabel tree) {
|
||||
result = tree;
|
||||
|
@ -69,6 +69,7 @@ public class Names {
|
||||
public final Name transitive;
|
||||
public final Name uses;
|
||||
public final Name open;
|
||||
public final Name underscore;
|
||||
public final Name when;
|
||||
public final Name with;
|
||||
public final Name yield;
|
||||
@ -262,6 +263,7 @@ public class Names {
|
||||
transitive = fromString("transitive");
|
||||
uses = fromString("uses");
|
||||
open = fromString("open");
|
||||
underscore = fromString("_");
|
||||
when = fromString("when");
|
||||
with = fromString("with");
|
||||
yield = fromString("yield");
|
||||
|
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* @test /nodynamiccopyright/
|
||||
* @bug 8304246
|
||||
* @summary Compiler Implementation for Unnamed patterns and variables
|
||||
* @enablePreview
|
||||
* @compile/ref=TwrLintUnderscore.out --enable-preview -source ${jdk.version} -Xlint:try -XDrawDiagnostics TwrLintUnderscore.java
|
||||
*/
|
||||
class TwrLintUnderscore implements AutoCloseable {
|
||||
private static void test1() {
|
||||
try(TwrLintUnderscore _ = new TwrLintUnderscore()) {
|
||||
// _ cannot be referenced so no lint warning for an unused resource should be emitted
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The AutoCloseable method of a resource.
|
||||
*/
|
||||
@Override
|
||||
public void close () {
|
||||
return;
|
||||
}
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
- compiler.note.preview.filename: TwrLintUnderscore.java, DEFAULT
|
||||
- compiler.note.preview.recompile
|
@ -148,7 +148,7 @@ public class TestGetScopeResult {
|
||||
multipleCandidates2);
|
||||
|
||||
String[] implicitExplicitConflict1 = {
|
||||
":t",
|
||||
"<error>:t",
|
||||
"s:java.lang.String",
|
||||
"super:java.lang.Object",
|
||||
"this:Test"
|
||||
@ -159,7 +159,7 @@ public class TestGetScopeResult {
|
||||
|
||||
String[] implicitExplicitConflict2 = {
|
||||
"s:none",
|
||||
":t",
|
||||
"<error>:t",
|
||||
"super:java.lang.Object",
|
||||
"this:Test"
|
||||
};
|
||||
@ -169,7 +169,7 @@ public class TestGetScopeResult {
|
||||
|
||||
String[] noFunctionInterface = {
|
||||
"s:none",
|
||||
":t",
|
||||
"<error>:t",
|
||||
"super:java.lang.Object",
|
||||
"this:Test"
|
||||
};
|
||||
|
@ -21,7 +21,10 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
// key: compiler.err.underscore.as.identifier.in.lambda
|
||||
// key: compiler.misc.feature.unnamed.variables
|
||||
// key: compiler.warn.preview.feature.use.plural
|
||||
// options: --enable-preview -source ${jdk.version} -Xlint:preview
|
||||
|
||||
public class UnderscoreInLambdaExpression {
|
||||
java.util.function.Function<String,String> f = _ -> "x";
|
||||
}
|
||||
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2023, 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.
|
||||
*/
|
||||
|
||||
// key: compiler.err.use.of.underscore.not.allowed
|
||||
// options: --enable-preview -source ${jdk.version} -Xlint:preview
|
||||
|
||||
import java.util.function.*;
|
||||
|
||||
class UseOfUnderscoreNotAllowed {
|
||||
IntBinaryOperator f = (int x, int y) -> _ + x;
|
||||
}
|
@ -5,6 +5,7 @@
|
||||
* @summary Test generation of warnings when '_' is used an identifier
|
||||
* @compile/fail/ref=IdentifierTest8.out --release 8 -Werror -XDrawDiagnostics -Xlint:-options IdentifierTest.java
|
||||
* @compile/fail/ref=IdentifierTest9.out -XDrawDiagnostics IdentifierTest.java
|
||||
* @compile/fail/ref=IdentifierTest21.out -source ${jdk.version} --enable-preview -XDrawDiagnostics IdentifierTest.java
|
||||
*/
|
||||
|
||||
import java.util.List;
|
||||
|
39
test/langtools/tools/javac/lambda/IdentifierTest21.out
Normal file
39
test/langtools/tools/javac/lambda/IdentifierTest21.out
Normal file
@ -0,0 +1,39 @@
|
||||
IdentifierTest.java:42:11: compiler.err.use.of.underscore.not.allowed
|
||||
IdentifierTest.java:45:16: compiler.err.use.of.underscore.not.allowed
|
||||
IdentifierTest.java:47:22: compiler.err.use.of.underscore.not.allowed
|
||||
IdentifierTest.java:52:13: compiler.err.use.of.underscore.not.allowed
|
||||
IdentifierTest.java:52:23: compiler.err.use.of.underscore.not.allowed
|
||||
IdentifierTest.java:54:13: compiler.err.use.of.underscore.not.allowed
|
||||
IdentifierTest.java:56:13: compiler.err.use.of.underscore.not.allowed
|
||||
IdentifierTest.java:64:67: compiler.err.use.of.underscore.not.allowed
|
||||
IdentifierTest.java:71:13: compiler.err.use.of.underscore.not.allowed
|
||||
IdentifierTest.java:72:14: compiler.err.use.of.underscore.not.allowed
|
||||
IdentifierTest.java:73:18: compiler.err.use.of.underscore.not.allowed
|
||||
IdentifierTest.java:80:13: compiler.err.use.of.underscore.not.allowed
|
||||
IdentifierTest.java:80:15: compiler.err.use.of.underscore.not.allowed
|
||||
IdentifierTest.java:82:13: compiler.err.use.of.underscore.not.allowed
|
||||
IdentifierTest.java:82:15: compiler.err.use.of.underscore.not.allowed
|
||||
IdentifierTest.java:89:10: compiler.err.use.of.underscore.not.allowed
|
||||
IdentifierTest.java:89:38: compiler.err.use.of.underscore.not.allowed
|
||||
IdentifierTest.java:95:14: compiler.err.use.of.underscore.not.allowed
|
||||
IdentifierTest.java:102:17: compiler.err.use.of.underscore.not.allowed
|
||||
IdentifierTest.java:102:26: compiler.err.use.of.underscore.not.allowed
|
||||
IdentifierTest.java:119:20: compiler.err.use.of.underscore.not.allowed
|
||||
IdentifierTest.java:124:10: compiler.err.use.of.underscore.not.allowed
|
||||
IdentifierTest.java:129:17: compiler.err.use.of.underscore.not.allowed
|
||||
IdentifierTest.java:132:17: compiler.err.use.of.underscore.not.allowed
|
||||
IdentifierTest.java:139:24: compiler.err.use.of.underscore.not.allowed
|
||||
IdentifierTest.java:139:33: compiler.err.use.of.underscore.not.allowed
|
||||
IdentifierTest.java:140:39: compiler.err.use.of.underscore.not.allowed
|
||||
IdentifierTest.java:145:15: compiler.err.use.of.underscore.not.allowed
|
||||
IdentifierTest.java:146:13: compiler.err.use.of.underscore.not.allowed
|
||||
IdentifierTest.java:151:15: compiler.err.use.of.underscore.not.allowed
|
||||
IdentifierTest.java:152:17: compiler.err.use.of.underscore.not.allowed
|
||||
IdentifierTest.java:160:25: compiler.err.use.of.underscore.not.allowed
|
||||
IdentifierTest.java:169:5: compiler.err.use.of.underscore.not.allowed
|
||||
IdentifierTest.java:173:26: compiler.err.use.of.underscore.not.allowed
|
||||
IdentifierTest.java:175:19: compiler.err.use.of.underscore.not.allowed
|
||||
IdentifierTest.java:181:11: compiler.err.use.of.underscore.not.allowed
|
||||
- compiler.note.preview.filename: IdentifierTest.java, DEFAULT
|
||||
- compiler.note.preview.recompile
|
||||
36 errors
|
@ -1,47 +1,47 @@
|
||||
IdentifierTest.java:41:11: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:44:16: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:45:20: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:46:22: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:51:13: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:51:15: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:51:23: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:53:13: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:55:13: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:61:21: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:62:42: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:63:67: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:70:13: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:71:14: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:72:18: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:77:22: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:79:13: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:79:15: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:81:13: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:81:15: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:88:10: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:88:38: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:94:14: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:101:17: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:101:26: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:118:20: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:123:10: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:128:17: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:131:17: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:138:17: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:138:24: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:138:33: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:139:39: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:143:13: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:144:15: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:145:13: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:150:15: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:151:17: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:157:16: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:159:25: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:168:5: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:172:26: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:174:19: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:180:11: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:42:11: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:45:16: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:46:20: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:47:22: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:52:13: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:52:15: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:52:23: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:54:13: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:56:13: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:62:21: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:63:42: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:64:67: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:71:13: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:72:14: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:73:18: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:78:22: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:80:13: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:80:15: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:82:13: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:82:15: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:89:10: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:89:38: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:95:14: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:102:17: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:102:26: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:119:20: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:124:10: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:129:17: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:132:17: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:139:17: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:139:24: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:139:33: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:140:39: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:144:13: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:145:15: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:146:13: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:151:15: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:152:17: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:158:16: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:160:25: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:169:5: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:173:26: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:175:19: compiler.warn.underscore.as.identifier
|
||||
IdentifierTest.java:181:11: compiler.warn.underscore.as.identifier
|
||||
- compiler.err.warnings.and.werror
|
||||
1 error
|
||||
44 warnings
|
||||
44 warnings
|
@ -1,45 +1,38 @@
|
||||
IdentifierTest.java:41:11: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:44:16: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:45:20: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:46:22: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:51:13: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:51:15: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:51:23: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:53:13: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:55:13: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:61:21: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:62:42: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:63:67: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:70:13: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:71:14: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:72:18: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:77:22: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:79:13: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:79:15: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:81:13: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:81:15: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:88:10: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:88:38: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:94:14: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:101:17: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:101:26: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:118:20: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:123:10: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:128:17: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:131:17: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:138:17: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:138:24: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:138:33: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:139:39: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:143:13: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:144:15: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:145:13: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:150:15: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:151:17: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:157:16: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:159:25: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:168:5: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:172:26: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:174:19: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:180:11: compiler.err.underscore.as.identifier
|
||||
44 errors
|
||||
IdentifierTest.java:42:11: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:45:16: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:46:20: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.unnamed.variables)
|
||||
IdentifierTest.java:47:22: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:52:13: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:52:23: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:54:13: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:56:13: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:64:67: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:71:13: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:72:14: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:73:18: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:80:13: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:80:15: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:82:13: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:82:15: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:89:10: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:89:38: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:95:14: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:102:17: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:102:26: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:119:20: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:124:10: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:129:17: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:132:17: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:139:24: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:139:33: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:140:39: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:145:15: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:146:13: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:151:15: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:152:17: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:160:25: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:169:5: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:173:26: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:175:19: compiler.err.underscore.as.identifier
|
||||
IdentifierTest.java:181:11: compiler.err.underscore.as.identifier
|
||||
37 errors
|
@ -3,6 +3,7 @@
|
||||
* @summary Check usages of underscore as identifier generate warnings
|
||||
* @compile/fail/ref=UnderscoreAsIdent8.out --release 8 -XDrawDiagnostics -Xlint:-options -Werror UnderscoreAsIdent.java
|
||||
* @compile/fail/ref=UnderscoreAsIdent9.out -XDrawDiagnostics -Werror UnderscoreAsIdent.java
|
||||
* @compile/fail/ref=UnderscoreAsIdent21.out -source ${jdk.version} --enable-preview -XDrawDiagnostics UnderscoreAsIdent.java
|
||||
*/
|
||||
package _._;
|
||||
|
||||
|
17
test/langtools/tools/javac/lambda/UnderscoreAsIdent21.out
Normal file
17
test/langtools/tools/javac/lambda/UnderscoreAsIdent21.out
Normal file
@ -0,0 +1,17 @@
|
||||
UnderscoreAsIdent.java:8:9: compiler.err.use.of.underscore.not.allowed
|
||||
UnderscoreAsIdent.java:8:11: compiler.err.use.of.underscore.not.allowed
|
||||
UnderscoreAsIdent.java:10:8: compiler.err.use.of.underscore.not.allowed
|
||||
UnderscoreAsIdent.java:10:10: compiler.err.use.of.underscore.not.allowed
|
||||
UnderscoreAsIdent.java:12:7: compiler.err.use.of.underscore.not.allowed
|
||||
UnderscoreAsIdent.java:13:12: compiler.err.use.of.underscore.not.allowed
|
||||
UnderscoreAsIdent.java:14:10: compiler.err.use.of.underscore.not.allowed
|
||||
UnderscoreAsIdent.java:14:19: compiler.err.use.of.underscore.not.allowed
|
||||
UnderscoreAsIdent.java:19:25: compiler.err.use.of.underscore.not.allowed
|
||||
UnderscoreAsIdent.java:19:33: compiler.err.use.of.underscore.not.allowed
|
||||
UnderscoreAsIdent.java:25:9: compiler.err.use.of.underscore.not.allowed
|
||||
UnderscoreAsIdent.java:27:19: compiler.err.use.of.underscore.not.allowed
|
||||
UnderscoreAsIdent.java:29:9: compiler.err.use.of.underscore.not.allowed
|
||||
UnderscoreAsIdent.java:31:22: compiler.err.use.of.underscore.not.allowed
|
||||
- compiler.note.preview.filename: UnderscoreAsIdent.java, DEFAULT
|
||||
- compiler.note.preview.recompile
|
||||
14 errors
|
@ -1,20 +1,20 @@
|
||||
UnderscoreAsIdent.java:7:9: compiler.warn.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:7:11: compiler.warn.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:9:8: compiler.warn.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:9:10: compiler.warn.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:11:7: compiler.warn.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:12:12: compiler.warn.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:13:10: compiler.warn.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:13:19: compiler.warn.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:15:16: compiler.warn.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:18:18: compiler.warn.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:18:25: compiler.warn.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:18:33: compiler.warn.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:21:34: compiler.warn.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:24:9: compiler.warn.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:26:19: compiler.warn.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:28:9: compiler.warn.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:30:22: compiler.warn.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:8:9: compiler.warn.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:8:11: compiler.warn.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:10:8: compiler.warn.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:10:10: compiler.warn.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:12:7: compiler.warn.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:13:12: compiler.warn.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:14:10: compiler.warn.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:14:19: compiler.warn.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:16:16: compiler.warn.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:19:18: compiler.warn.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:19:25: compiler.warn.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:19:33: compiler.warn.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:22:34: compiler.warn.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:25:9: compiler.warn.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:27:19: compiler.warn.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:29:9: compiler.warn.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:31:22: compiler.warn.underscore.as.identifier
|
||||
- compiler.err.warnings.and.werror
|
||||
1 error
|
||||
17 warnings
|
||||
|
@ -1,18 +1,16 @@
|
||||
UnderscoreAsIdent.java:7:9: compiler.err.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:7:11: compiler.err.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:9:8: compiler.err.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:9:10: compiler.err.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:11:7: compiler.err.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:12:12: compiler.err.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:13:10: compiler.err.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:13:19: compiler.err.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:15:16: compiler.err.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:18:18: compiler.err.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:18:25: compiler.err.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:18:33: compiler.err.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:21:34: compiler.err.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:24:9: compiler.err.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:26:19: compiler.err.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:28:9: compiler.err.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:30:22: compiler.err.underscore.as.identifier
|
||||
17 errors
|
||||
UnderscoreAsIdent.java:8:9: compiler.err.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:8:11: compiler.err.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:10:8: compiler.err.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:10:10: compiler.err.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:12:7: compiler.err.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:13:12: compiler.err.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:14:10: compiler.err.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:14:19: compiler.err.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:16:16: compiler.err.preview.feature.disabled.plural: (compiler.misc.feature.unnamed.variables)
|
||||
UnderscoreAsIdent.java:19:25: compiler.err.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:19:33: compiler.err.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:25:9: compiler.err.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:27:19: compiler.err.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:29:9: compiler.err.underscore.as.identifier
|
||||
UnderscoreAsIdent.java:31:22: compiler.err.underscore.as.identifier
|
||||
15 errors
|
@ -12,7 +12,6 @@ public class DeconstructionPatternErrors {
|
||||
public static void meth() throws Throwable {
|
||||
Object p;
|
||||
p = new P(42);
|
||||
if (p instanceof P(_));
|
||||
if (p instanceof P3(ArrayList<Integer> l));
|
||||
if (p instanceof P4(ArrayList<Integer> l));
|
||||
if (p instanceof P5(int i));
|
||||
|
@ -1,29 +1,27 @@
|
||||
DeconstructionPatternErrors.java:15:28: compiler.err.underscore.as.identifier
|
||||
DeconstructionPatternErrors.java:15:29: compiler.err.expected: token.identifier
|
||||
DeconstructionPatternErrors.java:43:37: compiler.err.illegal.start.of.type
|
||||
DeconstructionPatternErrors.java:45:28: compiler.err.illegal.start.of.type
|
||||
DeconstructionPatternErrors.java:47:42: compiler.err.expected: ';'
|
||||
DeconstructionPatternErrors.java:47:43: compiler.err.not.stmt
|
||||
DeconstructionPatternErrors.java:16:29: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.util.List<java.lang.String>, java.util.ArrayList<java.lang.Integer>)
|
||||
DeconstructionPatternErrors.java:17:29: compiler.err.instanceof.reifiable.not.safe: java.lang.Object, java.util.ArrayList<java.lang.Integer>
|
||||
DeconstructionPatternErrors.java:18:29: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String, int)
|
||||
DeconstructionPatternErrors.java:19:28: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: int, java.lang.String)
|
||||
DeconstructionPatternErrors.java:20:29: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String, DeconstructionPatternErrors.P)
|
||||
DeconstructionPatternErrors.java:42:37: compiler.err.illegal.start.of.type
|
||||
DeconstructionPatternErrors.java:44:28: compiler.err.illegal.start.of.type
|
||||
DeconstructionPatternErrors.java:46:42: compiler.err.expected: ';'
|
||||
DeconstructionPatternErrors.java:46:43: compiler.err.not.stmt
|
||||
DeconstructionPatternErrors.java:15:29: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.util.List<java.lang.String>, java.util.ArrayList<java.lang.Integer>)
|
||||
DeconstructionPatternErrors.java:16:29: compiler.err.instanceof.reifiable.not.safe: java.lang.Object, java.util.ArrayList<java.lang.Integer>
|
||||
DeconstructionPatternErrors.java:17:29: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String, int)
|
||||
DeconstructionPatternErrors.java:18:28: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: int, java.lang.String)
|
||||
DeconstructionPatternErrors.java:19:29: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String, DeconstructionPatternErrors.P)
|
||||
DeconstructionPatternErrors.java:20:26: compiler.err.incorrect.number.of.nested.patterns: java.lang.Runnable,java.lang.Runnable, java.lang.Runnable
|
||||
DeconstructionPatternErrors.java:21:26: compiler.err.incorrect.number.of.nested.patterns: java.lang.Runnable,java.lang.Runnable, java.lang.Runnable
|
||||
DeconstructionPatternErrors.java:22:26: compiler.err.incorrect.number.of.nested.patterns: java.lang.Runnable,java.lang.Runnable, java.lang.Runnable
|
||||
DeconstructionPatternErrors.java:23:26: compiler.err.incorrect.number.of.nested.patterns: int, int,compiler.misc.type.none
|
||||
DeconstructionPatternErrors.java:24:26: compiler.err.incorrect.number.of.nested.patterns: int, int,int
|
||||
DeconstructionPatternErrors.java:25:36: compiler.err.cant.resolve.location: kindname.class, Unresolvable, , , (compiler.misc.location: kindname.class, DeconstructionPatternErrors, null)
|
||||
DeconstructionPatternErrors.java:25:26: compiler.err.incorrect.number.of.nested.patterns: int, int,Unresolvable
|
||||
DeconstructionPatternErrors.java:26:13: compiler.err.instanceof.reifiable.not.safe: java.lang.Object, DeconstructionPatternErrors.GenRecord<java.lang.String>
|
||||
DeconstructionPatternErrors.java:27:29: compiler.err.instanceof.reifiable.not.safe: java.lang.Object, DeconstructionPatternErrors.GenRecord<java.lang.String>
|
||||
DeconstructionPatternErrors.java:28:44: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String, java.lang.Integer)
|
||||
DeconstructionPatternErrors.java:28:13: compiler.err.instanceof.reifiable.not.safe: java.lang.Object, DeconstructionPatternErrors.GenRecord<java.lang.String>
|
||||
DeconstructionPatternErrors.java:29:40: compiler.err.match.binding.exists
|
||||
DeconstructionPatternErrors.java:30:56: compiler.err.already.defined: kindname.variable, v1, kindname.method, meth()
|
||||
DeconstructionPatternErrors.java:30:64: compiler.err.already.defined: kindname.variable, v2, kindname.method, meth()
|
||||
DeconstructionPatternErrors.java:31:29: compiler.err.prob.found.req: (compiler.misc.not.applicable.types: int, byte)
|
||||
DeconstructionPatternErrors.java:32:29: compiler.err.prob.found.req: (compiler.misc.not.applicable.types: int, long)
|
||||
DeconstructionPatternErrors.java:34:21: compiler.err.prob.found.req: (compiler.misc.not.applicable.types: int, byte)
|
||||
DeconstructionPatternErrors.java:35:21: compiler.err.prob.found.req: (compiler.misc.not.applicable.types: int, long)
|
||||
28 errors
|
||||
DeconstructionPatternErrors.java:22:26: compiler.err.incorrect.number.of.nested.patterns: int, int,compiler.misc.type.none
|
||||
DeconstructionPatternErrors.java:23:26: compiler.err.incorrect.number.of.nested.patterns: int, int,int
|
||||
DeconstructionPatternErrors.java:24:36: compiler.err.cant.resolve.location: kindname.class, Unresolvable, , , (compiler.misc.location: kindname.class, DeconstructionPatternErrors, null)
|
||||
DeconstructionPatternErrors.java:24:26: compiler.err.incorrect.number.of.nested.patterns: int, int,Unresolvable
|
||||
DeconstructionPatternErrors.java:25:13: compiler.err.instanceof.reifiable.not.safe: java.lang.Object, DeconstructionPatternErrors.GenRecord<java.lang.String>
|
||||
DeconstructionPatternErrors.java:26:29: compiler.err.instanceof.reifiable.not.safe: java.lang.Object, DeconstructionPatternErrors.GenRecord<java.lang.String>
|
||||
DeconstructionPatternErrors.java:27:44: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String, java.lang.Integer)
|
||||
DeconstructionPatternErrors.java:27:13: compiler.err.instanceof.reifiable.not.safe: java.lang.Object, DeconstructionPatternErrors.GenRecord<java.lang.String>
|
||||
DeconstructionPatternErrors.java:28:40: compiler.err.match.binding.exists
|
||||
DeconstructionPatternErrors.java:29:56: compiler.err.already.defined: kindname.variable, v1, kindname.method, meth()
|
||||
DeconstructionPatternErrors.java:29:64: compiler.err.already.defined: kindname.variable, v2, kindname.method, meth()
|
||||
DeconstructionPatternErrors.java:30:29: compiler.err.prob.found.req: (compiler.misc.not.applicable.types: int, byte)
|
||||
DeconstructionPatternErrors.java:31:29: compiler.err.prob.found.req: (compiler.misc.not.applicable.types: int, long)
|
||||
DeconstructionPatternErrors.java:33:21: compiler.err.prob.found.req: (compiler.misc.not.applicable.types: int, byte)
|
||||
DeconstructionPatternErrors.java:34:21: compiler.err.prob.found.req: (compiler.misc.not.applicable.types: int, long)
|
||||
26 errors
|
@ -23,6 +23,7 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @enablePreview
|
||||
* @summary Test behavior of Pretty
|
||||
* @modules jdk.compiler
|
||||
*/
|
||||
@ -48,38 +49,46 @@ public class PrettyTest {
|
||||
String code = "class Test {\n" +
|
||||
" boolean t(Object o) {\n" +
|
||||
" boolean b;\n" +
|
||||
" boolean _ = true;\n" +
|
||||
" b = o instanceof String s;\n" +
|
||||
" b = o instanceof R(String s);\n" +
|
||||
" b = o instanceof R(var s);\n" +
|
||||
" b = o instanceof R2(R(var s), String t);\n" +
|
||||
" b = o instanceof R2(R(var s), var t);\n" +
|
||||
" b = o instanceof R(String _);\n" +
|
||||
" b = o instanceof R2(R(var _), var _);\n" +
|
||||
" b = o instanceof R2(R(_), var t);\n" +
|
||||
" }\n" +
|
||||
" record R(String s) {}\n" +
|
||||
" record R2(R r, String s) {}\n" +
|
||||
"}\n";
|
||||
String pretty = parse(code).toString().replaceAll("\\R", "\n");
|
||||
String expected = """
|
||||
\n\
|
||||
class Test {
|
||||
\n\
|
||||
boolean t(Object o) {
|
||||
boolean b;
|
||||
b = o instanceof String s;
|
||||
b = o instanceof R(String s);
|
||||
b = o instanceof R(/*missing*/ s);
|
||||
b = o instanceof R2(R(/*missing*/ s), String t);
|
||||
b = o instanceof R2(R(/*missing*/ s), /*missing*/ t);
|
||||
}
|
||||
\n\
|
||||
class R {
|
||||
private final String s;
|
||||
}
|
||||
\n\
|
||||
class R2 {
|
||||
private final R r;
|
||||
private final String s;
|
||||
}
|
||||
}""";
|
||||
\n\
|
||||
class Test {
|
||||
\n\
|
||||
boolean t(Object o) {
|
||||
boolean b;
|
||||
boolean _ = true;
|
||||
b = o instanceof String s;
|
||||
b = o instanceof R(String s);
|
||||
b = o instanceof R(/*missing*/ s);
|
||||
b = o instanceof R2(R(/*missing*/ s), String t);
|
||||
b = o instanceof R2(R(/*missing*/ s), /*missing*/ t);
|
||||
b = o instanceof R(String _);
|
||||
b = o instanceof R2(R(/*missing*/ _), /*missing*/ _);
|
||||
b = o instanceof R2(R(_), /*missing*/ t);
|
||||
}
|
||||
\n\
|
||||
class R {
|
||||
private final String s;
|
||||
}
|
||||
\n\
|
||||
class R2 {
|
||||
private final R r;
|
||||
private final String s;
|
||||
}
|
||||
}""";
|
||||
if (!expected.equals(pretty)) {
|
||||
throw new AssertionError("Actual prettified source: " + pretty);
|
||||
}
|
||||
|
306
test/langtools/tools/javac/patterns/Unnamed.java
Normal file
306
test/langtools/tools/javac/patterns/Unnamed.java
Normal file
@ -0,0 +1,306 @@
|
||||
/*
|
||||
* Copyright (c) 2023, 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
|
||||
* @bug 8304246
|
||||
* @summary Compiler Implementation for Unnamed patterns and variables
|
||||
* @enablePreview
|
||||
* @compile Unnamed.java
|
||||
* @run main Unnamed
|
||||
*/
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class Unnamed {
|
||||
public static void main(String[] args) throws Throwable {
|
||||
new Unnamed().run();
|
||||
}
|
||||
|
||||
public void run() {
|
||||
assertEquals(1, testMultiValuesTopLevel(new R1()));
|
||||
assertEquals(2, testMultiValuesTopLevel(new R3()));
|
||||
assertEquals(1, testMultiValuesTopLevel2(new R1()));
|
||||
assertEquals(2, testMultiValuesTopLevel2(new R2()));
|
||||
assertEquals(2, testMultiValuesTopLevel2(new R4()));
|
||||
assertEquals(1, testMultiValuesNested(new Box<>(new R1())));
|
||||
assertEquals(1, testMultiValuesNested(new Box<>(new R2())));
|
||||
assertEquals(2, testMultiValuesNested(new Box<>(new R3())));
|
||||
assertEquals(3, testMultiValuesNested(new Box<>(new R4())));
|
||||
assertEquals(1, testMultiValuesNestedUnnamedVarAndPattern(new Box<>(new R1())));
|
||||
assertEquals(2, testMultiValuesNestedUnnamedVarAndPattern(new Box<>(new R4())));
|
||||
assertEquals(1, testMultiValuesNestedMix(new Box<>(new R1())));
|
||||
assertEquals(1, testMultiValuesNestedMix(new Box2<>(new R1())));
|
||||
assertEquals(1, testMultiValuesNestedMix2(new Box<>(new R1())));
|
||||
assertEquals(1, testMultiValuesNestedMix2("BOX"));
|
||||
assertEquals(2, testMultiValuesNestedMix2(new Box2<>(new R1())));
|
||||
assertEquals(1, testMultiValuesStatementBlock(42));
|
||||
assertEquals(1, testMultiValuesStatementBlock(42.0f));
|
||||
assertEquals(2, testMultiValuesStatementBlock("BOX"));
|
||||
assertEquals(1, testMultiValuesStatementBlock2(new Box<>(new R1())));
|
||||
assertEquals(1, testMultiValuesStatementBlock2("BOX"));
|
||||
assertEquals(2, testMultiValuesStatementBlock2(new Box2<>(new R1())));
|
||||
assertEquals(2, testMultiValuesGuards(new R3(), 1));
|
||||
assertEquals(3, testMultiValuesGuards(new R4(), 42));
|
||||
assertEquals(3, testMultiValuesGuards(new R3(), 42));
|
||||
assertEquals(1, testMultiValuesNestedGuards(new Box(new R2()), 42));
|
||||
assertEquals(2, testMultiValuesNestedGuards(new Box(new R3()), 1));
|
||||
assertEquals(1, testMixUnconditionalAndConditional(new R1()));
|
||||
assertEquals(2, testMixUnconditionalAndConditional(new R2()));
|
||||
assertEquals(2, testMixUnconditionalAndConditional(new R3()));
|
||||
assertEquals(1, testMultipleExpr(new Box<>(new R1())));
|
||||
assertEquals(1, testUnrolledExpr(new Box<>(new R1())));
|
||||
assertEquals(1, testMultipleStat(new Box<>(new R1())));
|
||||
assertEquals(1, testUnrolledStat(new Box<>(new R1())));
|
||||
assertEquals(2, testMixVarWithExplicit(new Box<>(new R2())));
|
||||
assertEquals("binding", unnamedGuardAddsBindings("match1", "binding"));
|
||||
assertEquals("any", unnamedGuardAddsBindings(42, 42));
|
||||
|
||||
unnamedTest();
|
||||
}
|
||||
|
||||
private void unnamedTest() {
|
||||
int _ = 0;
|
||||
int _ = 1;
|
||||
try (Lock _ = null) {
|
||||
try (Lock _ = null) {
|
||||
} catch (Exception _) {
|
||||
try {
|
||||
} catch (Exception _) {}
|
||||
}
|
||||
}
|
||||
String[] strs = new String[] { "str1", "str2" };
|
||||
for (var _ : strs) {
|
||||
for (var _ : strs) {
|
||||
}
|
||||
}
|
||||
TwoParams p1 = (_, _) -> {};
|
||||
TwoParams p2 = (var _, var _) -> {};
|
||||
TwoIntParams p3 = (int _, int b) -> {};
|
||||
TwoIntParams p4 = (int _, int _) -> {};
|
||||
TwoIntParamsIntRet p5 = (int _, int _) -> { return 1; };
|
||||
|
||||
p1.run(1, 2);
|
||||
p2.run(1, 2);
|
||||
p3.run(1, 2);
|
||||
p4.run(1, 2);
|
||||
p5.run(1, 2);
|
||||
|
||||
R r = new R(null);
|
||||
if (r instanceof R _) {}
|
||||
if (r instanceof R(_)) {}
|
||||
for (int _ = 0, _ = 1, x = 1; x <= 1 ; x++) {}
|
||||
}
|
||||
|
||||
int testMultiValuesTopLevel(Object o) {
|
||||
return switch (o) {
|
||||
case R1 _, R2 _ -> 1;
|
||||
default -> 2;
|
||||
};
|
||||
}
|
||||
|
||||
int testMultiValuesTopLevel2(Base o) {
|
||||
return switch (o) {
|
||||
case R1 r -> 1;
|
||||
case R2 _, R3 _, R4 _ -> 2;
|
||||
};
|
||||
}
|
||||
|
||||
int testMultiValuesNested(Box<?> b) {
|
||||
return switch (b) {
|
||||
case Box(R1 _), Box(R2 _) -> 1;
|
||||
case Box(R3 _) -> 2;
|
||||
case Box(_) -> 3;
|
||||
};
|
||||
}
|
||||
|
||||
int testMultiValuesNestedUnnamedVarAndPattern(Box<?> b) {
|
||||
return switch (b) {
|
||||
case Box(R1 _), Box(R2 _) -> 1;
|
||||
case Box(R3 _), Box(_) -> 2;
|
||||
};
|
||||
}
|
||||
|
||||
int testMultiValuesNestedMix(Object b) {
|
||||
return switch (b) {
|
||||
case Box(_), Box2(_) -> 1;
|
||||
default -> 2;
|
||||
};
|
||||
}
|
||||
|
||||
int testMultiValuesNestedMix2(Object b) {
|
||||
return switch (b) {
|
||||
case Box(_), String _ -> 1;
|
||||
default -> 2;
|
||||
};
|
||||
}
|
||||
|
||||
int testMultiValuesStatementBlock(Object o) {
|
||||
switch (o) {
|
||||
case Integer _:
|
||||
case Number _:
|
||||
return 1;
|
||||
default:
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
int testMultiValuesStatementBlock2(Object o) {
|
||||
switch (o) {
|
||||
case Box(_):
|
||||
case String _:
|
||||
return 1;
|
||||
default:
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
int testMultiValuesGuards(Base b, int x) {
|
||||
return switch (b) {
|
||||
case R1 r -> 1;
|
||||
case R2 _, R3 _, R4 _ when x == 1 -> 2;
|
||||
case R2 _, R3 _, R4 _ -> 3;
|
||||
};
|
||||
}
|
||||
|
||||
int testMultiValuesNestedGuards(Box<?> b, int x) {
|
||||
return switch (b) {
|
||||
case Box(R1 _), Box(R2 _) -> 1;
|
||||
case Box(R3 _), Box(_) when x == 1 -> 2;
|
||||
case Box(_) -> 3;
|
||||
};
|
||||
}
|
||||
|
||||
int testMixUnconditionalAndConditional(Base t) {
|
||||
return switch(t) {
|
||||
case R1 _ -> 1;
|
||||
case R2 _, Base _-> 2;
|
||||
};
|
||||
}
|
||||
|
||||
int testMultipleExpr(Box<?> t) {
|
||||
return switch(t) {
|
||||
case Box(R1 _), Box(R2 _) -> 1;
|
||||
default -> -2;
|
||||
};
|
||||
}
|
||||
|
||||
int testUnrolledExpr(Box<?> t) {
|
||||
return switch(t) {
|
||||
case Box(R1 _) -> 1;
|
||||
case Box(R2 _) -> 0;
|
||||
default -> -2;
|
||||
};
|
||||
}
|
||||
|
||||
int testMultipleStat(Box<?> t) {
|
||||
int ret = -1;
|
||||
switch(t) {
|
||||
case Box(R1 _), Box(R2 _):
|
||||
ret = 1;
|
||||
break;
|
||||
default:
|
||||
ret = -2;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int testUnrolledStat(Box<?> t) {
|
||||
int ret = -1;
|
||||
switch(t) {
|
||||
case Box(R1 _):
|
||||
ret = 1;
|
||||
break;
|
||||
case Box(R2 _):
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
ret = -2;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int testMixVarWithExplicit(Box<?> t) {
|
||||
int success = -1;
|
||||
success = switch(t) {
|
||||
case Box(R1 _) : {
|
||||
yield 1;
|
||||
}
|
||||
case Box(R2 _), Box(var _) : {
|
||||
yield 2;
|
||||
}
|
||||
default : {
|
||||
yield -2;
|
||||
}
|
||||
};
|
||||
return success;
|
||||
}
|
||||
|
||||
String unnamedGuardAddsBindings(Object o1, Object o2) {
|
||||
return switch (o1) {
|
||||
case String _, Object _ when o2 instanceof String s: yield s;
|
||||
case Object _: yield "any";
|
||||
};
|
||||
}
|
||||
|
||||
// JEP 443 examples
|
||||
record Point(int x, int y) { }
|
||||
enum Color { RED, GREEN, BLUE }
|
||||
record ColoredPoint(Point p, Color c) { }
|
||||
|
||||
void jep443examples(ColoredPoint r) {
|
||||
if (r instanceof ColoredPoint(Point(int x, int y), _)) { }
|
||||
if (r instanceof ColoredPoint(_, Color c)) { }
|
||||
if (r instanceof ColoredPoint(Point(int x, _), _)) { }
|
||||
if (r instanceof ColoredPoint(Point(int x, int _), Color _)) { }
|
||||
if (r instanceof ColoredPoint _) { }
|
||||
}
|
||||
|
||||
class Lock implements AutoCloseable {
|
||||
@Override
|
||||
public void close() {}
|
||||
}
|
||||
interface TwoParams {
|
||||
public void run(Object o1, Object o2);
|
||||
}
|
||||
interface TwoIntParams {
|
||||
public void run(int o1, int o2);
|
||||
}
|
||||
interface TwoIntParamsIntRet {
|
||||
public int run(int a, int b);
|
||||
}
|
||||
record R(Object o) {}
|
||||
|
||||
sealed abstract class Base permits R1, R2, R3, R4 { }
|
||||
final class R1 extends Base { }
|
||||
final class R2 extends Base { }
|
||||
final class R3 extends Base { }
|
||||
final class R4 extends Base { }
|
||||
record Box<T extends Base>(T content) { }
|
||||
record Box2<T extends Base>(T content) { }
|
||||
void assertEquals(Object expected, Object actual) {
|
||||
if (!Objects.equals(expected, actual)) {
|
||||
throw new AssertionError("Expected: " + expected + ", but got: " + actual);
|
||||
}
|
||||
}
|
||||
}
|
118
test/langtools/tools/javac/patterns/UnnamedErrors.java
Normal file
118
test/langtools/tools/javac/patterns/UnnamedErrors.java
Normal file
@ -0,0 +1,118 @@
|
||||
/**
|
||||
* @test /nodynamiccopyright/
|
||||
* @bug 8304246
|
||||
* @summary Compiler Implementation for Unnamed patterns and variables
|
||||
* @enablePreview
|
||||
* @compile/fail/ref=UnnamedErrors.out -XDrawDiagnostics -XDshould-stop.at=FLOW UnnamedErrors.java
|
||||
*/
|
||||
public class UnnamedErrors {
|
||||
private int _; // error
|
||||
private int _, x; // error
|
||||
private int x, _, y, _, z, _; // error
|
||||
private int _ = 0, _ = 1; // error
|
||||
private int a = 0, _ = 1; // error
|
||||
|
||||
record R(int _) {} //no record components
|
||||
UnnamedErrors(int _) {} //no constructor parameters
|
||||
void test(int _) {} //no method parameters
|
||||
|
||||
record RR(int x) {}
|
||||
void test2() {
|
||||
Object o = Integer.valueOf(42);
|
||||
if (o instanceof _) {} //no top level
|
||||
|
||||
if (o instanceof _(int x)) {} //no record pattern head
|
||||
|
||||
switch (o) {
|
||||
case _:
|
||||
System.out.println("no underscore top level");
|
||||
default:
|
||||
System.out.println("");
|
||||
}
|
||||
|
||||
switch (o) {
|
||||
case var _:
|
||||
System.out.println("no var _ top level");
|
||||
default:
|
||||
System.out.println("");
|
||||
}
|
||||
}
|
||||
|
||||
void dominanceError(Object o) {
|
||||
switch (o) {
|
||||
case Number _ ->
|
||||
System.out.println("A Number");
|
||||
case Integer _, String _ -> // Error - dominated case pattern: `Integer _`
|
||||
System.out.println("An Integer or a String");
|
||||
default ->
|
||||
System.out.println("rest");
|
||||
}
|
||||
}
|
||||
|
||||
void mixedNamedUnnamedError(Object o) {
|
||||
switch (o) {
|
||||
case Integer i, String _ ->
|
||||
System.out.println("named/unnamed");
|
||||
default ->
|
||||
System.out.println("rest");
|
||||
}
|
||||
|
||||
switch (o) {
|
||||
case Integer _, String s ->
|
||||
System.out.println("unnamed/named");
|
||||
default ->
|
||||
System.out.println("rest");
|
||||
}
|
||||
|
||||
switch (o) {
|
||||
case PairIS(_, _), String s ->
|
||||
System.out.println("unnamed patterns/named");
|
||||
default ->
|
||||
System.out.println("rest");
|
||||
}
|
||||
}
|
||||
|
||||
private void test1() {
|
||||
try (Lock _ = null) {
|
||||
} catch (_) { }
|
||||
}
|
||||
|
||||
int guardErrors(Object o, int x1, int x2) {
|
||||
return switch (o) {
|
||||
case Integer _ when x1 == 2, String _ when x2 == 1 -> 1;
|
||||
default -> 2;
|
||||
};
|
||||
}
|
||||
|
||||
int testMixVarWithExplicitDominanceError(Box<?> t) {
|
||||
int success = -1;
|
||||
success = switch(t) {
|
||||
case Box(var _), Box(R2 _) : {
|
||||
yield 1;
|
||||
}
|
||||
default : {
|
||||
yield -2;
|
||||
}
|
||||
};
|
||||
return success;
|
||||
}
|
||||
|
||||
void testUnderscoreWithoutInitializer() {
|
||||
int _;
|
||||
int x1 = 1, _, x2;
|
||||
|
||||
for (int x = 1, _; x<=1; x++) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class Lock implements AutoCloseable {
|
||||
@Override
|
||||
public void close() {}
|
||||
}
|
||||
record PairIS(int i, String s) {}
|
||||
sealed abstract class Base permits R1, R2 { }
|
||||
final class R1 extends Base { }
|
||||
final class R2 extends Base { }
|
||||
record Box<T extends Base>(T content) { }
|
||||
}
|
35
test/langtools/tools/javac/patterns/UnnamedErrors.out
Normal file
35
test/langtools/tools/javac/patterns/UnnamedErrors.out
Normal file
@ -0,0 +1,35 @@
|
||||
UnnamedErrors.java:9:17: compiler.err.use.of.underscore.not.allowed
|
||||
UnnamedErrors.java:10:17: compiler.err.use.of.underscore.not.allowed
|
||||
UnnamedErrors.java:11:20: compiler.err.use.of.underscore.not.allowed
|
||||
UnnamedErrors.java:11:26: compiler.err.use.of.underscore.not.allowed
|
||||
UnnamedErrors.java:11:32: compiler.err.use.of.underscore.not.allowed
|
||||
UnnamedErrors.java:12:17: compiler.err.use.of.underscore.not.allowed
|
||||
UnnamedErrors.java:12:24: compiler.err.use.of.underscore.not.allowed
|
||||
UnnamedErrors.java:13:24: compiler.err.use.of.underscore.not.allowed
|
||||
UnnamedErrors.java:15:18: compiler.err.use.of.underscore.not.allowed
|
||||
UnnamedErrors.java:16:23: compiler.err.use.of.underscore.not.allowed
|
||||
UnnamedErrors.java:17:19: compiler.err.use.of.underscore.not.allowed
|
||||
UnnamedErrors.java:22:26: compiler.err.use.of.underscore.not.allowed
|
||||
UnnamedErrors.java:24:26: compiler.err.use.of.underscore.not.allowed
|
||||
UnnamedErrors.java:27:18: compiler.err.use.of.underscore.not.allowed
|
||||
UnnamedErrors.java:34:18: compiler.err.restricted.type.not.allowed.here: var
|
||||
UnnamedErrors.java:77:18: compiler.err.use.of.underscore.not.allowed
|
||||
UnnamedErrors.java:77:19: compiler.err.expected: token.identifier
|
||||
UnnamedErrors.java:82:40: compiler.err.expected2: :, ->
|
||||
UnnamedErrors.java:82:51: compiler.err.expected: =
|
||||
UnnamedErrors.java:82:58: compiler.err.expected: ';'
|
||||
UnnamedErrors.java:101:14: compiler.err.expected: =
|
||||
UnnamedErrors.java:102:22: compiler.err.expected: =
|
||||
UnnamedErrors.java:104:26: compiler.err.expected: =
|
||||
UnnamedErrors.java:11:17: compiler.err.already.defined: kindname.variable, x, kindname.class, UnnamedErrors
|
||||
UnnamedErrors.java:36:13: compiler.err.unconditional.pattern.and.default
|
||||
UnnamedErrors.java:45:18: compiler.err.pattern.dominated
|
||||
UnnamedErrors.java:54:29: compiler.err.flows.through.from.pattern
|
||||
UnnamedErrors.java:61:29: compiler.err.flows.through.from.pattern
|
||||
UnnamedErrors.java:68:32: compiler.err.flows.through.from.pattern
|
||||
UnnamedErrors.java:82:56: compiler.err.already.defined: kindname.variable, x2, kindname.method, guardErrors(java.lang.Object,int,int)
|
||||
UnnamedErrors.java:83:13: compiler.err.switch.mixing.case.types
|
||||
UnnamedErrors.java:90:30: compiler.err.pattern.dominated
|
||||
- compiler.note.preview.filename: UnnamedErrors.java, DEFAULT
|
||||
- compiler.note.preview.recompile
|
||||
32 errors
|
@ -35,13 +35,7 @@
|
||||
|
||||
import java.util.Set;
|
||||
import javax.annotation.processing.*;
|
||||
import javax.lang.model.SourceVersion;
|
||||
import static javax.lang.model.SourceVersion.*;
|
||||
import javax.lang.model.element.*;
|
||||
import javax.lang.model.util.*;
|
||||
import static javax.lang.model.util.ElementFilter.*;
|
||||
import static javax.tools.Diagnostic.Kind.*;
|
||||
import static javax.tools.StandardLocation.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
|
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (c) 2023, 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
|
||||
* @bug 8302344 8307007
|
||||
* @summary Compiler Implementation for Unnamed patterns and variables
|
||||
* @library /tools/javac/lib
|
||||
* @modules jdk.compiler
|
||||
* @build JavacTestingAbstractProcessor
|
||||
* @enablePreview
|
||||
* @compile TestUnnamedVariableElement.java
|
||||
* @compile --enable-preview -source ${jdk.version} -processor TestUnnamedVariableElement -proc:only TestUnnamedVariableElementData.java
|
||||
*/
|
||||
|
||||
import javax.annotation.processing.*;
|
||||
import javax.lang.model.element.*;
|
||||
import javax.lang.model.util.Elements;
|
||||
import java.util.*;
|
||||
import com.sun.source.tree.*;
|
||||
import com.sun.source.util.*;
|
||||
import java.io.StringWriter;
|
||||
|
||||
public class TestUnnamedVariableElement extends JavacTestingAbstractProcessor implements AutoCloseable {
|
||||
|
||||
public boolean process(Set<? extends TypeElement> annotations,
|
||||
RoundEnvironment roundEnv) {
|
||||
if (!roundEnv.processingOver()) {
|
||||
Trees trees = Trees.instance(processingEnv);
|
||||
|
||||
for(Element rootElement : roundEnv.getRootElements()) {
|
||||
TreePath treePath = trees.getPath(rootElement);
|
||||
|
||||
(new UnnamedVariableScanner(processingEnv.getElementUtils(), trees)).
|
||||
scan(treePath.getCompilationUnit(), null);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {}
|
||||
|
||||
class UnnamedVariableScanner extends TreePathScanner<Void, Void> {
|
||||
|
||||
private final Elements elements;
|
||||
private Trees trees;
|
||||
|
||||
public UnnamedVariableScanner(Elements elements, Trees trees) {
|
||||
super();
|
||||
this.elements = elements;
|
||||
this.trees = trees;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitVariable(VariableTree node, Void unused) {
|
||||
handleTreeAsLocalVar(getCurrentPath());
|
||||
|
||||
if(!node.getName().isEmpty()) {
|
||||
throw new RuntimeException("Expected empty name as the name of the Tree API but got: " + node.getName());
|
||||
}
|
||||
|
||||
return super.visitVariable(node, unused);
|
||||
}
|
||||
|
||||
private void handleTreeAsLocalVar(TreePath tp) {
|
||||
VariableElement element = (VariableElement) trees.getElement(tp);
|
||||
|
||||
System.out.println("Name: " + element.getSimpleName() +
|
||||
"\tKind: " + element.getKind());
|
||||
if (element.getKind() != ElementKind.LOCAL_VARIABLE) {
|
||||
throw new RuntimeException("Expected a local variable, but got: " +
|
||||
element.getKind());
|
||||
}
|
||||
StringWriter out = new StringWriter();
|
||||
String expected = "int _;";
|
||||
elements.printElements(out, element);
|
||||
if (!expected.equals(out.toString().trim())) {
|
||||
throw new RuntimeException("Expected: " + expected + ", but got: " + out.toString());
|
||||
}
|
||||
testUnnamedVariable(element);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that a local variable modeled as an element behaves
|
||||
* as expected under 6 and latest specific visitors.
|
||||
*/
|
||||
private static void testUnnamedVariable(Element element) {
|
||||
ElementKindVisitor visitorLatest =
|
||||
new ElementKindVisitor<Object, Void>() {
|
||||
@Override
|
||||
public Object visitVariableAsLocalVariable(VariableElement e,
|
||||
Void p) {
|
||||
return e;
|
||||
}
|
||||
};
|
||||
|
||||
if (visitorLatest.visit(element) == null) {
|
||||
throw new RuntimeException("Null result of a resource variable visitation.");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (c) 2023, 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
|
||||
* @bug 8302344 8307007
|
||||
* @summary Compiler Implementation for Unnamed patterns and variables
|
||||
* @library /tools/javac/lib
|
||||
* @modules jdk.compiler
|
||||
* @build JavacTestingAbstractProcessor
|
||||
* @compile TestUnnamedVariableElement8.java
|
||||
* @compile -source 8 -processor TestUnnamedVariableElement8 -proc:only TestUnnamedVariableElementData.java
|
||||
*/
|
||||
|
||||
import com.sun.source.tree.VariableTree;
|
||||
import com.sun.source.util.TreePath;
|
||||
import com.sun.source.util.TreePathScanner;
|
||||
import com.sun.source.util.Trees;
|
||||
|
||||
import javax.annotation.processing.RoundEnvironment;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.ElementKind;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.element.VariableElement;
|
||||
import java.util.Set;
|
||||
|
||||
public class TestUnnamedVariableElement8 extends JavacTestingAbstractProcessor implements AutoCloseable {
|
||||
|
||||
public boolean process(Set<? extends TypeElement> annotations,
|
||||
RoundEnvironment roundEnv) {
|
||||
if (!roundEnv.processingOver()) {
|
||||
Trees trees = Trees.instance(processingEnv);
|
||||
|
||||
for(Element rootElement : roundEnv.getRootElements()) {
|
||||
TreePath treePath = trees.getPath(rootElement);
|
||||
|
||||
(new UnnamedVariableScanner(trees)).
|
||||
scan(treePath.getCompilationUnit(), null);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {}
|
||||
|
||||
class UnnamedVariableScanner extends TreePathScanner<Void, Void> {
|
||||
private Trees trees;
|
||||
|
||||
public UnnamedVariableScanner(Trees trees) {
|
||||
super();
|
||||
this.trees = trees;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitVariable(VariableTree node, Void unused) {
|
||||
handleTreeAsLocalVar(getCurrentPath());
|
||||
return super.visitVariable(node, unused);
|
||||
}
|
||||
|
||||
private void handleTreeAsLocalVar(TreePath tp) {
|
||||
Element element = trees.getElement(tp);
|
||||
|
||||
System.out.println("Name: " + element.getSimpleName() +
|
||||
"\tKind: " + element.getKind());
|
||||
if (element.getKind() != ElementKind.LOCAL_VARIABLE) {
|
||||
throw new RuntimeException("Expected a local variable, but got: " +
|
||||
element.getKind());
|
||||
}
|
||||
if (!element.getSimpleName().toString().equals("_")) {
|
||||
throw new RuntimeException("Expected _ for simple name of an unnamed variable, but got: " +
|
||||
element.getSimpleName());
|
||||
}
|
||||
testUnnamedVariable(element);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that a local variable modeled as an element behaves
|
||||
* as expected under 6 and latest specific visitors.
|
||||
*/
|
||||
private static void testUnnamedVariable(Element element) {
|
||||
ElementKindVisitor visitorLatest =
|
||||
new ElementKindVisitor<Object, Void>() {
|
||||
@Override
|
||||
public Object visitVariableAsLocalVariable(VariableElement e,
|
||||
Void p) {
|
||||
return e;
|
||||
}
|
||||
};
|
||||
|
||||
if (visitorLatest.visit(element) == null) {
|
||||
throw new RuntimeException("Null result of a resource variable visitation.");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2023, 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.
|
||||
*/
|
||||
|
||||
public class TestUnnamedVariableElementData {
|
||||
private void test() {
|
||||
int _ = 0;
|
||||
}
|
||||
}
|
@ -67,8 +67,6 @@ public class VarTree {
|
||||
"java.lang.String testVar");
|
||||
test.run("java.util.function.Consumer<String> c = (|var testVar|) -> {};",
|
||||
"java.lang.String testVar");
|
||||
test.run("java.util.function.IntBinaryOperator c = (var x, |testType|) -> 1;",
|
||||
"testType ");
|
||||
}
|
||||
|
||||
void run(String code, String expected) throws IOException {
|
||||
|
Loading…
x
Reference in New Issue
Block a user