Search in sources :

Example 1 with InferenceContext18

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;
}
Also used : InferenceContext18(org.eclipse.jdt.internal.compiler.lookup.InferenceContext18) ProblemMethodBinding(org.eclipse.jdt.internal.compiler.lookup.ProblemMethodBinding) SourceTypeBinding(org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding) TypeBinding(org.eclipse.jdt.internal.compiler.lookup.TypeBinding) ParameterizedGenericMethodBinding(org.eclipse.jdt.internal.compiler.lookup.ParameterizedGenericMethodBinding) ProblemMethodBinding(org.eclipse.jdt.internal.compiler.lookup.ProblemMethodBinding) MethodBinding(org.eclipse.jdt.internal.compiler.lookup.MethodBinding) ParameterizedMethodBinding(org.eclipse.jdt.internal.compiler.lookup.ParameterizedMethodBinding) ParameterizedGenericMethodBinding(org.eclipse.jdt.internal.compiler.lookup.ParameterizedGenericMethodBinding) ReferenceBinding(org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding)

Example 2 with InferenceContext18

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;
}
Also used : Invocation(org.eclipse.jdt.internal.compiler.ast.Invocation) SwitchExpression(org.eclipse.jdt.internal.compiler.ast.SwitchExpression) MessageSend(org.eclipse.jdt.internal.compiler.ast.MessageSend) ArrayList(java.util.ArrayList) List(java.util.List) SuspendedInferenceRecord(org.eclipse.jdt.internal.compiler.lookup.InferenceContext18.SuspendedInferenceRecord) ConditionalExpression(org.eclipse.jdt.internal.compiler.ast.ConditionalExpression) ConditionalExpression(org.eclipse.jdt.internal.compiler.ast.ConditionalExpression) LambdaExpression(org.eclipse.jdt.internal.compiler.ast.LambdaExpression) Expression(org.eclipse.jdt.internal.compiler.ast.Expression) SwitchExpression(org.eclipse.jdt.internal.compiler.ast.SwitchExpression) ReferenceExpression(org.eclipse.jdt.internal.compiler.ast.ReferenceExpression) ReferenceExpression(org.eclipse.jdt.internal.compiler.ast.ReferenceExpression) LambdaExpression(org.eclipse.jdt.internal.compiler.ast.LambdaExpression)

Example 3 with InferenceContext18

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);
    }
}
Also used : SuspendedInferenceRecord(org.eclipse.jdt.internal.compiler.lookup.InferenceContext18.SuspendedInferenceRecord) ArrayList(java.util.ArrayList)

Aggregations

ArrayList (java.util.ArrayList)2 SuspendedInferenceRecord (org.eclipse.jdt.internal.compiler.lookup.InferenceContext18.SuspendedInferenceRecord)2 List (java.util.List)1 ConditionalExpression (org.eclipse.jdt.internal.compiler.ast.ConditionalExpression)1 Expression (org.eclipse.jdt.internal.compiler.ast.Expression)1 Invocation (org.eclipse.jdt.internal.compiler.ast.Invocation)1 LambdaExpression (org.eclipse.jdt.internal.compiler.ast.LambdaExpression)1 MessageSend (org.eclipse.jdt.internal.compiler.ast.MessageSend)1 ReferenceExpression (org.eclipse.jdt.internal.compiler.ast.ReferenceExpression)1 SwitchExpression (org.eclipse.jdt.internal.compiler.ast.SwitchExpression)1 InferenceContext18 (org.eclipse.jdt.internal.compiler.lookup.InferenceContext18)1 MethodBinding (org.eclipse.jdt.internal.compiler.lookup.MethodBinding)1 ParameterizedGenericMethodBinding (org.eclipse.jdt.internal.compiler.lookup.ParameterizedGenericMethodBinding)1 ParameterizedMethodBinding (org.eclipse.jdt.internal.compiler.lookup.ParameterizedMethodBinding)1 ProblemMethodBinding (org.eclipse.jdt.internal.compiler.lookup.ProblemMethodBinding)1 ReferenceBinding (org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding)1 SourceTypeBinding (org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding)1 TypeBinding (org.eclipse.jdt.internal.compiler.lookup.TypeBinding)1