Search in sources :

Example 1 with InferenceSession

use of com.intellij.psi.impl.source.resolve.graphInference.InferenceSession in project intellij-community by JetBrains.

the class ExpressionCompatibilityConstraint method reduce.

@Override
public boolean reduce(InferenceSession session, List<ConstraintFormula> constraints) {
    if (!PsiPolyExpressionUtil.isPolyExpression(myExpression)) {
        PsiType exprType = myExpression.getType();
        if (session.isProperType(myT)) {
            final boolean assignmentCompatible = exprType == null || TypeConversionUtil.isAssignable(myT, exprType);
            if (!assignmentCompatible) {
                final PsiType type = myExpression.getType();
                session.registerIncompatibleErrorMessage((type != null ? type.getPresentableText() : myExpression.getText()) + " is not compatible with " + session.getPresentableText(myT));
            } else if (TypeCompatibilityConstraint.isUncheckedConversion(myT, exprType) && !JavaGenericsUtil.isReifiableType(myT)) {
                session.setErasedDuringApplicabilityCheck();
            }
            return assignmentCompatible;
        }
        if (exprType instanceof PsiLambdaParameterType) {
            return false;
        }
        if (exprType instanceof PsiClassType) {
            if (((PsiClassType) exprType).resolve() == null) {
                return true;
            }
        }
        if (exprType != null && exprType != PsiType.NULL) {
            if (exprType instanceof PsiDisjunctionType) {
                exprType = ((PsiDisjunctionType) exprType).getLeastUpperBound();
            }
            constraints.add(new TypeCompatibilityConstraint(myT, exprType));
        }
        return true;
    }
    if (myExpression instanceof PsiParenthesizedExpression) {
        final PsiExpression expression = ((PsiParenthesizedExpression) myExpression).getExpression();
        if (expression != null) {
            constraints.add(new ExpressionCompatibilityConstraint(expression, myT));
            return true;
        }
    }
    if (myExpression instanceof PsiConditionalExpression) {
        final PsiExpression thenExpression = ((PsiConditionalExpression) myExpression).getThenExpression();
        if (thenExpression != null) {
            constraints.add(new ExpressionCompatibilityConstraint(thenExpression, myT));
        }
        final PsiExpression elseExpression = ((PsiConditionalExpression) myExpression).getElseExpression();
        if (elseExpression != null) {
            constraints.add(new ExpressionCompatibilityConstraint(elseExpression, myT));
        }
        return true;
    }
    if (myExpression instanceof PsiCall) {
        final InferenceSession callSession = reduceExpressionCompatibilityConstraint(session, myExpression, myT);
        if (callSession == null) {
            return false;
        }
        if (callSession != session) {
            session.getInferenceSessionContainer().registerNestedSession(callSession);
            session.propagateVariables(callSession.getInferenceVariables(), callSession.getRestoreNameSubstitution());
        /*        if (callSession.isErased()) {
          session.setErased();
        }*/
        }
        return true;
    }
    if (myExpression instanceof PsiMethodReferenceExpression) {
        constraints.add(new PsiMethodReferenceCompatibilityConstraint(((PsiMethodReferenceExpression) myExpression), myT));
        return true;
    }
    if (myExpression instanceof PsiLambdaExpression) {
        constraints.add(new LambdaExpressionCompatibilityConstraint((PsiLambdaExpression) myExpression, myT));
        return true;
    }
    return true;
}
Also used : InferenceSession(com.intellij.psi.impl.source.resolve.graphInference.InferenceSession)

Example 2 with InferenceSession

use of com.intellij.psi.impl.source.resolve.graphInference.InferenceSession in project intellij-community by JetBrains.

the class ExpressionCompatibilityConstraint method reduceExpressionCompatibilityConstraint.

