Skip to content

Commit

Permalink
Remove left overs from implementing version 0.7.0 of the JSR 305 spec
Browse files Browse the repository at this point in the history
Fixes #818

Code changes:
- impl of JLS 18.5.3 refreshed from Java 19 spec
- small code unification towards PTB.getNonWildcardParameterization()

Test adjustments:
- fewer captures created cause different capture-names
- wildcards eliminated from some error messages
  • Loading branch information
stephan-herrmann committed Mar 8, 2023
1 parent d86e63a commit 0187a06
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,7 @@ private ReferenceBinding findGroundTargetType(BlockScope blockScope, TypeBinding
freshInferenceContext.cleanUp();
}
} else {
return findGroundTargetTypeForElidedLambda(blockScope, withWildCards);
return withWildCards.getNonWildcardParameterization(blockScope);
}
}
if (targetType instanceof ReferenceBinding)
Expand All @@ -542,15 +542,6 @@ private ReferenceBinding findGroundTargetType(BlockScope blockScope, TypeBinding
return null;
}

public ReferenceBinding findGroundTargetTypeForElidedLambda(BlockScope blockScope, ParameterizedTypeBinding withWildCards) {
// non-wildcard parameterization (9.8) of the target type
TypeBinding[] types = withWildCards.getNonWildcardParameterization(blockScope);
if (types == null)
return null;
ReferenceBinding genericType = withWildCards.genericType();
return blockScope.environment().createParameterizedType(genericType, types, withWildCards.enclosingType());
}

