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

Looks into indirect types during compilation #2543

Merged
merged 16 commits into from
Jul 11, 2024
Merged
Show file tree
Hide file tree
Changes from 7 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
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2000, 2023 IBM Corporation and others.
* Copyright (c) 2000, 2024 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand Down Expand Up @@ -4485,7 +4485,7 @@ public int generateMethodInfoAttributes(MethodBinding methodBinding) {
}
}
if ((methodBinding.tagBits & TagBits.HasMissingType) != 0) {
this.missingTypes = methodBinding.collectMissingTypes(this.missingTypes);
this.missingTypes = methodBinding.collectMissingTypes(this.missingTypes, true);
}
return attributesNumber;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2000, 2015 IBM Corporation and others.
* Copyright (c) 2000, 2024 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand Down Expand Up @@ -208,6 +208,9 @@ public TypeBinding resolveType(BlockScope scope) {
&& ((CastExpression)this.receiver).innermostCastedExpression() instanceof NullLiteral) {
this.receiver.bits |= ASTNode.DisableUnnecessaryCastCheck; // will check later on
}
if (this.receiver instanceof MessageSend) {
((MessageSend) this.receiver).isReceiver = true;
}
TypeBinding arrayType = this.receiver.resolveType(scope);
if (arrayType != null) {
this.receiver.computeConversion(scope, arrayType, arrayType);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2000, 2018 IBM Corporation and others.
* Copyright (c) 2000, 2024 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand Down Expand Up @@ -661,6 +661,9 @@ public TypeBinding resolveType(BlockScope scope) {
this.receiver.bits |= ASTNode.DisableUnnecessaryCastCheck; // will check later on
receiverCast = true;
}
if (this.receiver instanceof MessageSend) {
((MessageSend) this.receiver).isReceiver = true;
}
this.actualReceiverType = this.receiver.resolveType(scope);
if (this.actualReceiverType == null) {
this.constant = Constant.NotAConstant;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2000, 2017 IBM Corporation and others.
* Copyright (c) 2000, 2024 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
Expand Down Expand Up @@ -69,6 +69,8 @@ public void resolveTypeExpecting(BlockScope scope, TypeBinding requiredType) {
this.compilerElementPair = new ElementValuePair(this.name, this.value, this.binding);
return;
}
// the following is not really useful, but let's humor the resolution even if value is not a constant
this.value.setExpressionContext(ExpressionContext.ASSIGNMENT_CONTEXT);
if (requiredType == null) {
// fault tolerance: keep resolving
if (this.value instanceof ArrayInitializer) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ public class MessageSend extends Expression implements IPolyExpression, Invocati
public TypeReference[] typeArguments;
public TypeBinding[] genericTypeArguments;
public ExpressionContext expressionContext = VANILLA_CONTEXT;
public boolean isReceiver = false;

// hold on to this context from invocation applicability inference until invocation type inference (per method candidate):
private SimpleLookupTable/*<PGMB,InferenceContext18>*/ inferenceContexts;
Expand Down Expand Up @@ -811,6 +812,9 @@ public TypeBinding resolveType(BlockScope scope) {
if (this.receiver instanceof CastExpression) {
this.receiver.bits |= ASTNode.DisableUnnecessaryCastCheck; // will check later on
}
if (this.receiver instanceof MessageSend) {
((MessageSend) this.receiver).isReceiver = true;
}
this.actualReceiverType = this.receiver.resolveType(scope);
if (this.actualReceiverType instanceof InferenceVariable) {
return null; // not yet ready for resolving
Expand Down Expand Up @@ -995,7 +999,7 @@ public TypeBinding resolveType(BlockScope scope) {
this.binding = scope.environment().updatePolymorphicMethodReturnType((PolymorphicMethodBinding) this.binding, TypeBinding.VOID);
}
}
if ((this.binding.tagBits & TagBits.HasMissingType) != 0) {
if ((this.binding.tagBits & TagBits.HasMissingType) != 0 && isMissingTypeRelevant()) {
scope.problemReporter().missingTypeInMethod(this, this.binding);
}
if (!this.binding.isStatic()) {
Expand Down Expand Up @@ -1112,6 +1116,25 @@ protected boolean isUnnecessaryReceiverCast(BlockScope scope, TypeBinding uncast
|| MethodVerifier.doesMethodOverride(otherMethod, this.binding, scope.environment());
}

protected boolean isMissingTypeRelevant() {
if (this.expressionContext == ExpressionContext.VANILLA_CONTEXT && !this.isReceiver) {
if (this.binding.collectMissingTypes(null, false) == null)
return false; // only irrelevant return type is missing
}
if ((this.binding.returnType.tagBits & TagBits.HasMissingType) == 0
&& this.binding.isVarargs()) {
if (this.arguments.length < this.binding.parameters.length) {
// are all but the irrelevant varargs type present?
for (int i = 0; i < this.arguments.length; i++) {
if ((this.binding.parameters[i].tagBits & TagBits.HasMissingType) != 0)
return true; // this one *is* relevant
}
return false;
}
}
return true;
}

protected TypeBinding handleNullnessCodePatterns(BlockScope scope, TypeBinding returnType) {
// j.u.s.Stream.filter() may modify nullness of stream elements:
if (this.binding.isWellknownMethod(TypeConstants.JAVA_UTIL_STREAM__STREAM, TypeConstants.FILTER)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1951,33 +1951,39 @@ MethodBinding resolveTypesFor(MethodBinding method) {

if ((method.modifiers & ExtraCompilerModifiers.AccUnresolved) == 0)
return method;
boolean tolerateSave = this.environment.mayTolerateMissingType;
this.environment.mayTolerateMissingType |= this.environment.globalOptions.complianceLevel >= ClassFileConstants.JDK1_8; // tolerance only implemented for 1.8+
try {

if (!method.isConstructor()) {
TypeBinding resolvedType = resolveType(method.returnType, this.environment, true /* raw conversion */);
method.returnType = resolvedType;
if ((resolvedType.tagBits & TagBits.HasMissingType) != 0) {
method.tagBits |= TagBits.HasMissingType;
if (!method.isConstructor()) {
TypeBinding resolvedType = resolveType(method.returnType, this.environment, true /* raw conversion */);
method.returnType = resolvedType;
if ((resolvedType.tagBits & TagBits.HasMissingType) != 0) {
method.tagBits |= TagBits.HasMissingType;
}
}
}
for (int i = method.parameters.length; --i >= 0;) {
TypeBinding resolvedType = resolveType(method.parameters[i], this.environment, true /* raw conversion */);
method.parameters[i] = resolvedType;
if ((resolvedType.tagBits & TagBits.HasMissingType) != 0) {
method.tagBits |= TagBits.HasMissingType;
for (int i = method.parameters.length; --i >= 0;) {
TypeBinding resolvedType = resolveType(method.parameters[i], this.environment, true /* raw conversion */);
method.parameters[i] = resolvedType;
if ((resolvedType.tagBits & TagBits.HasMissingType) != 0) {
method.tagBits |= TagBits.HasMissingType;
}
}
}
for (int i = method.thrownExceptions.length; --i >= 0;) {
ReferenceBinding resolvedType = (ReferenceBinding) resolveType(method.thrownExceptions[i], this.environment, true /* raw conversion */);
method.thrownExceptions[i] = resolvedType;
if ((resolvedType.tagBits & TagBits.HasMissingType) != 0) {
method.tagBits |= TagBits.HasMissingType;
for (int i = method.thrownExceptions.length; --i >= 0;) {
ReferenceBinding resolvedType = (ReferenceBinding) resolveType(method.thrownExceptions[i], this.environment, true /* raw conversion */);
method.thrownExceptions[i] = resolvedType;
if ((resolvedType.tagBits & TagBits.HasMissingType) != 0) {
method.tagBits |= TagBits.HasMissingType;
}
}
for (int i = method.typeVariables.length; --i >= 0;) {
method.typeVariables[i].resolve();
}
method.modifiers &= ~ExtraCompilerModifiers.AccUnresolved;
return method;
} finally {
this.environment.mayTolerateMissingType = tolerateSave;
}
for (int i = method.typeVariables.length; --i >= 0;) {
method.typeVariables[i].resolve();
}
method.modifiers &= ~ExtraCompilerModifiers.AccUnresolved;
return method;
}
@Override
AnnotationBinding[] retrieveAnnotations(Binding binding) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,7 @@ private boolean addConstraintsToC_OneExpr(Expression expri, Set<ConstraintFormul
protected int getInferenceKind(MethodBinding nonGenericMethod, TypeBinding[] argumentTypes) {
switch (this.scope.parameterCompatibilityLevel(nonGenericMethod, argumentTypes)) {
case Scope.AUTOBOX_COMPATIBLE:
case Scope.NEEDS_MISSING_TYPE: // if in doubt the method with missing types should be accepted to signal its relevance for resolution
return CHECK_LOOSE;
case Scope.VARARGS_COMPATIBLE:
return CHECK_VARARG;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -413,9 +413,11 @@ public final boolean canBeSeenBy(TypeBinding receiverType, InvocationSite invoca
return false;
}

public List<TypeBinding> collectMissingTypes(List<TypeBinding> missingTypes) {
public List<TypeBinding> collectMissingTypes(List<TypeBinding> missingTypes, boolean considerReturnType) {
if ((this.tagBits & TagBits.HasMissingType) != 0) {
missingTypes = this.returnType.collectMissingTypes(missingTypes);
if (considerReturnType) {
missingTypes = this.returnType.collectMissingTypes(missingTypes);
}
for (TypeBinding parameter : this.parameters) {
missingTypes = parameter.collectMissingTypes(missingTypes);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ public static MethodBinding computeCompatibleMethod(MethodBinding originalMethod
ParameterizedGenericMethodBinding substitute = inferFromArgumentTypes(scope, originalMethod, arguments, parameters, inferenceContext);
if (substitute != null && substitute.returnType.isCompatibleWith(expectedType)) {
// Do not use the new solution if it results in incompatibilities in parameter types
if ((scope.parameterCompatibilityLevel(substitute, arguments, false)) > Scope.NOT_COMPATIBLE) {
if ((scope.parameterCompatibilityLevel(substitute, arguments, false)) > Scope.NOT_COMPATIBLE) { // don't worry about NEEDS_MISSING_TYPE in 1.7 context
methodSubstitute = substitute;
} else {
inferenceContext = oldContext;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,5 @@ public interface ProblemReasons {
final int InterfaceMethodInvocationNotBelow18 = 29;
final int NotAccessible = 30; // JLS 6.6.1 - module aspects
final int ErrorAlreadyReported = 31;
final int MissingTypeInSignature = 32;
}
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ public char[] readableName() {
public final static int COMPATIBLE = 0;
public final static int AUTOBOX_COMPATIBLE = 1;
public final static int VARARGS_COMPATIBLE = 2;
public final static int NEEDS_MISSING_TYPE = -2;

/* Type Compatibilities */
public static final int EQUAL_OR_MORE_SPECIFIC = -1;
Expand Down Expand Up @@ -871,13 +872,16 @@ protected final MethodBinding computeCompatibleMethod(MethodBinding method, Type
}


if ((parameterCompatibilityLevel(method, arguments, tiebreakingVarargsMethods)) > NOT_COMPATIBLE) {
int level = parameterCompatibilityLevel(method, arguments, tiebreakingVarargsMethods);
if (level > NOT_COMPATIBLE) {
if (method.hasPolymorphicSignature(this)) {
// generate polymorphic method and set polymorphic tagbits as well
method.tagBits |= TagBits.AnnotationPolymorphicSignature;
return this.environment().createPolymorphicMethod(method, arguments, this);
}
return method;
} else if (level == NEEDS_MISSING_TYPE) {
return new ProblemMethodBinding(method, method.selector, method.parameters, ProblemReasons.MissingTypeInSignature);
}
// if method is generic and type arguments have been supplied, only then answer a problem
// of ParameterizedMethodTypeMismatch, else a non-generic method was invoked using type arguments
Expand Down Expand Up @@ -1764,6 +1768,8 @@ public MethodBinding findMethod0(ReferenceBinding receiverType, char[] selector,
if (candidatesCount == 0)
candidates = new MethodBinding[foundSize];
candidates[candidatesCount++] = compatibleMethod;
} else if (compatibleMethod.problemId() == ProblemReasons.MissingTypeInSignature) {
return compatibleMethod; // use this method for error message to give a hint about the missing type
} else if (problemMethod == null) {
problemMethod = compatibleMethod;
}
Expand Down Expand Up @@ -2495,6 +2501,8 @@ public MethodBinding getConstructor0(ReferenceBinding receiverType, TypeBinding[
if (compatibleMethod != null) {
if (compatibleMethod.isValidBinding())
compatible[compatibleIndex++] = compatibleMethod;
else if (compatibleMethod.problemId() == ProblemReasons.MissingTypeInSignature)
return compatibleMethod; // use this method for error message to give a hint about the missing type
else if (problemMethod == null)
problemMethod = compatibleMethod;
}
Expand Down Expand Up @@ -4648,6 +4656,10 @@ protected final MethodBinding mostSpecificMethodBinding(MethodBinding[] visible,
int compatibleCount = 0;
for (int i = 0; i < visibleSize; i++)
if ((compatibilityLevels[i] = parameterCompatibilityLevel(visible[i], argumentTypes, invocationSite)) != NOT_COMPATIBLE) {
if (compatibilityLevels[i] == NEEDS_MISSING_TYPE) {
// cannot conclusively select any candidate, use the method with missing types in the error message
return new ProblemMethodBinding(visible[i], visible[i].selector, visible[i].parameters, ProblemReasons.Ambiguous);
}
if (i != compatibleCount) {
visible[compatibleCount] = visible[i];
compatibilityLevels[compatibleCount] = compatibilityLevels[i];
Expand Down Expand Up @@ -5144,13 +5156,17 @@ public int parameterCompatibilityLevel(MethodBinding method, TypeBinding[] argum
TypeBinding param = ((ArrayBinding) parameters[lastIndex]).elementsType();
for (int i = lastIndex; i < argLength; i++) {
TypeBinding arg = (tiebreakingVarargsMethods && (i == (argLength - 1))) ? ((ArrayBinding)arguments[i]).elementsType() : arguments[i];
if (TypeBinding.notEquals(param, arg) && parameterCompatibilityLevel(arg, param, env, tiebreakingVarargsMethods, method) == NOT_COMPATIBLE)
return NOT_COMPATIBLE;
if (TypeBinding.notEquals(param, arg)) {
level = parameterCompatibilityLevel(arg, param, env, tiebreakingVarargsMethods, method);
if (level == NOT_COMPATIBLE)
stephan-herrmann marked this conversation as resolved.
Show resolved Hide resolved
return NOT_COMPATIBLE;
}
stephan-herrmann marked this conversation as resolved.
Show resolved Hide resolved
}
} else if (lastIndex != argLength) { // can call foo(int i, X ... x) with foo(1) but NOT foo();
return NOT_COMPATIBLE;
}
level = VARARGS_COMPATIBLE; // varargs support needed
if (level != NEEDS_MISSING_TYPE) // preserve any NEEDS_MISSING_TYPE
level = VARARGS_COMPATIBLE; // varargs support needed
}
} else if (paramLength != argLength) {
return NOT_COMPATIBLE;
Expand All @@ -5161,9 +5177,9 @@ public int parameterCompatibilityLevel(MethodBinding method, TypeBinding[] argum
TypeBinding arg = (tiebreakingVarargsMethods && (i == (argLength - 1))) ? ((ArrayBinding)arguments[i]).elementsType() : arguments[i];
if (TypeBinding.notEquals(arg,param)) {
int newLevel = parameterCompatibilityLevel(arg, param, env, tiebreakingVarargsMethods, method);
if (newLevel == NOT_COMPATIBLE)
return NOT_COMPATIBLE;
if (newLevel > level)
if (newLevel < COMPATIBLE)
return newLevel;
if (newLevel > level && level != NEEDS_MISSING_TYPE) // preserve any NEEDS_MISSING_TYPE
level = newLevel;
}
}
Expand Down Expand Up @@ -5193,6 +5209,8 @@ private int parameterCompatibilityLevel(TypeBinding arg, TypeBinding param, Look
// only called if env.options.sourceLevel >= ClassFileConstants.JDK1_5
if (arg == null || param == null)
return NOT_COMPATIBLE;
if ((param.tagBits & TagBits.HasMissingType) != 0)
return NEEDS_MISSING_TYPE;
stephan-herrmann marked this conversation as resolved.
Show resolved Hide resolved
if (arg instanceof PolyTypeBinding && !((PolyTypeBinding) arg).expression.isPertinentToApplicability(param, method)) {
if (arg.isPotentiallyCompatibleWith(param, this))
return COMPATIBLE;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4164,6 +4164,10 @@ public void invalidConstructor(Statement statement, MethodBinding targetConstruc
problemConstructor = (ProblemMethodBinding) targetConstructor;
contradictoryNullAnnotationsInferred(problemConstructor.closestMatch, statement);
return;
case ProblemReasons.MissingTypeInSignature:
problemConstructor = (ProblemMethodBinding) targetConstructor;
missingTypeInConstructor(statement, problemConstructor.closestMatch);
return;
case ProblemReasons.NoError : // 0
default :
needImplementation(statement); // want to fail to see why we were here...
Expand Down Expand Up @@ -4785,6 +4789,10 @@ public void invalidMethod(MessageSend messageSend, MethodBinding method, Scope s
problemMethod = (ProblemMethodBinding) method;
contradictoryNullAnnotationsInferred(problemMethod.closestMatch, messageSend);
return;
case ProblemReasons.MissingTypeInSignature:
problemMethod = (ProblemMethodBinding) method;
missingTypeInMethod(messageSend, problemMethod.closestMatch);
return;
case ProblemReasons.NoError : // 0
default :
needImplementation(messageSend); // want to fail to see why we were here...
Expand Down Expand Up @@ -6943,7 +6951,7 @@ public void missingSynchronizedOnInheritedMethod(MethodBinding currentMethod, Me
currentMethod.sourceEnd());
}
public void missingTypeInConstructor(ASTNode location, MethodBinding constructor) {
List<TypeBinding> missingTypes = constructor.collectMissingTypes(null);
List<TypeBinding> missingTypes = constructor.collectMissingTypes(null, true);
if (missingTypes == null) {
System.err.println("The constructor " + constructor + " is wrongly tagged as containing missing types"); //$NON-NLS-1$ //$NON-NLS-2$
return;
Expand Down Expand Up @@ -6976,7 +6984,7 @@ public void missingTypeInConstructor(ASTNode location, MethodBinding constructor
public void missingTypeInLambda(LambdaExpression lambda, MethodBinding method) {
int nameSourceStart = lambda.sourceStart();
int nameSourceEnd = lambda.diagnosticsSourceEnd();
List<TypeBinding> missingTypes = method.collectMissingTypes(null);
List<TypeBinding> missingTypes = method.collectMissingTypes(null, true);
if (missingTypes == null) {
System.err.println("The lambda expression " + method + " is wrongly tagged as containing missing types"); //$NON-NLS-1$ //$NON-NLS-2$
return;
Expand All @@ -7003,7 +7011,7 @@ public void missingTypeInMethod(ASTNode astNode, MethodBinding method) {
nameSourceStart = astNode.sourceStart;
nameSourceEnd = astNode.sourceEnd;
}
List<TypeBinding> missingTypes = method.collectMissingTypes(null);
List<TypeBinding> missingTypes = method.collectMissingTypes(null, true);
if (missingTypes == null) {
System.err.println("The method " + method + " is wrongly tagged as containing missing types"); //$NON-NLS-1$ //$NON-NLS-2$
return;
Expand Down
Loading
Loading