public static InferenceSession reduceExpressionCompatibilityConstraint(InferenceSession session, PsiExpression expression, PsiType targetType) {
    final PsiExpressionList argumentList = ((PsiCall) expression).getArgumentList();
    if (argumentList != null) {
        final MethodCandidateInfo.CurrentCandidateProperties candidateProperties = MethodCandidateInfo.getCurrentMethod(argumentList);
        PsiType returnType = null;
        PsiTypeParameter[] typeParams = null;
        final JavaResolveResult resolveResult = candidateProperties != null ? null : InferenceSession.getResolveResult((PsiCall) expression);
        final PsiMethod method = InferenceSession.getCalledMethod((PsiCall) expression);
        if (method != null && !method.isConstructor()) {
            returnType = method.getReturnType();
            typeParams = method.getTypeParameters();
        } else if (resolveResult != null) {
            final PsiClass psiClass = method != null ? method.getContainingClass() : (PsiClass) resolveResult.getElement();
            if (psiClass != null) {
                returnType = JavaPsiFacade.getElementFactory(argumentList.getProject()).createType(psiClass, PsiSubstitutor.EMPTY);
                typeParams = psiClass.getTypeParameters();
                if (method != null && method.hasTypeParameters()) {
                    typeParams = ArrayUtil.mergeArrays(typeParams, method.getTypeParameters());
                }
            }
        }
        if (typeParams != null) {
            PsiSubstitutor siteSubstitutor = InferenceSession.chooseSiteSubstitutor(candidateProperties, resolveResult, method);
            final InferenceSession callSession = new InferenceSession(typeParams, siteSubstitutor, expression.getManager(), expression);
            callSession.propagateVariables(session.getInferenceVariables(), session.getRestoreNameSubstitution());
            if (method != null) {
                final PsiExpression[] args = argumentList.getExpressions();
                final PsiParameter[] parameters = method.getParameterList().getParameters();
                callSession.initExpressionConstraints(parameters, args, expression, method, InferenceSession.chooseVarargsMode(candidateProperties, resolveResult));
            }
            if (callSession.repeatInferencePhases()) {
                if (PsiType.VOID.equals(targetType)) {
                    return callSession;
                }
                if (returnType != null) {
                    callSession.registerReturnTypeConstraints(siteSubstitutor.substitute(returnType), targetType);
                }
                if (callSession.repeatInferencePhases()) {
                    return callSession;
                }
            }
            //copy incompatible message if any
            final List<String> messages = callSession.getIncompatibleErrorMessages();
            if (messages != null) {
                for (String message : messages) {
                    session.registerIncompatibleErrorMessage(message);
                }
            }
        }
        return null;
    }
    return session;
}
Also used : MethodCandidateInfo(com.intellij.psi.infos.MethodCandidateInfo) InferenceSession(com.intellij.psi.impl.source.resolve.graphInference.InferenceSession)

Example 3 with InferenceSession

use of com.intellij.psi.impl.source.resolve.graphInference.InferenceSession in project intellij-community by JetBrains.

the class CheckedExceptionCompatibilityConstraint method reduce.

