diff options
author | Stephan Herrmann | 2014-02-22 00:52:39 +0000 |
---|---|---|
committer | Stephan Herrmann | 2014-02-22 15:32:08 +0000 |
commit | 8bffc680730baeb75a0764c02d5d9479eee4502e (patch) | |
tree | a8cd90fbdb8671a95a0964e849c8ec8838ca35ff | |
parent | a2a25daab3f792071cba7e3d51c3d2abf00c6c2a (diff) | |
download | eclipse.jdt.core-8bffc680730baeb75a0764c02d5d9479eee4502e.tar.gz eclipse.jdt.core-8bffc680730baeb75a0764c02d5d9479eee4502e.tar.xz eclipse.jdt.core-8bffc680730baeb75a0764c02d5d9479eee4502e.zip |
Bug 428786 - [1.8][compiler] Inference needs to compute the "ground
target type" when reducing a lambda compatibility constraint
- preparatory refactoring
3 files changed, 100 insertions, 80 deletions
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java index 8ac877d10f..377e41f1f2 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/LambdaExpression.java @@ -31,6 +31,7 @@ * Bug 420525 - [1.8] [compiler] Incorrect error "The type Integer does not define sum(Object, Object) that is applicable here" * Bug 427438 - [1.8][compiler] NPE at org.eclipse.jdt.internal.compiler.ast.ConditionalExpression.generateCode(ConditionalExpression.java:280) * Bug 428294 - [1.8][compiler] Type mismatch: cannot convert from List<Object> to Collection<Object[]> + * Bug 428786 - [1.8][compiler] Inference needs to compute the "ground target type" when reducing a lambda compatibility constraint * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for * Bug 405104 - [1.8][compiler][codegen] Implement support for serializeable lambdas *******************************************************************************/ @@ -128,6 +129,10 @@ public class LambdaExpression extends FunctionalExpression implements ReferenceC return this.arguments; } + public TypeBinding[] argumentTypes() { + return this.argumentTypes; + } + public void setBody(Statement body) { this.body = body == null ? NO_BODY : body; } @@ -414,32 +419,23 @@ public class LambdaExpression extends FunctionalExpression implements ReferenceC return null; ParameterizedTypeBinding withWildCards = InferenceContext18.parameterizedWithWildcard(targetType); if (withWildCards != null) { - ReferenceBinding genericType = withWildCards.genericType(); - if (!argumentTypesElided) { - // invoke 18.5.3 Functional Interface Parameterization Inference - InferenceContext18 ctx = new InferenceContext18(blockScope); - TypeBinding[] q = ctx.createBoundsForFunctionalInterfaceParameterizationInference(withWildCards); - if (q == null || q.length != this.arguments.length) { - // fail TODO: can this still happen here? - } else { - if (ctx.reduceWithEqualityConstraints(this.argumentTypes, q)) { - TypeBinding[] a = withWildCards.arguments; // a is not-null by construction of parameterizedWithWildcard() - TypeBinding[] aprime = ctx.getFunctionInterfaceArgumentSolutions(a); - // TODO If F<A'1, ..., A'm> is a well-formed type, ... - return blockScope.environment().createParameterizedType(genericType, aprime, genericType.enclosingType()); - } - } - } else { - // non-wildcard parameterization (9.8) of the target type - TypeBinding[] types = withWildCards.getNonWildcardParameterization(blockScope); - if (types == null) - return null; - return blockScope.environment().createParameterizedType(genericType, types, genericType.enclosingType()); - } + if (!argumentTypesElided) + return new InferenceContext18(blockScope).inferFunctionalInterfaceParameterization(this, blockScope, withWildCards); + else + return findGroundTargetTypeForElidedLambda(blockScope, withWildCards); } return targetType; } + 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, genericType.enclosingType()); + } + public boolean argumentsTypeElided() { return this.arguments.length > 0 && this.arguments[0].hasElidedType(); } diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintExpressionFormula.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintExpressionFormula.java index 147833153d..4140548a6e 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintExpressionFormula.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintExpressionFormula.java @@ -33,7 +33,7 @@ import org.eclipse.jdt.internal.compiler.ast.LambdaExpression; import org.eclipse.jdt.internal.compiler.ast.ReferenceExpression; import org.eclipse.jdt.internal.compiler.ast.ReturnStatement; import org.eclipse.jdt.internal.compiler.ast.Statement; -import org.eclipse.jdt.internal.compiler.lookup.InferenceContext18.InvocationRecord; +import org.eclipse.jdt.internal.compiler.lookup.InferenceContext18.SuspendedInferenceRecord; /** * Implementation of 18.1.2 in JLS8, case: @@ -114,7 +114,7 @@ class ConstraintExpressionFormula extends ConstraintFormula { // avoid original(), since we only want to discard one level of instantiation // (method type variables - not class type variables)! method = previousMethod.shallowOriginal(); - InvocationRecord prevInvocation = inferenceContext.enterPolyInvocation(invocation, invocation.arguments()); + SuspendedInferenceRecord prevInvocation = inferenceContext.enterPolyInvocation(invocation, invocation.arguments()); // Invocation Applicability Inference: 18.5.1 & Invocation Type Inference: 18.5.2 try { @@ -282,7 +282,7 @@ class ConstraintExpressionFormula extends ConstraintFormula { && ((original.typeVariables() != Binding.NO_TYPE_VARIABLES && r.mentionsAny(original.typeVariables(), -1)) || (original.isConstructor() && original.declaringClass.typeVariables() != Binding.NO_TYPE_VARIABLES && r.mentionsAny(original.declaringClass.typeVariables(), -1)))) { - InvocationRecord prevInvocation = inferenceContext.enterPolyInvocation(reference, null/*no invocation arguments available*/); + SuspendedInferenceRecord prevInvocation = inferenceContext.enterPolyInvocation(reference, null/*no invocation arguments available*/); // Invocation Applicability Inference: 18.5.1 & Invocation Type Inference: 18.5.2 try { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java index 0cd9f4d311..eaae4c3ffd 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/InferenceContext18.java @@ -204,12 +204,12 @@ public class InferenceContext18 { public static final int CHECK_LOOSE = 2; public static final int CHECK_VARARG = 3; - static class InvocationRecord { + static class SuspendedInferenceRecord { InvocationSite site; Expression[] invocationArguments; InferenceVariable[] inferenceVariables; int inferenceKind; - InvocationRecord(InvocationSite site, Expression[] invocationArguments, InferenceVariable[] inferenceVariables, int inferenceKind) { + SuspendedInferenceRecord(InvocationSite site, Expression[] invocationArguments, InferenceVariable[] inferenceVariables, int inferenceKind) { this.site = site; this.invocationArguments = invocationArguments; this.inferenceVariables = inferenceVariables; @@ -596,6 +596,80 @@ public class InferenceContext18 { } /** + * 18.5.3 Functional Interface Parameterization Inference + */ + public ReferenceBinding inferFunctionalInterfaceParameterization(LambdaExpression lambda, BlockScope blockScope, + ParameterizedTypeBinding targetTypeWithWildCards) + { + TypeBinding[] q = createBoundsForFunctionalInterfaceParameterizationInference(targetTypeWithWildCards); + if (q == null || q.length != lambda.arguments().length) { + // fail TODO: can this still happen here? + } 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); + // TODO If F<A'1, ..., A'm> is a well-formed type, ... + return blockScope.environment().createParameterizedType(genericType, aprime, genericType.enclosingType()); + } + } + return targetTypeWithWildCards; + } + + /** + * Create initial bound set for 18.5.3 Functional Interface Parameterization Inference + * @param functionalInterface the functional interface F<A1,..Am> + * @return the parameter types Q1..Qk of the function type of the type F<α1, ..., αm>, or null + */ + TypeBinding[] createBoundsForFunctionalInterfaceParameterizationInference(ParameterizedTypeBinding functionalInterface) { + if (this.currentBounds == null) + this.currentBounds = new BoundSet(); + 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); + } + TypeBinding falpha = substitute(functionalInterface); + return falpha.getSingleAbstractMethod(this.scope, true).parameters; + } + + public boolean reduceWithEqualityConstraints(TypeBinding[] p, TypeBinding[] q) { + if (p != null) { + for (int i = 0; i < p.length; i++) { + try { + if (!this.reduceAndIncorporate(new ConstraintTypeFormula(p[i], q[i], ReductionResult.SAME))) + return false; + } catch (InferenceFailureException e) { + return false; + } + } + } + return true; + } + + /** * 18.5.4 More Specific Method Inference */ public boolean isMoreSpecificThan(MethodBinding m1, MethodBinding m2, boolean isVarArgs, boolean isVarArgs2) { @@ -1260,8 +1334,8 @@ public class InferenceContext18 { return types; } - public InvocationRecord enterPolyInvocation(InvocationSite invocation, Expression[] innerArguments) { - InvocationRecord record = new InvocationRecord(this.currentInvocation, this.invocationArguments, this.inferenceVariables, this.inferenceKind); + public SuspendedInferenceRecord enterPolyInvocation(InvocationSite invocation, Expression[] innerArguments) { + SuspendedInferenceRecord record = new SuspendedInferenceRecord(this.currentInvocation, this.invocationArguments, this.inferenceVariables, this.inferenceKind); this.inferenceVariables = null; this.invocationArguments = innerArguments; this.currentInvocation = invocation; @@ -1271,7 +1345,7 @@ public class InferenceContext18 { return record; } - public void leavePolyInvocation(InvocationRecord record) { + public void leavePolyInvocation(SuspendedInferenceRecord record) { // merge inference variables: if (this.inferenceVariables == null) { // no new ones, assume we aborted prematurely this.inferenceVariables = record.inferenceVariables; @@ -1530,56 +1604,6 @@ public class InferenceContext18 { return null; } - /** - * Create initial bound set for 18.5.3 Functional Interface Parameterization Inference - * @param functionalInterface the functional interface F<A1,..Am> - * @return the parameter types Q1..Qk of the function type of the type F<α1, ..., αm>, or null - */ - public TypeBinding[] createBoundsForFunctionalInterfaceParameterizationInference(ParameterizedTypeBinding functionalInterface) { - this.currentBounds = new BoundSet(); - 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); - } - TypeBinding falpha = substitute(functionalInterface); - return falpha.getSingleAbstractMethod(this.scope, true).parameters; - } - - public boolean reduceWithEqualityConstraints(TypeBinding[] p, TypeBinding[] q) { - for (int i = 0; i < p.length; i++) { - try { - if (!this.reduceAndIncorporate(new ConstraintTypeFormula(p[i], q[i], ReductionResult.SAME))) - return false; - } catch (InferenceFailureException e) { - return false; - } - } - return true; - } - public TypeBinding[] getFunctionInterfaceArgumentSolutions(TypeBinding[] a) { int m = a.length; TypeBinding[] aprime = new TypeBinding[m]; |