diff options
author | Stephan Herrmann | 2013-12-03 11:34:51 +0000 |
---|---|---|
committer | Stephan Herrmann | 2013-12-03 11:34:51 +0000 |
commit | a6234b6d34f70b04dc8086b5971307bab5f2f8ed (patch) | |
tree | a410eb9689a6c8a2365d9aa9b5b8635d8a3703ae | |
parent | 564744a51fe27e3b0533ebc8bf859ffbedefd30b (diff) | |
download | eclipse.jdt.core-a6234b6d34f70b04dc8086b5971307bab5f2f8ed.tar.gz eclipse.jdt.core-a6234b6d34f70b04dc8086b5971307bab5f2f8ed.tar.xz eclipse.jdt.core-a6234b6d34f70b04dc8086b5971307bab5f2f8ed.zip |
Draft impl of reduction for lambda constraints.
- based on some new API in LE
Improve LE.isPertinentToApplicability() to fix NLET.test401610d()
6 files changed, 80 insertions, 25 deletions
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java index 64b7a2379b..7de8492124 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/ConditionalExpression.java @@ -649,8 +649,9 @@ public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, this.expressionContext = context; } - public boolean isPertinentToApplicability(TypeBinding targetType) { - return this.valueIfTrue.isPertinentToApplicability(targetType) && this.valueIfFalse.isPertinentToApplicability(targetType); + public boolean isPertinentToApplicability(TypeBinding targetType, MethodBinding method) { + return this.valueIfTrue.isPertinentToApplicability(targetType, method) + && this.valueIfFalse.isPertinentToApplicability(targetType, method); } public boolean isPolyExpression() throws UnsupportedOperationException { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java index 66d19e6b7f..d8199823b0 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/ast/Expression.java @@ -949,7 +949,7 @@ public Constant optimizedBooleanConstant() { return this.constant; } -public boolean isPertinentToApplicability(TypeBinding targetType) { +public boolean isPertinentToApplicability(TypeBinding targetType, MethodBinding method) { return true; } 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 6feefbd72e..66e4c803e4 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 @@ -56,6 +56,7 @@ import org.eclipse.jdt.internal.compiler.lookup.TagBits; import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; import org.eclipse.jdt.internal.compiler.lookup.TypeIds; +import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding; import org.eclipse.jdt.internal.compiler.lookup.VariableBinding; import org.eclipse.jdt.internal.compiler.parser.Parser; import org.eclipse.jdt.internal.compiler.problem.AbortCompilation; @@ -108,6 +109,10 @@ public class LambdaExpression extends FunctionalExpression implements ReferenceC return this.body; } + public Expression[] resultExpressions() { + return this.resultExpressions; + } + public void setArrowPosition(int arrowPosition) { this.arrowPosition = arrowPosition; } @@ -443,32 +448,37 @@ public class LambdaExpression extends FunctionalExpression implements ReferenceC } } - public boolean isPertinentToApplicability(TypeBinding targetType) { - if (targetType == null) - return true; - - // Add the rule about type variable of the generic method. - - final MethodBinding sam = targetType.getSingleAbstractMethod(this.enclosingScope); // cached/cheap call. - - if (sam == null || !sam.isValidBinding()) - return true; - - if (sam.parameters.length != this.argumentTypes.length) + public boolean isPertinentToApplicability(TypeBinding targetType, MethodBinding method) { + if (targetType == null) // assumed to signal another primary error return true; if (argumentsTypeElided()) return false; + if (targetType instanceof TypeVariableBinding && ((TypeVariableBinding)targetType).declaringElement == method) + return false; + Expression [] returnExpressions = this.resultExpressions; for (int i = 0, length = returnExpressions.length; i < length; i++) { - if (!returnExpressions[i].isPertinentToApplicability(targetType)) + if (!returnExpressions[i].isPertinentToApplicability(targetType, method)) return false; } return true; } + public boolean isVoidCompatible() { + if (!this.shapeAnalysisComplete) + throw new IllegalStateException("asking isVoidCompatible before shape analysis is complete"); + return this.voidCompatible; + } + + public boolean isValueCompatible() { + if (!this.shapeAnalysisComplete) + throw new IllegalStateException("asking isValueCompatible before shape analysis is complete"); + return this.valueCompatible; + } + public StringBuffer printExpression(int tab, StringBuffer output) { int parenthesesCount = (this.bits & ASTNode.ParenthesizedMASK) >> ASTNode.ParenthesizedSHIFT; String suffix = ""; //$NON-NLS-1$ @@ -561,7 +571,7 @@ public class LambdaExpression extends FunctionalExpression implements ReferenceC } // Do not proceed with data/control flow analysis if resolve encountered errors. if (type == null || !type.isValidBinding() || this.hasIgnoredMandatoryErrors || enclosingScopesHaveErrors()) { - if (!isPertinentToApplicability(left)) + if (!isPertinentToApplicability(left, null)) // FIXME is null OK? return true; return this.arguments.length == 0; // error not because of the target type imposition, but is inherent. Just say compatible since errors in body aren't to influence applicability. } @@ -578,7 +588,7 @@ public class LambdaExpression extends FunctionalExpression implements ReferenceC } } - if (!isPertinentToApplicability(left)) + if (!isPertinentToApplicability(left, null)) // FIXME is null OK? return true; if (sam.returnType.id == TypeIds.T_void) { diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintExceptionFormula.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintExceptionFormula.java index 22bd7a7ca7..1bcb9b5988 100644 --- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintExceptionFormula.java +++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/ConstraintExceptionFormula.java @@ -67,7 +67,8 @@ public class ConstraintExceptionFormula extends ConstraintFormula { if (this.left instanceof LambdaExpression) { // TODO find exceptions thrown by the lambda's body // ((LambdaExpression)this.left). - InferenceContext18.missingImplementation("NYI"); +// InferenceContext18.missingImplementation("NYI"); + return TRUE; } else { ReferenceExpression referenceExpression = (ReferenceExpression)this.left; // TODO: can we avoid this resolve() (which in turn may invoke inference)? 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 b4d8ce281a..34926ed6b3 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 @@ -22,6 +22,7 @@ import java.util.List; import java.util.Set; import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.ast.Argument; import org.eclipse.jdt.internal.compiler.ast.ConditionalExpression; import org.eclipse.jdt.internal.compiler.ast.Expression; import org.eclipse.jdt.internal.compiler.ast.LambdaExpression; @@ -88,7 +89,49 @@ class ConstraintExpressionFormula extends ConstraintFormula { } else if (this.left instanceof ConditionalExpression) { InferenceContext18.missingImplementation("NYI"); } else if (this.left instanceof LambdaExpression) { - InferenceContext18.missingImplementation("NYI"); + LambdaExpression lambda = (LambdaExpression) this.left; + Scope scope = inferenceContext.scope; + TypeBinding t = this.right; + if (!t.isFunctionalInterface(scope)) + return FALSE; + MethodBinding functionType = t.getSingleAbstractMethod(scope); + if (functionType == null) + return FALSE; + TypeBinding[] parameters = functionType.parameters; + if (parameters.length != lambda.arguments().length) + return FALSE; + if (lambda.argumentsTypeElided()) + for (int i = 0; i < parameters.length; i++) + if (!parameters[i].isProperType(true)) + return FALSE; + // FIXME: force shape analysis: + lambda.isCompatibleWith(t, scope); + if (functionType.returnType == TypeBinding.VOID) { + if (!lambda.isVoidCompatible()) + return FALSE; + } else { + if (!lambda.isValueCompatible()) + return FALSE; + } + List result = new ArrayList(); + if (!lambda.argumentsTypeElided()) { + Argument[] arguments = lambda.arguments(); + for (int i = 0; i < parameters.length; i++) + result.add(new ConstraintTypeFormula(parameters[i], arguments[i].type.resolvedType, SAME)); + } + if (functionType.returnType != TypeBinding.VOID) { + TypeBinding r = functionType.returnType; + if (lambda.body() instanceof Expression) { + result.add(new ConstraintExpressionFormula((Expression)lambda.body(), r, COMPATIBLE)); + } else { + Expression[] exprs = lambda.resultExpressions(); + for (int i = 0; i < exprs.length; i++) + result.add(new ConstraintExpressionFormula(exprs[i], r, COMPATIBLE)); + } + } + if (result.size() == 0) + return TRUE; + return result.toArray(new ConstraintFormula[result.size()]); } else if (this.left instanceof ReferenceExpression) { return reduceReferenceExpressionCompatibility((ReferenceExpression) this.left, inferenceContext); } @@ -157,7 +200,7 @@ class ConstraintExpressionFormula extends ConstraintFormula { int varArgPos = paramLength-1; varArgsType = method.parameters[varArgPos]; } - inferenceContext.createInitialConstraintsForParameters(parameters, checkType==InferenceContext18.CHECK_VARARG, varArgsType); + inferenceContext.createInitialConstraintsForParameters(parameters, checkType==InferenceContext18.CHECK_VARARG, varArgsType, method); inferenceContext.addThrowsContraints(typeVariables, inferenceVariables, method.thrownExceptions); } 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 e6f383db6e..ade0bead61 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 @@ -100,7 +100,7 @@ public class InferenceContext18 { } /** JLS 18.5.1: compute bounds from formal and actual parameters. */ - public void createInitialConstraintsForParameters(TypeBinding[] parameters, boolean checkVararg, TypeBinding varArgsType) { + public void createInitialConstraintsForParameters(TypeBinding[] parameters, boolean checkVararg, TypeBinding varArgsType, MethodBinding method) { // TODO discriminate strict vs. loose invocations if (this.invocationArguments == null) return; @@ -116,7 +116,7 @@ public class InferenceContext18 { this.initialConstraints=new ConstraintFormula[maxConstraints], 0, numConstraints); } for (int i = 0; i < len; i++) { - if (this.invocationArguments[i].isPertinentToApplicability(parameters[i])) { + if (this.invocationArguments[i].isPertinentToApplicability(parameters[i], method)) { TypeBinding thetaF = substitute(parameters[i]); this.initialConstraints[numConstraints++] = new ConstraintExpressionFormula(this.invocationArguments[i], thetaF, ReductionResult.COMPATIBLE); } @@ -124,7 +124,7 @@ public class InferenceContext18 { if (checkVararg && varArgsType instanceof ArrayBinding) { TypeBinding thetaF = substitute(((ArrayBinding) varArgsType).elementsType()); for (int i = len; i < this.invocationArguments.length; i++) { - if (this.invocationArguments[i].isPertinentToApplicability(varArgsType)) { + if (this.invocationArguments[i].isPertinentToApplicability(varArgsType, method)) { this.initialConstraints[numConstraints++] = new ConstraintExpressionFormula(this.invocationArguments[i], thetaF, ReductionResult.COMPATIBLE); } } @@ -236,7 +236,7 @@ public class InferenceContext18 { TypeBinding fsi = fs[Math.min(i, p-1)]; TypeBinding substF = substitute(fsi); // For all i (1 ≤ i ≤ k), if ei is not pertinent to applicability, the set contains ⟨ei → θ Fi⟩. - if (!arguments[i].isPertinentToApplicability(fsi)) { + if (!arguments[i].isPertinentToApplicability(fsi, method)) { c.add(new ConstraintExpressionFormula(arguments[i], substF, ReductionResult.COMPATIBLE)); } c.add(new ConstraintExceptionFormula(arguments[i], substF)); |