Search in sources :

Example 1 with Invocation

use of org.eclipse.jdt.internal.compiler.ast.Invocation 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 2 with Invocation

use of org.eclipse.jdt.internal.compiler.ast.Invocation in project bazel-jdt-java-toolchain by salesforce.

the class InferenceContext18 method addConstraintsToC_OneExpr.

private boolean addConstraintsToC_OneExpr(Expression expri, Set<ConstraintFormula> c, TypeBinding fsi, TypeBinding substF, MethodBinding method) throws InferenceFailureException {
    boolean substFIsProperType = substF.isProperType(true);
    // -- not per JLS, emulate javac behavior:
    substF = Scope.substitute(getResultSubstitution(this.b3), substF);
    // For all i (1 ≤ i ≤ k), if ei is not pertinent to applicability, the set contains ⟨ei → θ Fi⟩.
    if (!expri.isPertinentToApplicability(fsi, method)) {
        c.add(new ConstraintExpressionFormula(expri, substF, ReductionResult.COMPATIBLE, ARGUMENT_CONSTRAINTS_ARE_SOFT));
    }
    if (expri instanceof FunctionalExpression) {
        c.add(new ConstraintExceptionFormula((FunctionalExpression) expri, substF));
        if (expri instanceof LambdaExpression) {
            // https://bugs.openjdk.java.net/browse/JDK-8038747
            LambdaExpression lambda = (LambdaExpression) expri;
            BlockScope skope = lambda.enclosingScope;
            if (substF.isFunctionalInterface(skope)) {
                // could be an inference variable.
                ReferenceBinding t = (ReferenceBinding) substF;
                ParameterizedTypeBinding withWildCards = InferenceContext18.parameterizedWithWildcard(t);
                if (withWildCards != null) {
                    t = ConstraintExpressionFormula.findGroundTargetType(this, skope, lambda, withWildCards);
                }
                MethodBinding functionType;
                if (t != null && (functionType = t.getSingleAbstractMethod(skope, true)) != null && (lambda = lambda.resolveExpressionExpecting(t, this.scope, this)) != null) {
                    TypeBinding r = functionType.returnType;
                    Expression[] resultExpressions = lambda.resultExpressions();
                    for (int i = 0, length = resultExpressions == null ? 0 : resultExpressions.length; i < length; i++) {
                        Expression resultExpression = resultExpressions[i];
                        if (!addConstraintsToC_OneExpr(resultExpression, c, r.original(), r, method))
                            return false;
                    }
                }
            }
        }
    } else if (expri instanceof Invocation && expri.isPolyExpression()) {
        if (// https://bugs.openjdk.java.net/browse/JDK-8052325
        substFIsProperType)
            return true;
        Invocation invocation = (Invocation) expri;
        MethodBinding innerMethod = invocation.binding();
        if (innerMethod == null)
            // -> proceed with no new C set elements.
            return true;
        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;
        InferenceContext18 innerContext = null;
        if (innerMethod instanceof ParameterizedGenericMethodBinding)
            innerContext = invocation.getInferenceContext((ParameterizedGenericMethodBinding) innerMethod);
        if (innerContext != null) {
            MethodBinding shallowMethod = innerMethod.shallowOriginal();
            innerContext.outerContext = this;
            if (// shouldn't happen, but let's play safe
            innerContext.stepCompleted < InferenceContext18.APPLICABILITY_INFERRED)
                innerContext.inferInvocationApplicability(shallowMethod, argumentTypes, shallowMethod.isConstructor());
            if (!innerContext.computeB3(invocation, substF, shallowMethod))
                return false;
            if (innerContext.addConstraintsToC(arguments, c, innerMethod.genericMethod(), innerContext.inferenceKind, invocation)) {
                this.currentBounds.addBounds(innerContext.currentBounds, this.environment);
                return true;
            }
            return false;
        } else {
            int applicabilityKind = getInferenceKind(innerMethod, argumentTypes);
            return this.addConstraintsToC(arguments, c, innerMethod.genericMethod(), applicabilityKind, invocation);
        }
    } else if (expri instanceof ConditionalExpression) {
        ConditionalExpression ce = (ConditionalExpression) expri;
        return addConstraintsToC_OneExpr(ce.valueIfTrue, c, fsi, substF, method) && addConstraintsToC_OneExpr(ce.valueIfFalse, c, fsi, substF, method);
    } else if (expri instanceof SwitchExpression) {
        SwitchExpression se = (SwitchExpression) expri;
        for (Expression re : se.resultExpressions) {
            if (!addConstraintsToC_OneExpr(re, c, fsi, substF, method))
                return false;
        }
        return true;
    }
    return true;
}
Also used : Invocation(org.eclipse.jdt.internal.compiler.ast.Invocation) SwitchExpression(org.eclipse.jdt.internal.compiler.ast.SwitchExpression) 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) FunctionalExpression(org.eclipse.jdt.internal.compiler.ast.FunctionalExpression) ReferenceExpression(org.eclipse.jdt.internal.compiler.ast.ReferenceExpression) FunctionalExpression(org.eclipse.jdt.internal.compiler.ast.FunctionalExpression) LambdaExpression(org.eclipse.jdt.internal.compiler.ast.LambdaExpression)