@Override
public boolean reduce(final InferenceSession session, List<ConstraintFormula> constraints) {
    if (!PsiPolyExpressionUtil.isPolyExpression(myExpression)) {
        return true;
    }
    if (myExpression instanceof PsiParenthesizedExpression) {
        constraints.add(new CheckedExceptionCompatibilityConstraint(((PsiParenthesizedExpression) myExpression).getExpression(), myT));
        return true;
    }
    if (myExpression instanceof PsiConditionalExpression) {
        final PsiExpression thenExpression = ((PsiConditionalExpression) myExpression).getThenExpression();
        if (thenExpression != null) {
            constraints.add(new CheckedExceptionCompatibilityConstraint(thenExpression, myT));
        }
        final PsiExpression elseExpression = ((PsiConditionalExpression) myExpression).getElseExpression();
        if (elseExpression != null) {
            constraints.add(new CheckedExceptionCompatibilityConstraint(elseExpression, myT));
        }
        return true;
    }
    if (myExpression instanceof PsiLambdaExpression || myExpression instanceof PsiMethodReferenceExpression) {
        if (!LambdaUtil.isFunctionalType(myT)) {
            session.registerIncompatibleErrorMessage(session.getPresentableText(myT) + " is not a functional interface");
            return false;
        }
        final PsiType groundTargetType = myExpression instanceof PsiLambdaExpression ? FunctionalInterfaceParameterizationUtil.getGroundTargetType(myT, (PsiLambdaExpression) myExpression, false) : FunctionalInterfaceParameterizationUtil.getGroundTargetType(myT);
        final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(groundTargetType);
        if (interfaceMethod == null) {
            session.registerIncompatibleErrorMessage("No valid function type can be found for " + session.getPresentableText(myT));
            return false;
        }
        final PsiSubstitutor substitutor = LambdaUtil.getSubstitutor(interfaceMethod, PsiUtil.resolveGenericsClassInType(myT));
        if (myExpression instanceof PsiLambdaExpression && !((PsiLambdaExpression) myExpression).hasFormalParameterTypes() || myExpression instanceof PsiMethodReferenceExpression && !((PsiMethodReferenceExpression) myExpression).isExact()) {
            for (PsiParameter parameter : interfaceMethod.getParameterList().getParameters()) {
                final PsiType type = substitutor.substitute(parameter.getType());
                if (!session.isProperType(type)) {
                    session.registerIncompatibleErrorMessage("Parameter type is not yet inferred: " + session.getPresentableText(type));
                    return false;
                }
            }
        }
        final PsiType returnType = interfaceMethod.getReturnType();
        if (myExpression instanceof PsiLambdaExpression || !((PsiMethodReferenceExpression) myExpression).isExact()) {
            final PsiType type = substitutor.substitute(returnType);
            if (!session.isProperType(type)) {
                session.registerIncompatibleErrorMessage("Return type is not yet inferred: " + session.getPresentableText(type));
                return false;
            }
        }
        final List<PsiType> expectedThrownTypes = ContainerUtil.map(interfaceMethod.getThrowsList().getReferencedTypes(), (Function<PsiType, PsiType>) type -> session.substituteWithInferenceVariables(substitutor.substitute(type)));
        final List<PsiType> expectedNonProperThrownTypes = new ArrayList<>();
        for (PsiType type : expectedThrownTypes) {
            if (!session.isProperType(type)) {
                expectedNonProperThrownTypes.add(type);
            }
        }
        final List<PsiType> thrownTypes = new ArrayList<>();
        final PsiElement body = myExpression instanceof PsiLambdaExpression ? ((PsiLambdaExpression) myExpression).getBody() : myExpression;
        if (body != null) {
            final List<PsiClassType> exceptions = ExceptionUtil.getUnhandledExceptions(new PsiElement[] { body });
            if (exceptions != null) {
                thrownTypes.addAll(ContainerUtil.filter(exceptions, type -> !ExceptionUtil.isUncheckedException(type)));
            }
        }
        if (expectedNonProperThrownTypes.isEmpty()) {
            for (PsiType thrownType : thrownTypes) {
                if (!isAddressed(expectedThrownTypes, thrownType)) {
                    session.registerIncompatibleErrorMessage("Unhandled exception: " + session.getPresentableText(thrownType));
                    return false;
                }
            }
        } else {
            final ArrayList<PsiType> expectedProperTypes = new ArrayList<>(expectedThrownTypes);
            expectedProperTypes.removeAll(expectedNonProperThrownTypes);
            for (PsiType thrownType : thrownTypes) {
                if (!isAddressed(expectedProperTypes, thrownType)) {
                    for (PsiType expectedNonProperThrownType : expectedNonProperThrownTypes) {
                        constraints.add(new StrictSubtypingConstraint(expectedNonProperThrownType, thrownType));
                    }
                }
            }
            for (PsiType expectedNonProperThrownType : expectedNonProperThrownTypes) {
                final InferenceVariable variable = session.getInferenceVariable(expectedNonProperThrownType);
                //could be null for invalid code
                if (variable != null) {
                    variable.setThrownBound();
                }
            }
        }
    }
    return true;
}
Also used : TypeConversionUtil(com.intellij.psi.util.TypeConversionUtil) Set(java.util.Set) ContainerUtil(com.intellij.util.containers.ContainerUtil) PsiPolyExpressionUtil(com.intellij.psi.impl.source.resolve.graphInference.PsiPolyExpressionUtil) ArrayList(java.util.ArrayList) InferenceVariable(com.intellij.psi.impl.source.resolve.graphInference.InferenceVariable) List(java.util.List) InferenceSession(com.intellij.psi.impl.source.resolve.graphInference.InferenceSession) Function(com.intellij.util.Function) FunctionalInterfaceParameterizationUtil(com.intellij.psi.impl.source.resolve.graphInference.FunctionalInterfaceParameterizationUtil) PsiUtil(com.intellij.psi.util.PsiUtil) com.intellij.psi(com.intellij.psi) ExceptionUtil(com.intellij.codeInsight.ExceptionUtil) Logger(com.intellij.openapi.diagnostic.Logger) Condition(com.intellij.openapi.util.Condition) ArrayList(java.util.ArrayList) InferenceVariable(com.intellij.psi.impl.source.resolve.graphInference.InferenceVariable)

Example 4 with InferenceSession

use of com.intellij.psi.impl.source.resolve.graphInference.InferenceSession in project intellij-community by JetBrains.

the class MethodReferenceResolver method resolve.

