// if we get here for some kinds of poly expressions (incl. ConditionalExpression),
// then other ways for checking compatibility are needed:
if (this.left instanceof FunctionalExpression) {
if (this.left instanceof LambdaExpression) {
// cf. NegativeLambdaExpressionTest.test412453()
LambdaExpression copy = ((LambdaExpression) this.left).getResolvedCopyForInferenceTargeting(this.right);
return (copy != null && copy.resolvedType != null && copy.resolvedType.isValidBinding()) ? TRUE : FALSE;
}
}
return this.left.isCompatibleWith(this.right, inferenceContext.scope) ? TRUE : FALSE;
} else if (!exprType.isValidBinding()) {
return FALSE;
}
if (isCompatibleWithInLooseInvocationContext(exprType, this.right, inferenceContext)) {
return TRUE;
} else if (this.left instanceof AllocationExpression && this.left.isPolyExpression()) {
// half-resolved diamond has a resolvedType, but that may not be the final word, try one more step of resolution:
MethodBinding binding = ((AllocationExpression) this.left).binding(this.right, false, null);
return (binding != null && binding.declaringClass.isCompatibleWith(this.right, inferenceContext.scope)) ? TRUE : FALSE;
} else if (this.left instanceof Invocation && this.left.isPolyExpression()) {
Invocation invoc = (Invocation) this.left;
MethodBinding binding = invoc.binding(this.right, false, null);
if (binding instanceof ParameterizedGenericMethodBinding) {
ParameterizedGenericMethodBinding method = (ParameterizedGenericMethodBinding) binding;
InferenceContext18 leftCtx = invoc.getInferenceContext(method);
if (leftCtx.stepCompleted < InferenceContext18.TYPE_INFERRED) {
break proper; // fall through into nested inference below (not explicit in the spec!)
}
}
}
return FALSE;
}
if (!canBePolyExpression(this.left)) {
TypeBinding exprType = this.left.resolvedType;
if (exprType == null || !exprType.isValidBinding())
return FALSE;
return ConstraintTypeFormula.create(exprType, this.right, COMPATIBLE, this.isSoft);
} else {
// shapes of poly expressions (18.2.1)
// - parenthesized expression : these are transparent in our AST
if (this.left instanceof Invocation) {
Invocation invocation = (Invocation) this.left;
MethodBinding previousMethod = invocation.binding(this.right, false, null);
if (previousMethod == null) // can happen, e.g., if inside a copied lambda with ignored errors
return null; // -> proceed with no new constraints
MethodBinding method = previousMethod;
// ignore previous (inner) inference result and do a fresh start:
// avoid original(), since we only want to discard one level of instantiation
// (method type variables - not class type variables)!
method = previousMethod.shallowOriginal();
SuspendedInferenceRecord prevInvocation = inferenceContext.enterPolyInvocation(invocation, invocation.arguments());
// Invocation Applicability Inference: 18.5.1 & Invocation Type Inference: 18.5.2
try {
Expression[] arguments = invocation.arguments();
TypeBinding[] argumentTypes = arguments == null ? Binding.NO_PARAMETERS : new TypeBinding[arguments.length];
for (int i = 0; i < argumentTypes.length; i++)
argumentTypes[i] = arguments[i].resolvedType;
if (previousMethod instanceof ParameterizedGenericMethodBinding) {
// find the previous inner inference context to see what inference kind this invocation needs:
InferenceContext18 innerCtx = invocation.getInferenceContext((ParameterizedGenericMethodBinding) previousMethod);
if (innerCtx == null) { // no inference -> assume it wasn't really poly after all
TypeBinding exprType = this.left.resolvedType;
if (exprType == null || !exprType.isValidBinding())
return FALSE;
return ConstraintTypeFormula.create(exprType, this.right, COMPATIBLE, this.isSoft);
}
inferenceContext.inferenceKind = innerCtx.inferenceKind;
innerCtx.outerContext = inferenceContext;
}
boolean isDiamond = method.isConstructor() && this.left.isPolyExpression(method);
inferInvocationApplicability(inferenceContext, method, argumentTypes, isDiamond, inferenceContext.inferenceKind);
if (!inferPolyInvocationType(inferenceContext, invocation, this.right, method))
return FALSE;
return null; // already incorporated
} finally {
inferenceContext.resumeSuspendedInference(prevInvocation);
}
} else if (this.left instanceof ConditionalExpression) {
ConditionalExpression conditional = (ConditionalExpression) this.left;
return new ConstraintFormula[] {
new ConstraintExpressionFormula(conditional.valueIfTrue, this.right, this.relation, this.isSoft),
new ConstraintExpressionFormula(conditional.valueIfFalse, this.right, this.relation, this.isSoft)
};
} else if (this.left instanceof LambdaExpression) {
LambdaExpression lambda = (LambdaExpression) this.left;
BlockScope scope = lambda.enclosingScope;
if (!this.right.isFunctionalInterface(scope))
return FALSE;
ReferenceBinding t = (ReferenceBinding) this.right;
ParameterizedTypeBinding withWildCards = InferenceContext18.parameterizedWithWildcard(t);
if (withWildCards != null) {
t = findGroundTargetType(inferenceContext, scope, lambda, withWildCards);
}
if (t == null)
return FALSE;
MethodBinding functionType = t.getSingleAbstractMethod(scope, true);
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;
lambda = lambda.getResolvedCopyForInferenceTargeting(t);
if (lambda == null)
return FALSE; // not strictly unreduceable, but proceeding with TRUE would likely produce secondary errors
if (functionType.returnType == TypeBinding.VOID) {
if (!lambda.isVoidCompatible())
return FALSE;
} else {
if (!lambda.isValueCompatible())
return FALSE;
}
List<ConstraintFormula> result = new ArrayList<ConstraintFormula>();
if (!lambda.argumentsTypeElided()) {
Argument[] arguments = lambda.arguments();
for (int i = 0; i < parameters.length; i++)
result.add(ConstraintTypeFormula.create(parameters[i], arguments[i].type.resolveType(lambda.enclosingScope), SAME));
// in addition, ⟨T' <: T⟩:
if (lambda.resolvedType != null)
result.add(ConstraintTypeFormula.create(lambda.resolvedType, this.right, SUBTYPE));
}
if (functionType.returnType != TypeBinding.VOID) {
TypeBinding r = functionType.returnType;
Expression[] exprs;
if (lambda.body() instanceof Expression) {
exprs = new Expression[] {(Expression)lambda.body()};
} else {
exprs = lambda.resultExpressions();
}
for (int i = 0; i < exprs.length; i++) {
Expression expr = exprs[i];
if (r.isProperType(true) && expr.resolvedType != null) {
TypeBinding exprType = expr.resolvedType;