Example 3 with Invocation

use of org.eclipse.jdt.internal.compiler.ast.Invocation in project bazel-jdt-java-toolchain by salesforce.

the class ConstraintTypeFormula method reduceSubType.

private Object reduceSubType(Scope scope, TypeBinding subCandidate, TypeBinding superCandidate) {
    // 18.2.3 Subtyping Constraints
    if (subCandidate.isProperType(true) && superCandidate.isProperType(true)) {
        if (subCandidate.isSubtypeOf(superCandidate, InferenceContext18.SIMULATE_BUG_JDK_8026527))
            return TRUE;
        return FALSE;
    }
    if (subCandidate.id == TypeIds.T_null)
        return TRUE;
    if (superCandidate.id == TypeIds.T_null)
        return FALSE;
    if (subCandidate instanceof InferenceVariable)
        return new TypeBound((InferenceVariable) subCandidate, superCandidate, SUBTYPE, this.isSoft);
    if (superCandidate instanceof InferenceVariable)
        // normalize to have variable on LHS
        return new TypeBound((InferenceVariable) superCandidate, subCandidate, SUPERTYPE, this.isSoft);
    switch(superCandidate.kind()) {
        case Binding.GENERIC_TYPE:
        case Binding.TYPE:
        case Binding.RAW_TYPE:
            {
                if (subCandidate.isSubtypeOf(superCandidate, InferenceContext18.SIMULATE_BUG_JDK_8026527))
                    return TRUE;
                return FALSE;
            }
        case Binding.PARAMETERIZED_TYPE:
            {
                List<ConstraintFormula> constraints = new ArrayList<>();
                boolean isFirst = true;
                while (superCandidate != null && superCandidate.kind() == Binding.PARAMETERIZED_TYPE && subCandidate != null) {
                    if (!addConstraintsFromTypeParameters(subCandidate, (ParameterizedTypeBinding) superCandidate, constraints))
                        if (isFirst)
                            return FALSE;
                    isFirst = false;
                    // travel to enclosing types to check if they have type parameters, too:
                    superCandidate = superCandidate.enclosingType();
                    subCandidate = subCandidate.enclosingType();
                }
                switch(constraints.size()) {
                    case 0:
                        return TRUE;
                    case 1:
                        return constraints.get(0);
                    default:
                        return constraints.toArray(new ConstraintFormula[constraints.size()]);
                }
            }
        case Binding.ARRAY_TYPE:
            TypeBinding tPrime = ((ArrayBinding) superCandidate).elementsType();
            // let S'[] be the most specific array type that is a supertype of S (or S itself)
            ArrayBinding sPrimeArray = null;
            switch(subCandidate.kind()) {
                case Binding.INTERSECTION_TYPE:
                    {
                        WildcardBinding intersection = (WildcardBinding) subCandidate;
                        sPrimeArray = findMostSpecificSuperArray(intersection.bound, intersection.otherBounds, intersection);
                        break;
                    }
                case Binding.ARRAY_TYPE:
                    sPrimeArray = (ArrayBinding) subCandidate;
                    break;
                case Binding.TYPE_PARAMETER:
                    {
                        TypeVariableBinding subTVB = (TypeVariableBinding) subCandidate;
                        sPrimeArray = findMostSpecificSuperArray(subTVB.firstBound, subTVB.otherUpperBounds(), subTVB);
                        break;
                    }
                default:
                    return FALSE;
            }
            if (sPrimeArray == null)
                return FALSE;
            TypeBinding sPrime = sPrimeArray.elementsType();
            if (!tPrime.isPrimitiveType() && !sPrime.isPrimitiveType()) {
                return ConstraintTypeFormula.create(sPrime, tPrime, SUBTYPE, this.isSoft);
            }
            // same primitive type?
            return TypeBinding.equalsEquals(tPrime, sPrime) ? TRUE : FALSE;
        // "type variable" has two implementations in JDT:
        case Binding.WILDCARD_TYPE:
            if (subCandidate.kind() == Binding.INTERSECTION_TYPE) {
                ReferenceBinding[] intersectingTypes = subCandidate.getIntersectingTypes();
                if (intersectingTypes != null)
                    for (int i = 0; i < intersectingTypes.length; i++) if (TypeBinding.equalsEquals(intersectingTypes[i], superCandidate))
                        return true;
            }
            WildcardBinding variable = (WildcardBinding) superCandidate;
            if (variable.boundKind == Wildcard.SUPER)
                return ConstraintTypeFormula.create(subCandidate, variable.bound, SUBTYPE, this.isSoft);
            return FALSE;
        case Binding.TYPE_PARAMETER:
            // similar to wildcard, but different queries for lower bound
            if (subCandidate.kind() == Binding.INTERSECTION_TYPE) {
                ReferenceBinding[] intersectingTypes = subCandidate.getIntersectingTypes();
                if (intersectingTypes != null)
                    for (int i = 0; i < intersectingTypes.length; i++) if (TypeBinding.equalsEquals(intersectingTypes[i], superCandidate))
                        return true;
            }
            if (superCandidate instanceof CaptureBinding) {
                CaptureBinding capture = (CaptureBinding) superCandidate;
                if (capture.lowerBound != null)
                    return ConstraintTypeFormula.create(subCandidate, capture.lowerBound, SUBTYPE, this.isSoft);
            }
            return FALSE;
        case Binding.INTERSECTION_TYPE:
            superCandidate = ((WildcardBinding) superCandidate).allBounds();
        // $FALL-THROUGH$
        case Binding.INTERSECTION_TYPE18:
            TypeBinding[] intersectingTypes = ((IntersectionTypeBinding18) superCandidate).intersectingTypes;
            ConstraintFormula[] result = new ConstraintFormula[intersectingTypes.length];
            for (int i = 0; i < intersectingTypes.length; i++) {
                result[i] = ConstraintTypeFormula.create(subCandidate, intersectingTypes[i], SUBTYPE, this.isSoft);
            }
            return result;
        case Binding.POLY_TYPE:
            PolyTypeBinding poly = (PolyTypeBinding) superCandidate;
            Invocation invocation = (Invocation) poly.expression;
            MethodBinding binding = invocation.binding();
            if (binding == null || !binding.isValidBinding())
                return FALSE;
            TypeBinding returnType = binding.isConstructor() ? binding.declaringClass : binding.returnType;
            return reduceSubType(scope, subCandidate, returnType.capture(scope, invocation.sourceStart(), invocation.sourceEnd()));
    }
    // $NON-NLS-1$
    throw new IllegalStateException("Unexpected RHS " + superCandidate);
}
Also used : Invocation(org.eclipse.jdt.internal.compiler.ast.Invocation) List(java.util.List) ArrayList(java.util.ArrayList)