@Override
public boolean argumentsTypeElided() {
return (this.arguments.length > 0 && this.arguments[0].hasElidedType()) || this.argumentsTypeVar;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ public static ReferenceBinding findGroundTargetType(InferenceContext18 inference
LambdaExpression lambda, ParameterizedTypeBinding targetTypeWithWildCards)
{
if (lambda.argumentsTypeElided()) {
return lambda.findGroundTargetTypeForElidedLambda(scope, targetTypeWithWildCards);
return targetTypeWithWildCards.getNonWildcardParameterization(scope);
} else {
SuspendedInferenceRecord previous = inferenceContext.enterLambda(lambda);
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
import org.eclipse.jdt.internal.compiler.ast.LambdaExpression;
import org.eclipse.jdt.internal.compiler.ast.ReferenceExpression;
import org.eclipse.jdt.internal.compiler.ast.SwitchExpression;
import org.eclipse.jdt.internal.compiler.ast.Wildcard;
import org.eclipse.jdt.internal.compiler.lookup.TypeConstants.BoundCheckStatus;
import org.eclipse.jdt.internal.compiler.util.Sorting;

Expand Down Expand Up @@ -758,21 +757,37 @@ public ReferenceBinding inferFunctionalInterfaceParameterization(LambdaExpressio
{
TypeBinding[] q = createBoundsForFunctionalInterfaceParameterizationInference(targetTypeWithWildCards);
if (q == null || q.length != lambda.arguments().length) {
// fail TODO: can this still happen here?
return null;
} else {
if (reduceWithEqualityConstraints(lambda.argumentTypes(), q)) {
ReferenceBinding genericType = targetTypeWithWildCards.genericType();
TypeBinding[] a = targetTypeWithWildCards.arguments; // a is not-null by construction of parameterizedWithWildcard()
TypeBinding[] aprime = getFunctionInterfaceArgumentSolutions(a);
// If F<A'1, ..., A'm> is a well-formed type, ...
// If F<A'1, ..., A'm> is not a well-formed type, ...
ParameterizedTypeBinding ptb = blockScope.environment().createParameterizedType(genericType, aprime, targetTypeWithWildCards.enclosingType());
TypeVariableBinding[] vars = ptb.genericType().typeVariables();
ParameterizedTypeBinding captured = ptb.capture(blockScope, lambda.sourceStart, lambda.sourceEnd);
boolean hasWildcard = false;
for (int i = 0; i < vars.length; i++) {
if (vars[i].boundCheck(captured, aprime[i], blockScope, lambda) == BoundCheckStatus.MISMATCH)
return null;
if (vars[i].boundCheck(ptb, aprime[i], blockScope, lambda) == BoundCheckStatus.MISMATCH)
return null; // ... no valid parameterization exists
hasWildcard |= aprime[i].kind() == Binding.WILDCARD_TYPE;
}
/* as per spec we should do the following:
*
* // or if F<A'1, ..., A'm> is not a subtype of F<A1, ..., Am>
* if (!ptb.isSubtypeOf(targetTypeWithWildCards, false))
* return null; // ... no valid parameterization exists
*
* but that would surface as
* "The target type of this expression is not a well formed parameterized type due to bound(s) mismatch"
* whereas the ill-formed type only emerged during inference.
* So let final checks detect the incompatibility for a better error message.
*/
if (hasWildcard) {
return ptb.getNonWildcardParameterization(blockScope);
} else {
return ptb;
}
return ptb;
}
}
return targetTypeWithWildCards;
Expand All @@ -789,34 +804,16 @@ TypeBinding[] createBoundsForFunctionalInterfaceParameterizationInference(Parame
TypeBinding[] a = functionalInterface.arguments;
if (a == null)
return null;
InferenceVariable[] alpha = addInitialTypeVariableSubstitutions(a);

for (int i = 0; i < a.length; i++) {
TypeBound bound;
if (a[i].kind() == Binding.WILDCARD_TYPE) {
WildcardBinding wildcard = (WildcardBinding) a[i];
switch(wildcard.boundKind) {
case Wildcard.EXTENDS :
bound = new TypeBound(alpha[i], wildcard.allBounds(), ReductionResult.SUBTYPE);
break;
case Wildcard.SUPER :
bound = new TypeBound(alpha[i], wildcard.bound, ReductionResult.SUPERTYPE);
break;
case Wildcard.UNBOUND :
bound = new TypeBound(alpha[i], this.object, ReductionResult.SUBTYPE);
break;
default:
continue; // cannot
}
} else {
bound = new TypeBound(alpha[i], a[i], ReductionResult.SAME);
}
this.currentBounds.addBound(bound, this.environment);
}
addInitialTypeVariableSubstitutions(a);
TypeBinding falpha = substitute(functionalInterface);
return falpha.getSingleAbstractMethod(this.scope, true).parameters;
}

/**
* from 18.5.3:
* Otherwise, a set of constraint formulas is formed with, for all i (1 ≤ i ≤ n), ‹Pi = Qi›.
* This constraint formula set is reduced to form the bound set B.
*/
public boolean reduceWithEqualityConstraints(TypeBinding[] p, TypeBinding[] q) {
if (p != null) {
for (int i = 0; i < p.length; i++) {
Expand Down Expand Up @@ -1797,6 +1794,13 @@ public static ParameterizedTypeBinding parameterizedWithWildcard(TypeBinding typ
return null;
}

/**
* From 18.5.3:
* <ul>
* <li>If B contains an instantiation (§18.1.3) for αi, T, then A'i = T.
* <li>Otherwise, A'i = Ai.
* </ul>
*/
public TypeBinding[] getFunctionInterfaceArgumentSolutions(TypeBinding[] a) {
int m = a.length;
TypeBinding[] aprime = new TypeBinding[m];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1629,7 +1629,7 @@ public FieldBinding[] unResolvedFields() {
@Override
protected MethodBinding[] getInterfaceAbstractContracts(Scope scope, boolean replaceWildcards, boolean filterDefaultMethods) throws InvalidInputException {
if (replaceWildcards) {
TypeBinding[] types = getNonWildcardParameterization(scope);
TypeBinding[] types = getNonWildcardParameters(scope);
if (types == null)
return new MethodBinding[] { new ProblemMethodBinding(TypeConstants.ANONYMOUS_METHOD, null, ProblemReasons.NotAWellFormedParameterizedType) };
for (int i = 0; i < types.length; i++) {
Expand Down Expand Up @@ -1669,7 +1669,7 @@ public MethodBinding getSingleAbstractMethod(final Scope scope, boolean replaceW
ParameterizedTypeBinding declaringType = null;
TypeBinding [] types = this.arguments;
if (replaceWildcards) {
types = getNonWildcardParameterization(scope);
types = getNonWildcardParameters(scope);
if (types == null)
return this.singleAbstractMethod[index] = new ProblemMethodBinding(TypeConstants.ANONYMOUS_METHOD, null, ProblemReasons.NotAWellFormedParameterizedType);
} else if (types == null) {
Expand Down Expand Up @@ -1701,8 +1701,8 @@ public MethodBinding getSingleAbstractMethod(final Scope scope, boolean replaceW
return this.singleAbstractMethod[index];
}

// from JLS 9.8
public TypeBinding[] getNonWildcardParameterization(Scope scope) {
// from JLS 9.9
public TypeBinding[] getNonWildcardParameters(Scope scope) {
// precondition: isValidBinding()
TypeBinding[] typeArguments = this.arguments; // A1 ... An
if (typeArguments == null)
Expand Down Expand Up @@ -1770,6 +1770,16 @@ public TypeBinding[] getNonWildcardParameterization(Scope scope) {
}
return types;
}

public ReferenceBinding getNonWildcardParameterization(BlockScope blockScope) {
// non-wildcard parameterization (9.9) of the target type
TypeBinding[] types = getNonWildcardParameters(blockScope);
if (types == null)
return null;
ReferenceBinding genericType = genericType();
return blockScope.environment().createParameterizedType(genericType, types, enclosingType());
}

@Override
public long updateTagBits() {
if (this.arguments != null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2943,7 +2943,7 @@ public void testBug430296() {
"2. ERROR in AnnotationCollector.java (at line 9)\n" +
" return persons.collect(Collectors.toMap((Person p) -> p.getLastName(),\n" +
" ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
"Type mismatch: cannot convert from Function<Person,? extends K> to Function<? super T,? extends K>\n" +
"Type mismatch: cannot convert from Function<Person,K> to Function<? super T,? extends K>\n" +
"----------\n" +
"3. ERROR in AnnotationCollector.java (at line 10)\n" +
" Function::identity,\n" +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8601,12 +8601,12 @@ public void test428177() {
"4. ERROR in X.java (at line 36)\n" +
" if(\"1\" == \"\") { return stream.collect(Collectors.toList()).stream(); // ERROR\n" +
" ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
"Type mismatch: cannot convert from Stream<capture#24-of ? extends String> to Stream<String>\n" +
"Type mismatch: cannot convert from Stream<capture#14-of ? extends String> to Stream<String>\n" +
"----------\n" +
"5. ERROR in X.java (at line 38)\n" +
" return stream.collect(Collectors.toList()); // NO ERROR\n" +
" ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
"Type mismatch: cannot convert from List<capture#27-of ? extends String> to Stream<String>\n" +
"Type mismatch: cannot convert from List<capture#17-of ? extends String> to Stream<String>\n" +
"----------\n");
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=428795, - [1.8]Internal compiler error: java.lang.NullPointerException at org.eclipse.jdt.internal.compiler.ast.MessageSend.analyseCode
Expand Down Expand Up @@ -9884,7 +9884,7 @@ public void testGroundTargetTypeWithWithWildcards() {
"1. ERROR in X.java (at line 10)\n" +
" return m((X x1, X x2) -> { return new Y(); });\n" +
" ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" +
"Type mismatch: cannot convert from I<X,X,? extends C> to I<? extends A,? extends B,? extends C>\n" +
"Type mismatch: cannot convert from I<X,X,C> to I<? extends A,? extends B,? extends C>\n" +
"----------\n");
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=474522, [1.8][compiler] ecj doesn't handle captured final fields correctly in lambdas
Expand Down

0 comments on commit 0187a06

Please sign in to comment.