Skip to content

Commit

Permalink
WIP: Looks into indirect types during compilation
Browse files Browse the repository at this point in the history
fixes eclipse-jdt#543

+ tolerate missing types during BTB.resolveTypesFor(MethodBinding)
+ new parameterCompatibilityLevel NEED_MISSING_TYPE
+ when NEED_MISSING_TYPE is encountered during resolution
  answer ProblemMethodBinding(ProblemReason.MissingTypeInSignature)
+ for varargs invocation try to discern if a missing type is relevant

Tests:
+ adjust expected secondary errors (neither is better than the other)

TODO:
+ check all call paths into parameterCompatibilityLevel()
+ fields
  • Loading branch information
stephan-herrmann committed Jun 9, 2024
1 parent 7a95d70 commit a8edd5e
Show file tree
Hide file tree
Showing 9 changed files with 269 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -999,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 @@ -1096,6 +1096,21 @@ public TypeBinding resolveType(BlockScope scope) {
: null;
}

protected boolean isMissingTypeRelevant() {
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 = true;
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 @@ -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 @@ -4644,6 +4652,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 @@ -5157,8 +5169,8 @@ 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 < COMPATIBLE)
return newLevel;
if (newLevel > level)
level = newLevel;
}
Expand Down Expand Up @@ -5189,6 +5201,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;
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
Loading

0 comments on commit a8edd5e

Please sign in to comment.