Example 4 with Invocation

use of org.eclipse.jdt.internal.compiler.ast.Invocation in project bazel-jdt-java-toolchain by salesforce.

the class InferenceContext18 method forwardResults.

public void forwardResults(BoundSet result, Invocation invocation, ParameterizedMethodBinding pmb, TypeBinding targetType) {
    if (targetType != null)
        invocation.registerResult(targetType, pmb);
    Expression[] arguments = invocation.arguments();
    for (int i = 0, length = arguments == null ? 0 : arguments.length; i < length; i++) {
        Expression[] expressions = arguments[i].getPolyExpressions();
        for (int j = 0, jLength = expressions.length; j < jLength; j++) {
            Expression expression = expressions[j];
            if (!(expression instanceof Invocation))
                continue;
            Invocation polyInvocation = (Invocation) expression;
            MethodBinding binding = polyInvocation.binding();
            if (binding == null || !binding.isValidBinding())
                continue;
            ParameterizedMethodBinding methodSubstitute = null;
            if (binding instanceof ParameterizedGenericMethodBinding) {
                MethodBinding shallowOriginal = binding.shallowOriginal();
                TypeBinding[] solutions = getSolutions(shallowOriginal.typeVariables(), polyInvocation, result);
                if (// in CEF.reduce, we lift inner poly expressions into outer context only if their target type has inference variables.
                solutions == null)
                    continue;
                methodSubstitute = this.environment.createParameterizedGenericMethod(shallowOriginal, solutions);
            } else {
                if (!binding.isConstructor() || !(binding instanceof ParameterizedMethodBinding))
                    // throw ISE ?
                    continue;
                MethodBinding shallowOriginal = binding.shallowOriginal();
                ReferenceBinding genericType = shallowOriginal.declaringClass;
                TypeBinding[] solutions = getSolutions(genericType.typeVariables(), polyInvocation, result);
                if (// in CEF.reduce, we lift inner poly expressions into outer context only if their target type has inference variables.
                solutions == null)
                    continue;
                ParameterizedTypeBinding parameterizedType = this.environment.createParameterizedType(genericType, solutions, binding.declaringClass.enclosingType());
                for (MethodBinding parameterizedMethod : parameterizedType.methods()) {
                    if (parameterizedMethod.original() == shallowOriginal) {
                        methodSubstitute = (ParameterizedMethodBinding) parameterizedMethod;
                        break;
                    }
                }
            }
            if (methodSubstitute == null || !methodSubstitute.isValidBinding())
                continue;
            boolean variableArity = pmb.isVarargs();
            final TypeBinding[] parameters = pmb.parameters;
            if (variableArity && parameters.length == arguments.length && i == length - 1) {
                TypeBinding returnType = methodSubstitute.returnType.capture(this.scope, expression.sourceStart, expression.sourceEnd);
                if (returnType.isCompatibleWith(parameters[parameters.length - 1], this.scope)) {
                    variableArity = false;
                }
            }
            TypeBinding parameterType = InferenceContext18.getParameter(parameters, i, variableArity);
            forwardResults(result, polyInvocation, methodSubstitute, parameterType);
        }
    }
}
Also used : Invocation(org.eclipse.jdt.internal.compiler.ast.Invocation) 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) FunctionalExpression(org.eclipse.jdt.internal.compiler.ast.FunctionalExpression) ReferenceExpression(org.eclipse.jdt.internal.compiler.ast.ReferenceExpression)

