use of org.eclipse.jdt.internal.compiler.lookup.InferenceContext18 in project bazel-jdt-java-toolchain by salesforce.
the class ASTNode method resolvePolyExpressionArguments.
/**
* After method lookup has produced 'methodBinding' but when poly expressions have been seen as arguments,
* inspect the arguments to trigger another round of resolving with improved target types from the methods parameters.
* If this resolving produces better types for any arguments, update the 'argumentTypes' array in-place as an
* intended side effect that will feed better type information in checkInvocationArguments() and others.
* @param invocation the outer invocation which is being resolved
* @param method the method produced by lookup (possibly involving type inference).
* @param argumentTypes the argument types as collected from first resolving the invocation arguments and as used for the method lookup.
* @param scope scope for resolution.
* @return either the original method or a problem method
*/
public static MethodBinding resolvePolyExpressionArguments(Invocation invocation, MethodBinding method, TypeBinding[] argumentTypes, BlockScope scope) {
MethodBinding candidateMethod = method.isValidBinding() ? method : method instanceof ProblemMethodBinding ? ((ProblemMethodBinding) method).closestMatch : null;
if (candidateMethod == null)
return method;
ProblemMethodBinding problemMethod = null;
boolean variableArity = candidateMethod.isVarargs();
final TypeBinding[] parameters = candidateMethod.parameters;
Expression[] arguments = invocation.arguments();
if (variableArity && arguments != null && parameters.length == arguments.length) {
if (arguments[arguments.length - 1].isCompatibleWith(parameters[parameters.length - 1], scope)) {
variableArity = false;
}
}
for (int i = 0, length = arguments == null ? 0 : arguments.length; i < length; i++) {
Expression argument = arguments[i];
TypeBinding parameterType = InferenceContext18.getParameter(parameters, i, variableArity);
if (parameterType == null)
// not much we can do without a target type, assume it only happens after some resolve error
continue;
if (argumentTypes[i] != null && argumentTypes[i].isPolyType()) {
argument.setExpectedType(parameterType);
TypeBinding updatedArgumentType;
if (argument instanceof LambdaExpression) {
LambdaExpression lambda = (LambdaExpression) argument;
// avoid complaining about non-kosher descriptor as secondary problem
boolean skipKosherCheck = method.problemId() == ProblemReasons.Ambiguous;
updatedArgumentType = lambda.resolveType(scope, skipKosherCheck);
// additional checks, because LE.resolveType may return a valid binding even in the presence of structural errors
if (lambda.hasErrors() || lambda.hasDescripterProblem) {
continue;
}
// avoid that preliminary local type bindings escape beyond this point:
lambda.updateLocalTypesInMethod(candidateMethod);
// refresh after update
parameterType = InferenceContext18.getParameter(parameters, i, variableArity);
if (!lambda.isCompatibleWith(parameterType, scope)) {
if (method.isValidBinding() && problemMethod == null) {
TypeBinding[] originalArguments = Arrays.copyOf(argumentTypes, argumentTypes.length);
if (lambda.reportShapeError(parameterType, scope)) {
problemMethod = new ProblemMethodBinding(candidateMethod, method.selector, originalArguments, ProblemReasons.ErrorAlreadyReported);
} else {
problemMethod = new ProblemMethodBinding(candidateMethod, method.selector, originalArguments, ProblemReasons.NotFound);
}
}
continue;
}
} else {
updatedArgumentType = argument.resolveType(scope);
}
if (updatedArgumentType != null && updatedArgumentType.kind() != Binding.POLY_TYPE) {
argumentTypes[i] = updatedArgumentType;
if (candidateMethod.isPolymorphic())
candidateMethod.parameters[i] = updatedArgumentType;
}
}
}
if (method.returnType instanceof ReferenceBinding) {
scope.referenceCompilationUnit().updateLocalTypesInMethod(method);
}
if (method instanceof ParameterizedGenericMethodBinding) {
InferenceContext18 ic18 = invocation.getInferenceContext((ParameterizedMethodBinding) method);
if (ic18 != null)
// overload resolution is done, now perform the push of bounds from inner to outer
ic18.flushBoundOutbox();
}
if (problemMethod != null)
return problemMethod;
return method;
}
use of org.eclipse.jdt.internal.compiler.lookup.InferenceContext18 in project bazel-jdt-java-toolchain by salesforce.
the class ConstraintExpressionFormula method reduce.
@Override
public Object reduce(InferenceContext18 inferenceContext) throws InferenceFailureException {
if (this.relation == POTENTIALLY_COMPATIBLE) {
return this.left.isPotentiallyCompatibleWith(this.right, inferenceContext.scope) ? TRUE : FALSE;
}
// JLS 18.2.1
if (this.right.isProperType(true)) {
if (this.left.isCompatibleWith(this.right, inferenceContext.scope) || this.left.isBoxingCompatibleWith(this.right, inferenceContext.scope)) {
if (this.left.resolvedType != null && this.left.resolvedType.needsUncheckedConversion(this.right)) {
inferenceContext.usesUncheckedConversion = true;
}
return TRUE;
}
return FALSE;
}
if (!canBePolyExpression(this.left)) {
TypeBinding exprType = this.left.resolvedType;
if (exprType == null || !exprType.isValidBinding()) {
if (this.left instanceof MessageSend && ((MessageSend) this.left).actualReceiverType instanceof InferenceVariable)
// nothing valuable to infer from this
return null;
return FALSE;
}
return ConstraintTypeFormula.create(exprType, this.right, COMPATIBLE, this.isSoft);
} else {
// - parenthesized expression : these are transparent in our AST
if (this.left instanceof Invocation) {
Invocation invocation = (Invocation) this.left;
MethodBinding previousMethod = invocation.binding();
if (// can happen, e.g., if inside a copied lambda with ignored errors
previousMethod == null)
// -> proceed with no new constraints
return null;
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
InferenceContext18 innerCtx = null;
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:
innerCtx = invocation.getInferenceContext((ParameterizedGenericMethodBinding) previousMethod);
if (innerCtx == null) {
/* No inference context -> the method was likely manufactured by Scope.findExactMethod -> assume it wasn't really poly after all.
-> proceed as for non-poly expressions.
*/
TypeBinding exprType = this.left.resolvedType;
if (exprType == null || !exprType.isValidBinding())
return FALSE;
return ConstraintTypeFormula.create(exprType, this.right, COMPATIBLE, this.isSoft);
}
if (innerCtx.stepCompleted >= InferenceContext18.APPLICABILITY_INFERRED) {
inferenceContext.integrateInnerInferenceB2(innerCtx);
} else {
// should not reach here.
return FALSE;
}
// b2 has been lifted, inferring poly invocation type amounts to lifting b3.
} else {
inferenceContext.inferenceKind = inferenceContext.getInferenceKind(previousMethod, argumentTypes);
boolean isDiamond = method.isConstructor() && this.left.isPolyExpression(method);
inferInvocationApplicability(inferenceContext, method, argumentTypes, isDiamond, inferenceContext.inferenceKind);
// b2 has been lifted, inferring poly invocation type amounts to lifting b3.
}
if (!inferenceContext.computeB3(invocation, this.right, method))
return FALSE;
// already incorporated
return null;
} finally {
inferenceContext.resumeSuspendedInference(prevInvocation, innerCtx);
}
} 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 SwitchExpression) {
SwitchExpression se = (SwitchExpression) this.left;
ConstraintFormula[] cfs = new ConstraintFormula[se.resultExpressions.size()];
int i = 0;
for (Expression re : se.resultExpressions) {
cfs[i++] = new ConstraintExpressionFormula(re, this.right, this.relation, this.isSoft);
}
return cfs;
} else if (this.left instanceof LambdaExpression) {
LambdaExpression lambda = (LambdaExpression) this.left;
BlockScope scope = lambda.enclosingScope;
if (this.right instanceof InferenceVariable)
// assume inner inference will handle the fine print
return TRUE;
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.resolveExpressionExpecting(t, inferenceContext.scope, inferenceContext);
if (lambda == null)
// not strictly unreduceable, but proceeding with TRUE would likely produce secondary errors
return FALSE;
if (functionType.returnType == TypeBinding.VOID) {
if (!lambda.isVoidCompatible())
return FALSE;
} else {
if (!lambda.isValueCompatible())
return FALSE;
}
List<ConstraintFormula> result = new ArrayList<>();
if (!lambda.argumentsTypeElided()) {
Argument[] arguments = lambda.arguments();
for (int i = 0; i < parameters.length; i++) result.add(ConstraintTypeFormula.create(parameters[i], arguments[i].type.resolvedType, 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 = lambda.resultExpressions();
for (int i = 0, length = exprs == null ? 0 : exprs.length; i < length; i++) {
Expression expr = exprs[i];
if (r.isProperType(true) && expr.resolvedType != null) {
TypeBinding exprType = expr.resolvedType;
// "not compatible in an assignment context with R"?
if (!(expr.isConstantValueOfTypeAssignableToType(exprType, r) || exprType.isCompatibleWith(r) || expr.isBoxingCompatible(exprType, r, expr, scope)))
return FALSE;
} else {
result.add(new ConstraintExpressionFormula(expr, r, COMPATIBLE, this.isSoft));
}
}
}
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);
}
}
return FALSE;
}
use of org.eclipse.jdt.internal.compiler.lookup.InferenceContext18 in project bazel-jdt-java-toolchain by salesforce.
the class ConstraintExpressionFormula method reduceReferenceExpressionCompatibility.
private Object reduceReferenceExpressionCompatibility(ReferenceExpression reference, InferenceContext18 inferenceContext) {
TypeBinding t = this.right;
if (t.isProperType(true))
// $NON-NLS-1$
throw new IllegalStateException("Should not reach here with T being a proper type");
if (!t.isFunctionalInterface(inferenceContext.scope))
return FALSE;
MethodBinding functionType = t.getSingleAbstractMethod(inferenceContext.scope, true);
if (functionType == null)
return FALSE;
// potentially-applicable method for the method reference when targeting T (15.13.1),
reference = reference.resolveExpressionExpecting(t, inferenceContext.scope, inferenceContext);
MethodBinding potentiallyApplicable = reference != null ? reference.binding : null;
if (potentiallyApplicable == null)
return FALSE;
if (reference.isExactMethodReference()) {
List<ConstraintFormula> newConstraints = new ArrayList<>();
TypeBinding[] p = functionType.parameters;
int n = p.length;
TypeBinding[] pPrime = potentiallyApplicable.parameters;
int k = pPrime.length;
int offset = 0;
if (n == k + 1) {
newConstraints.add(ConstraintTypeFormula.create(p[0], reference.lhs.resolvedType, COMPATIBLE));
offset = 1;
}
for (int i = offset; i < n; i++) newConstraints.add(ConstraintTypeFormula.create(p[i], pPrime[i - offset], COMPATIBLE));
TypeBinding r = functionType.returnType;
if (r != TypeBinding.VOID) {
TypeBinding rAppl = potentiallyApplicable.isConstructor() && !reference.isArrayConstructorReference() ? potentiallyApplicable.declaringClass : potentiallyApplicable.returnType;
if (rAppl == TypeBinding.VOID)
return FALSE;
TypeBinding rPrime = rAppl.capture(inferenceContext.scope, reference.sourceStart, reference.sourceEnd);
newConstraints.add(ConstraintTypeFormula.create(rPrime, r, COMPATIBLE));
}
return newConstraints.toArray(new ConstraintFormula[newConstraints.size()]);
} else {
// inexact
int n = functionType.parameters.length;
for (int i = 0; i < n; i++) if (!functionType.parameters[i].isProperType(true))
return FALSE;
// Otherwise, a search for a compile-time declaration is performed, as defined in 15.13.1....
// Note: we currently don't distinguish search for a potentially-applicable method from searching the compiler-time declaration,
// hence reusing the method binding from above
MethodBinding compileTimeDecl = potentiallyApplicable;
if (!compileTimeDecl.isValidBinding())
return FALSE;
TypeBinding r = functionType.isConstructor() ? functionType.declaringClass : functionType.returnType;
if (r.id == TypeIds.T_void)
return TRUE;
// ignore parameterization of resolve result and do a fresh start:
MethodBinding original = compileTimeDecl.shallowOriginal();
if (needsInference(reference, original)) {
TypeBinding[] argumentTypes;
if (t.isParameterizedType()) {
MethodBinding capturedFunctionType = ((ParameterizedTypeBinding) t).getSingleAbstractMethod(inferenceContext.scope, true, reference.sourceStart, reference.sourceEnd);
argumentTypes = capturedFunctionType.parameters;
} else {
argumentTypes = functionType.parameters;
}
SuspendedInferenceRecord prevInvocation = inferenceContext.enterPolyInvocation(reference, reference.createPseudoExpressions(argumentTypes));
// Invocation Applicability Inference: 18.5.1 & Invocation Type Inference: 18.5.2
InferenceContext18 innerContext = null;
try {
innerContext = reference.getInferenceContext((ParameterizedMethodBinding) compileTimeDecl);
if (innerContext != null)
innerContext.pushBoundsTo(inferenceContext);
int innerInferenceKind = determineInferenceKind(compileTimeDecl, argumentTypes, innerContext);
inferInvocationApplicability(inferenceContext, original, argumentTypes, original.isConstructor(), /*mimic a diamond?*/
innerInferenceKind);
if (!inferenceContext.computeB3(reference, r, original))
return FALSE;
// already incorporated
return null;
} catch (InferenceFailureException e) {
return FALSE;
} finally {
inferenceContext.resumeSuspendedInference(prevInvocation, innerContext);
}
}
TypeBinding rPrime = compileTimeDecl.isConstructor() ? compileTimeDecl.declaringClass : compileTimeDecl.returnType.capture(inferenceContext.scope, reference.sourceStart(), reference.sourceEnd());
if (rPrime.id == TypeIds.T_void)
return FALSE;
return ConstraintTypeFormula.create(rPrime, r, COMPATIBLE, this.isSoft);
}
}
Aggregations