Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parser changes for JEP 443 #1517

Merged
merged 1 commit into from
Jan 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
222 changes: 125 additions & 97 deletions org.eclipse.jdt.core.compiler.batch/grammar/java.g

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -2581,4 +2581,15 @@ public interface IProblem {
* @since 3.35
*/
int SyntheticAccessorNotEnclosingMethod = MethodRelated + 1990;

/**
* @since 3.37
* @noreference preview feature
*/
int UnderscoreCannotBeUsedHere = PreviewRelated + 2000;
/**
* @since 3.37
* @noreference preview feature
*/
int UnnamedVariableMustHaveInitializer = PreviewRelated + 2001;
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.ast;

import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.flow.FlowContext;
import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
Expand Down Expand Up @@ -144,4 +145,15 @@ public void setDepth(int depth) {
public void setFieldIndex(int depth) {
// do nothing by default
}

/**
* Returns true if this variable is an unnamed variable (_) and false otherwise.
*
* @param scope used to determine source level
*/
public boolean isUnnamed(BlockScope scope) {
return this.name.length == 1 && this.name[0] == '_'
&& scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK21
&& scope.compilerOptions().enablePreviewFeatures;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious - is the ("\\u005F".equals(this.name.toString()))) really required ? Won't the scanner internalize the unicode and return an '_' ??

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -116,19 +116,25 @@ private Annotation[] getCorrespondingRecordComponentAnnotationsIfApplicable(Abst
return null;
}
public TypeBinding bind(MethodScope scope, TypeBinding typeBinding, boolean used) {
if (this.isUnnamed(scope) && !scope.isLambdaScope()) {
scope.problemReporter().illegalUseOfUnderscoreAsAnIdentifier(this.sourceStart, this.sourceEnd, scope.compilerOptions().sourceLevel > ClassFileConstants.JDK1_8, true);
}

TypeBinding newTypeBinding = createBinding(scope, typeBinding); // basically a no-op if createBinding() was called before
datho7561 marked this conversation as resolved.
Show resolved Hide resolved

// record the resolved type into the type reference
Binding existingVariable = scope.getBinding(this.name, Binding.VARIABLE, this, false /*do not resolve hidden field*/);
if (existingVariable != null && existingVariable.isValidBinding()){
final boolean localExists = existingVariable instanceof LocalVariableBinding;
if (localExists && this.hiddenVariableDepth == 0) {
if ((this.bits & ASTNode.ShadowsOuterLocal) != 0 && scope.isLambdaSubscope()) {
scope.problemReporter().lambdaRedeclaresArgument(this);
} else if (scope.referenceContext instanceof CompactConstructorDeclaration) {
// skip error reporting - hidden params - already reported in record components
} else {
scope.problemReporter().redefineArgument(this);
if (!this.isUnnamed(scope)) {
if ((this.bits & ASTNode.ShadowsOuterLocal) != 0 && scope.isLambdaSubscope()) {
scope.problemReporter().lambdaRedeclaresArgument(this);
} else if (scope.referenceContext instanceof CompactConstructorDeclaration) {
// skip error reporting - hidden params - already reported in record components
} else {
scope.problemReporter().redefineArgument(this);
}
}
} else {
boolean isSpecialArgument = false;
Expand Down Expand Up @@ -234,7 +240,7 @@ public TypeBinding resolveForCatch(BlockScope scope) {
}
}
Binding existingVariable = scope.getBinding(this.name, Binding.VARIABLE, this, false /*do not resolve hidden field*/);
if (existingVariable != null && existingVariable.isValidBinding()){
if (existingVariable != null && existingVariable.isValidBinding() && !isUnnamed(scope)) {
if (existingVariable instanceof LocalVariableBinding && this.hiddenVariableDepth == 0) {
scope.problemReporter().redefineArgument(this);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,10 @@ public StringBuilder printStatement(int indent, StringBuilder output) {
}

public void resolve(MethodScope initializationScope) {
if (this.isUnnamed(initializationScope)) {
initializationScope.problemReporter().illegalUseOfUnderscoreAsAnIdentifier(this.sourceStart, this.sourceEnd, initializationScope.compilerOptions().sourceLevel > ClassFileConstants.JDK1_8, true);
}

// the two <constant = Constant.NotAConstant> could be regrouped into
// a single line but it is clearer to have two lines while the reason of their
// existence is not at all the same. See comment for the second one.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,24 @@
import java.util.Set;

import org.eclipse.jdt.internal.compiler.ASTVisitor;
import org.eclipse.jdt.internal.compiler.impl.*;
import org.eclipse.jdt.internal.compiler.ast.TypeReference.AnnotationCollector;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.codegen.*;
import org.eclipse.jdt.internal.compiler.flow.*;
import org.eclipse.jdt.internal.compiler.lookup.*;
import org.eclipse.jdt.internal.compiler.codegen.AnnotationContext;
import org.eclipse.jdt.internal.compiler.codegen.CodeStream;
import org.eclipse.jdt.internal.compiler.flow.FlowContext;
import org.eclipse.jdt.internal.compiler.flow.FlowInfo;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.impl.Constant;
import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
import org.eclipse.jdt.internal.compiler.lookup.Binding;
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
import org.eclipse.jdt.internal.compiler.lookup.ExtraCompilerModifiers;
import org.eclipse.jdt.internal.compiler.lookup.LocalVariableBinding;
import org.eclipse.jdt.internal.compiler.lookup.Scope;
import org.eclipse.jdt.internal.compiler.lookup.TagBits;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeBindingVisitor;
import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
import org.eclipse.jdt.internal.compiler.parser.RecoveryScanner;

public class LocalDeclaration extends AbstractVariableDeclaration {
Expand Down Expand Up @@ -139,7 +151,6 @@ public void checkModifiers() {
*/
@Override
public void generateCode(BlockScope currentScope, CodeStream codeStream) {

// even if not reachable, variable must be added to visible if allocated (28298)
if (this.binding.resolvedPosition != -1) {
codeStream.addVisibleLocalVariable(this.binding);
Expand Down Expand Up @@ -260,10 +271,13 @@ private static Expression findPolyExpression(Expression e) {
public void resolve(BlockScope scope) {
resolve(scope, false);
}
public void resolve(BlockScope scope, boolean isPatternVariable) {
// prescan NNBD
public void resolve(BlockScope scope, boolean isPatternVariable) { // prescan NNBD
handleNonNullByDefault(scope, this.annotations, this);

if (!isPatternVariable && (this.bits & ASTNode.IsForeachElementVariable) == 0 && this.initialization == null && this.isUnnamed(scope)) {
scope.problemReporter().unnamedVariableMustHaveInitializer(this);
}

TypeBinding variableType = null;
boolean variableTypeInferenceError = false;
boolean isTypeNameVar = isTypeNameVar(scope);
Expand Down Expand Up @@ -301,7 +315,7 @@ public void resolve(BlockScope scope, boolean isPatternVariable) {
}

Binding existingVariable = scope.getBinding(this.name, Binding.VARIABLE, this, false /*do not resolve hidden field*/);
if (existingVariable != null && existingVariable.isValidBinding()){
if (existingVariable != null && existingVariable.isValidBinding() && !this.isUnnamed(scope)) {
boolean localExists = existingVariable instanceof LocalVariableBinding;
if (localExists && (this.bits & ASTNode.ShadowsOuterLocal) != 0 && scope.isLambdaSubscope() && this.hiddenVariableDepth == 0) {
scope.problemReporter().lambdaRedeclaresLocal(this);
Expand Down Expand Up @@ -488,7 +502,9 @@ public void traverse(ASTVisitor visitor, BlockScope scope) {
for (int i = 0; i < annotationsLength; i++)
this.annotations[i].traverse(visitor, scope);
}
this.type.traverse(visitor, scope);
if (this.type != null) {
this.type.traverse(visitor, scope);
}
if (this.initialization != null)
this.initialization.traverse(visitor, scope);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ public abstract class Pattern extends Expression {

public int nestingLevel = 0;

// denotes index of this pattern in the parent record pattern, or -1 for patterns whose parent is not a record pattern
public int index = -1;

@Override
datho7561 marked this conversation as resolved.
Show resolved Hide resolved
public boolean containsPatternVariable() {
class PatternVariablesVisitor extends ASTVisitor {
Expand All @@ -50,7 +53,7 @@ class PatternVariablesVisitor extends ASTVisitor {
@Override
public boolean visit(TypePattern typePattern, BlockScope blockScope) {
this.hasPatternVar = typePattern.local != null;
this.typeElidedVar |= typePattern.getType().isTypeNameVar(blockScope);
this.typeElidedVar |= typePattern.getType() == null || typePattern.getType().isTypeNameVar(blockScope);
return !(this.hasPatternVar && this.typeElidedVar);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ private void setAccessorsPlusInfuseInferredType(BlockScope scope) {
continue;
TypePattern tp = (TypePattern) p;
datho7561 marked this conversation as resolved.
Show resolved Hide resolved
RecordComponentBinding componentBinding = components[i];
if (p.getType().isTypeNameVar(scope)) {
if (p.getType() == null || p.getType().isTypeNameVar(scope)) {
infuseInferredType(scope, tp, componentBinding);
if (tp.local.binding != null) // rewrite with the inferred type
tp.local.binding.type = componentBinding.type;
Expand Down Expand Up @@ -216,14 +216,26 @@ private boolean shouldInitiateRecordTypeInference() {
return this.resolvedType != null && this.resolvedType.isRawType();
}
private void infuseInferredType(Scope currentScope, TypePattern tp, RecordComponentBinding componentBinding) {
SingleTypeReference ref = new SingleTypeReference(tp.local.type.getTypeName()[0],
tp.local.type.sourceStart,
tp.local.type.sourceEnd) {
@Override
public TypeBinding resolveType(BlockScope scope, boolean checkBounds) {
return componentBinding.type;
}
};
SingleTypeReference ref;
if (tp.local.type == null) {
ref = new SingleTypeReference("var".toCharArray(), //$NON-NLS-1$
tp.local.sourceStart,
tp.local.sourceEnd) {
@Override
public TypeBinding resolveType(BlockScope scope, boolean checkBounds) {
return componentBinding.type;
}
};
} else {
ref = new SingleTypeReference(tp.local.type.getTypeName()[0],
tp.local.type.sourceStart,
tp.local.type.sourceEnd) {
@Override
public TypeBinding resolveType(BlockScope scope, boolean checkBounds) {
return componentBinding.type;
}
};
}
tp.local.type = ref;
if (componentBinding.type != null && (componentBinding.tagBits & TagBits.HasMissingType) != 0) {
currentScope.problemReporter().invalidType(ref, componentBinding.type);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ public class TypePattern extends Pattern {

public LocalDeclaration local;
Expression expression;
public int index = -1; // denoting position

public TypePattern(LocalDeclaration local) {
this.local = local;
Expand All @@ -51,7 +50,7 @@ public TypeReference getType() {
}
@Override
public LocalVariableBinding[] bindingsWhenTrue() {
return this.local != null && this.local.binding != null ?
return this.local != null && this.local.binding != null && !this.local.isUnnamed(this.local.binding.declaringScope) ?
new LocalVariableBinding[] { this.local.binding } : NO_VARIABLES;
}
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public enum JavaFeature {
new char[][] {},
false),
UNNAMMED_PATTERNS_AND_VARS(ClassFileConstants.JDK21,
Messages.bind(Messages.unnammed_patterns_and_vars),
Messages.bind(Messages.unnamed_patterns_and_vars),
new char[][] {},
true),
UNNAMMED_CLASSES_AND_INSTANCE_MAIN_METHODS(ClassFileConstants.JDK21,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,8 @@ void computeLocalVariablePositions(int ilocal, int initOffset, CodeStream codeSt
// do not report fake used variable
if (local.useFlag == LocalVariableBinding.UNUSED
&& (local.declaration != null) // unused (and non secret) local
&& ((local.declaration.bits & ASTNode.IsLocalDeclarationReachable) != 0)) { // declaration is reachable
&& ((local.declaration.bits & ASTNode.IsLocalDeclarationReachable) != 0) // declaration is reachable
&& !local.declaration.isUnnamed(local.declaringScope)) {

if (local.isCatchParameter()) {
problemReporter().unusedExceptionParameter(local.declaration); // report unused catch arguments
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,6 @@ records = Records
sealed_types = Sealed Types
pattern_matching_switch = Pattern Matching in Switch
record_patterns = Record Pattern
unnammed_patterns_and_vars = Unnammed Patterns and Variables
unnamed_patterns_and_vars = Unnamed Patterns and Variables
unnamed_classes_and_instance_main_methods = Unnamed Classes and Instance Main Methods
string_templates = String Template
Loading
Loading