Example 5 with Invocation

use of org.eclipse.jdt.internal.compiler.ast.Invocation in project bazel-jdt-java-toolchain by salesforce.

the class ParameterizedGenericMethodBinding method computeCompatibleMethod18.

public static MethodBinding computeCompatibleMethod18(MethodBinding originalMethod, TypeBinding[] arguments, final Scope scope, InvocationSite invocationSite) {
    TypeVariableBinding[] typeVariables = originalMethod.typeVariables;
    if (invocationSite.checkingPotentialCompatibility()) {
        // Not interested in a solution, only that there could potentially be one.
        return scope.environment().createParameterizedGenericMethod(originalMethod, typeVariables);
    }
    ParameterizedGenericMethodBinding methodSubstitute = null;
    InferenceContext18 infCtx18 = invocationSite.freshInferenceContext(scope);
    if (infCtx18 == null)
        // per parity with old F & G integration.
        return originalMethod;
    TypeBinding[] parameters = originalMethod.parameters;
    CompilerOptions compilerOptions = scope.compilerOptions();
    boolean invocationTypeInferred = false;
    boolean requireBoxing = false;
    boolean allArgumentsAreProper = true;
    // See if we should start in loose inference mode.
    TypeBinding[] argumentsCopy = new TypeBinding[arguments.length];
    for (int i = 0, length = arguments.length, parametersLength = parameters.length; i < length; i++) {
        TypeBinding parameter = i < parametersLength ? parameters[i] : parameters[parametersLength - 1];
        final TypeBinding argument = arguments[i];
        allArgumentsAreProper &= argument.isProperType(true);
        if (argument.isPrimitiveType() != parameter.isPrimitiveType()) {
            // Scope.cCM incorrectly but harmlessly uses isBaseType which answers true for null.
            argumentsCopy[i] = scope.environment().computeBoxingType(argument);
            // can't be strict mode, needs at least loose.
            requireBoxing = true;
        } else {
            argumentsCopy[i] = argument;
        }
    }
    // either way, this allows the engine to update arguments without harming the callers.
    arguments = argumentsCopy;
    LookupEnvironment environment = scope.environment();
    InferenceContext18 previousContext = environment.currentInferenceContext;
    if (previousContext == null)
        environment.currentInferenceContext = infCtx18;
    try {
        BoundSet provisionalResult = null;
        BoundSet result = null;
        // ---- 18.5.1 (Applicability): ----
        final boolean isPolyExpression = invocationSite instanceof Expression && ((Expression) invocationSite).isTrulyExpression() && ((Expression) invocationSite).isPolyExpression(originalMethod);
        boolean isDiamond = isPolyExpression && originalMethod.isConstructor();
        if (arguments.length == parameters.length) {
            // engine may still slip into loose mode and adjust level.
            infCtx18.inferenceKind = requireBoxing ? InferenceContext18.CHECK_LOOSE : InferenceContext18.CHECK_STRICT;
            infCtx18.inferInvocationApplicability(originalMethod, arguments, isDiamond);
            result = infCtx18.solve(true);
        }
        if (result == null && originalMethod.isVarargs()) {
            // check for variable-arity applicability
            // start over
            infCtx18 = invocationSite.freshInferenceContext(scope);
            infCtx18.inferenceKind = InferenceContext18.CHECK_VARARG;
            infCtx18.inferInvocationApplicability(originalMethod, arguments, isDiamond);
            result = infCtx18.solve(true);
        }
        if (result == null)
            return null;
        if (infCtx18.isResolved(result)) {
            infCtx18.stepCompleted = InferenceContext18.APPLICABILITY_INFERRED;
        } else {
            return null;
        }
        // Applicability succeeded, proceed to infer invocation type, if possible.
        TypeBinding expectedType = invocationSite.invocationTargetType();
        boolean hasReturnProblem = false;
        if (expectedType != null || !invocationSite.getExpressionContext().definesTargetType() || !isPolyExpression) {
            // ---- 18.5.2 (Invocation type): ----
            provisionalResult = result;
            result = infCtx18.inferInvocationType(expectedType, invocationSite, originalMethod);
            invocationTypeInferred = infCtx18.stepCompleted == InferenceContext18.TYPE_INFERRED_FINAL;
            hasReturnProblem |= result == null;
            if (hasReturnProblem)
                // let's prefer a type error regarding the return type over reporting no match at all
                result = provisionalResult;
        }
        if (result != null) {
            // assemble the solution etc:
            TypeBinding[] solutions = infCtx18.getSolutions(typeVariables, invocationSite, result);
            if (solutions != null) {
                methodSubstitute = scope.environment().createParameterizedGenericMethod(originalMethod, solutions, infCtx18.usesUncheckedConversion, hasReturnProblem, expectedType);
                if (invocationSite instanceof Invocation && allArgumentsAreProper && (expectedType == null || expectedType.isProperType(true)))
                    infCtx18.forwardResults(result, (Invocation) invocationSite, methodSubstitute, expectedType);
                try {
                    if (hasReturnProblem) {
                        // illegally working from the provisional result?
                        MethodBinding problemMethod = infCtx18.getReturnProblemMethodIfNeeded(expectedType, methodSubstitute);
                        if (problemMethod instanceof ProblemMethodBinding) {
                            return problemMethod;
                        }
                    }
                    if (invocationTypeInferred) {
                        if (compilerOptions.isAnnotationBasedNullAnalysisEnabled)
                            NullAnnotationMatching.checkForContradictions(methodSubstitute, invocationSite, scope);
                        MethodBinding problemMethod = methodSubstitute.boundCheck18(scope, arguments, invocationSite);
                        if (problemMethod != null) {
                            return problemMethod;
                        }
                    } else {
                        methodSubstitute = new PolyParameterizedGenericMethodBinding(methodSubstitute);
                    }
                } finally {
                    if (allArgumentsAreProper) {
                        if (invocationSite instanceof Invocation)
                            // keep context so we can finish later
                            ((Invocation) invocationSite).registerInferenceContext(methodSubstitute, infCtx18);
                        else if (invocationSite instanceof ReferenceExpression)
                            // keep context so we can finish later
                            ((ReferenceExpression) invocationSite).registerInferenceContext(methodSubstitute, infCtx18);
                    }
                }
                return methodSubstitute;
            }
        }
        return null;
    } catch (InferenceFailureException e) {
        // FIXME stop-gap measure
        scope.problemReporter().genericInferenceError(e.getMessage(), invocationSite);
        return null;
    } finally {
        environment.currentInferenceContext = previousContext;
    }
}
Also used : Invocation(org.eclipse.jdt.internal.compiler.ast.Invocation) Expression(org.eclipse.jdt.internal.compiler.ast.Expression) ReferenceExpression(org.eclipse.jdt.internal.compiler.ast.ReferenceExpression) CompilerOptions(org.eclipse.jdt.internal.compiler.impl.CompilerOptions) ReferenceExpression(org.eclipse.jdt.internal.compiler.ast.ReferenceExpression)

Aggregations

Invocation (org.eclipse.jdt.internal.compiler.ast.Invocation)5 Expression (org.eclipse.jdt.internal.compiler.ast.Expression)4 ReferenceExpression (org.eclipse.jdt.internal.compiler.ast.ReferenceExpression)4 ConditionalExpression (org.eclipse.jdt.internal.compiler.ast.ConditionalExpression)3 LambdaExpression (org.eclipse.jdt.internal.compiler.ast.LambdaExpression)3 SwitchExpression (org.eclipse.jdt.internal.compiler.ast.SwitchExpression)3 ArrayList (java.util.ArrayList)2 List (java.util.List)2 FunctionalExpression (org.eclipse.jdt.internal.compiler.ast.FunctionalExpression)2 MessageSend (org.eclipse.jdt.internal.compiler.ast.MessageSend)1 CompilerOptions (org.eclipse.jdt.internal.compiler.impl.CompilerOptions)1 SuspendedInferenceRecord (org.eclipse.jdt.internal.compiler.lookup.InferenceContext18.SuspendedInferenceRecord)1