@NotNull
@Override
public JavaResolveResult[] resolve(@NotNull final PsiMethodReferenceExpressionImpl reference, @NotNull final PsiFile containingFile, boolean incompleteCode) {
    final PsiMethodReferenceUtil.QualifierResolveResult qualifierResolveResult = PsiMethodReferenceUtil.getQualifierResolveResult(reference);
    final PsiClass containingClass = qualifierResolveResult.getContainingClass();
    PsiSubstitutor substitutor = qualifierResolveResult.getSubstitutor();
    if (containingClass != null) {
        final PsiElement element = reference.getReferenceNameElement();
        final boolean isConstructor = reference.isConstructor();
        if (element instanceof PsiIdentifier || isConstructor) {
            if (isConstructor && !canBeConstructed(containingClass)) {
                return JavaResolveResult.EMPTY_ARRAY;
            }
            final PsiType functionalInterfaceType = getInterfaceType(reference);
            final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType);
            final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(resolveResult);
            final PsiSubstitutor functionalInterfaceSubstitutor = interfaceMethod != null ? LambdaUtil.getSubstitutor(interfaceMethod, resolveResult) : null;
            final MethodSignature signature = interfaceMethod != null ? interfaceMethod.getSignature(functionalInterfaceSubstitutor) : null;
            final PsiType interfaceMethodReturnType = LambdaUtil.getFunctionalInterfaceReturnType(functionalInterfaceType);
            if (isConstructor && containingClass.getConstructors().length == 0) {
                if (interfaceMethod != null) {
                    final PsiClassType returnType = composeReturnType(containingClass, substitutor);
                    final InferenceSession session = new InferenceSession(containingClass.getTypeParameters(), substitutor, reference.getManager(), null);
                    if (!(session.isProperType(session.substituteWithInferenceVariables(returnType)) && session.isProperType(interfaceMethodReturnType))) {
                        session.registerReturnTypeConstraints(returnType, interfaceMethodReturnType);
                        substitutor = session.infer();
                    }
                }
                ClassCandidateInfo candidateInfo = null;
                final boolean isArray = PsiEquivalenceUtil.areElementsEquivalent(containingClass, JavaPsiFacade.getElementFactory(reference.getProject()).getArrayClass(PsiUtil.getLanguageLevel(reference)));
                if (signature == null || !isArray && (containingClass.getContainingClass() == null || !isLocatedInStaticContext(containingClass, reference)) && signature.getParameterTypes().length == 0 || isArray && arrayCreationSignature(signature)) {
                    candidateInfo = new ClassCandidateInfo(containingClass, substitutor);
                }
                return candidateInfo == null ? JavaResolveResult.EMPTY_ARRAY : new JavaResolveResult[] { candidateInfo };
            }
            final PsiConflictResolver conflictResolver = createResolver(reference, qualifierResolveResult, interfaceMethod, signature);
            final MethodCandidatesProcessor processor = new MethodCandidatesProcessor(reference, containingFile, new PsiConflictResolver[] { conflictResolver }, new SmartList<>()) {

                @Override
                protected boolean acceptVarargs() {
                    return true;
                }

                @Override
                protected MethodCandidateInfo createCandidateInfo(@NotNull final PsiMethod method, @NotNull final PsiSubstitutor substitutor, final boolean staticProblem, final boolean accessible, final boolean varargs) {
                    final PsiExpressionList argumentList = getArgumentList();
                    final PsiType[] typeParameters = reference.getTypeParameters();
                    return new MethodCandidateInfo(method, substitutor, !accessible, staticProblem, argumentList, myCurrentFileContext, argumentList != null ? argumentList.getExpressionTypes() : null, method.hasTypeParameters() && typeParameters.length > 0 ? typeParameters : null, getLanguageLevel()) {

                        @Override
                        public boolean isVarargs() {
                            return varargs;
                        }

                        @NotNull
                        @Override
                        public PsiSubstitutor inferTypeArguments(@NotNull ParameterTypeInferencePolicy policy, boolean includeReturnConstraint) {
                            return inferTypeArguments(includeReturnConstraint);
                        }

                        private PsiSubstitutor inferTypeArguments(boolean includeReturnConstraint) {
                            if (interfaceMethod == null)
                                return substitutor;
                            final InferenceSession session = new InferenceSession(method.getTypeParameters(), substitutor, reference.getManager(), reference);
                            session.initThrowsConstraints(method);
                            final PsiSubstitutor psiSubstitutor = session.collectApplicabilityConstraints(reference, this, functionalInterfaceType);
                            if (psiSubstitutor != null) {
                                return psiSubstitutor;
                            }
                            if (!session.repeatInferencePhases()) {
                                return substitutor;
                            }
                            if (includeReturnConstraint && !PsiType.VOID.equals(interfaceMethodReturnType) && interfaceMethodReturnType != null) {
                                PsiSubstitutor subst = PsiMethodReferenceCompatibilityConstraint.getSubstitutor(signature, qualifierResolveResult, method, containingClass, reference);
                                final PsiType returnType = method.isConstructor() ? composeReturnType(containingClass, subst) : subst.substitute(method.getReturnType());
                                if (returnType != null) {
                                    session.registerReturnTypeConstraints(returnType, interfaceMethodReturnType);
                                }
                            }
                            return session.infer(method.getParameterList().getParameters(), null, null);
                        }

                        @Override
                        public boolean isApplicable() {
                            if (signature == null)
                                return false;
                            final PsiType[] argTypes = signature.getParameterTypes();
                            boolean hasReceiver = PsiMethodReferenceUtil.isSecondSearchPossible(argTypes, qualifierResolveResult, reference);
                            return MethodReferenceConflictResolver.isApplicableByFirstSearch(this, argTypes, hasReceiver, reference, interfaceMethod.isVarArgs()) != null;
                        }
                    };
                }
            };
            processor.setIsConstructor(isConstructor);
            processor.setName(isConstructor ? containingClass.getName() : element.getText());
            final PsiExpression expression = reference.getQualifierExpression();
            if (expression == null || !(expression.getType() instanceof PsiArrayType)) {
                processor.setAccessClass(containingClass);
            }
            if (qualifierResolveResult.isReferenceTypeQualified() && isLocatedInStaticContext(containingClass, reference)) {
                processor.handleEvent(JavaScopeProcessorEvent.START_STATIC, null);
            }
            ResolveState state = ResolveState.initial().put(PsiSubstitutor.KEY, substitutor);
            containingClass.processDeclarations(processor, state, reference, reference);
            return processor.getResult();
        }
    }
    return JavaResolveResult.EMPTY_ARRAY;
}
Also used : NotNull(org.jetbrains.annotations.NotNull) PsiConflictResolver(com.intellij.psi.scope.PsiConflictResolver) MethodCandidateInfo(com.intellij.psi.infos.MethodCandidateInfo) ClassCandidateInfo(com.intellij.psi.infos.ClassCandidateInfo) MethodCandidatesProcessor(com.intellij.psi.scope.processor.MethodCandidatesProcessor) MethodSignature(com.intellij.psi.util.MethodSignature) InferenceSession(com.intellij.psi.impl.source.resolve.graphInference.InferenceSession) ParameterTypeInferencePolicy(com.intellij.psi.impl.source.resolve.ParameterTypeInferencePolicy) NotNull(org.jetbrains.annotations.NotNull)

