Search in sources :

Example 1 with SuspendedInferenceRecord

use of org.eclipse.jdt.internal.compiler.lookup.InferenceContext18.SuspendedInferenceRecord 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 SuspendedInferenceRecord

use of org.eclipse.jdt.internal.compiler.lookup.InferenceContext18.SuspendedInferenceRecord 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