Aggregations

InferenceSession (com.intellij.psi.impl.source.resolve.graphInference.InferenceSession)4 MethodCandidateInfo (com.intellij.psi.infos.MethodCandidateInfo)2 ExceptionUtil (com.intellij.codeInsight.ExceptionUtil)1 Logger (com.intellij.openapi.diagnostic.Logger)1 Condition (com.intellij.openapi.util.Condition)1 com.intellij.psi (com.intellij.psi)1 ParameterTypeInferencePolicy (com.intellij.psi.impl.source.resolve.ParameterTypeInferencePolicy)1 FunctionalInterfaceParameterizationUtil (com.intellij.psi.impl.source.resolve.graphInference.FunctionalInterfaceParameterizationUtil)1 InferenceVariable (com.intellij.psi.impl.source.resolve.graphInference.InferenceVariable)1 PsiPolyExpressionUtil (com.intellij.psi.impl.source.resolve.graphInference.PsiPolyExpressionUtil)1 ClassCandidateInfo (com.intellij.psi.infos.ClassCandidateInfo)1 PsiConflictResolver (com.intellij.psi.scope.PsiConflictResolver)1 MethodCandidatesProcessor (com.intellij.psi.scope.processor.MethodCandidatesProcessor)1 MethodSignature (com.intellij.psi.util.MethodSignature)1 PsiUtil (com.intellij.psi.util.PsiUtil)1 TypeConversionUtil (com.intellij.psi.util.TypeConversionUtil)1 Function (com.intellij.util.Function)1 ContainerUtil (com.intellij.util.containers.ContainerUtil)1 ArrayList (java.util.ArrayList)1 List (java.util.List)1