Search in sources :

Example 1 with InferenceVariable

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

the class InputOutputConstraintFormula method getInputVariables.

public Set<InferenceVariable> getInputVariables(InferenceSession session) {
    final PsiExpression psiExpression = getExpression();
    final PsiType type = getT();
    if (psiExpression instanceof PsiFunctionalExpression) {
        final InferenceVariable inferenceVariable = session.getInferenceVariable(type);
        if (inferenceVariable != null) {
            final HashSet<InferenceVariable> result = new HashSet<>();
            result.add(inferenceVariable);
            return result;
        }
        if (LambdaUtil.isFunctionalType(type)) {
            final PsiType functionType = psiExpression instanceof PsiLambdaExpression ? FunctionalInterfaceParameterizationUtil.getGroundTargetType(type, (PsiLambdaExpression) psiExpression, false) : type;
            final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionType);
            final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(resolveResult);
            if (interfaceMethod != null) {
                final Set<InferenceVariable> result = new HashSet<>();
                final PsiSubstitutor substitutor = LambdaUtil.getSubstitutor(interfaceMethod, resolveResult);
                if (psiExpression instanceof PsiLambdaExpression && !((PsiLambdaExpression) psiExpression).hasFormalParameterTypes() || psiExpression instanceof PsiMethodReferenceExpression && !((PsiMethodReferenceExpression) psiExpression).isExact()) {
                    for (PsiParameter parameter : interfaceMethod.getParameterList().getParameters()) {
                        session.collectDependencies(substitutor.substitute(parameter.getType()), result);
                    }
                }
                final PsiType returnType = interfaceMethod.getReturnType();
                if (returnType != null) {
                    collectReturnTypeVariables(session, psiExpression, substitutor.substitute(returnType), result);
                }
                return result;
            }
        }
    }
    if (psiExpression instanceof PsiParenthesizedExpression) {
        final PsiExpression expression = ((PsiParenthesizedExpression) psiExpression).getExpression();
        return expression != null ? createSelfConstraint(type, expression).getInputVariables(session) : null;
    }
    if (psiExpression instanceof PsiConditionalExpression) {
        final PsiExpression thenExpression = ((PsiConditionalExpression) psiExpression).getThenExpression();
        final PsiExpression elseExpression = ((PsiConditionalExpression) psiExpression).getElseExpression();
        final Set<InferenceVariable> thenResult = thenExpression != null ? createSelfConstraint(type, thenExpression).getInputVariables(session) : null;
        final Set<InferenceVariable> elseResult = elseExpression != null ? createSelfConstraint(type, elseExpression).getInputVariables(session) : null;
        if (thenResult == null) {
            return elseResult;
        } else if (elseResult == null) {
            return thenResult;
        } else {
            thenResult.addAll(elseResult);
            return thenResult;
        }
    }
    return null;
}
Also used : InferenceVariable(com.intellij.psi.impl.source.resolve.graphInference.InferenceVariable) HashSet(java.util.HashSet)

Example 2 with InferenceVariable

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

the class TypeEqualityConstraint method reduce.

@Override
public boolean reduce(InferenceSession session, List<ConstraintFormula> constraints) {
    if (myT instanceof PsiWildcardType && myS instanceof PsiWildcardType) {
        final PsiType tBound = ((PsiWildcardType) myT).getBound();
        final PsiType sBound = ((PsiWildcardType) myS).getBound();
        if (tBound == null && sBound == null)
            return true;
        if (sBound == null && ((PsiWildcardType) myT).isExtends()) {
            //extends bound of "?" (Object)
            constraints.add(new TypeEqualityConstraint(((PsiWildcardType) myS).getExtendsBound(), tBound));
            return true;
        }
        if (tBound == null && ((PsiWildcardType) myS).isExtends()) {
            //extends bound of "?" (Object)
            constraints.add(new TypeEqualityConstraint(((PsiWildcardType) myT).getExtendsBound(), sBound));
            return true;
        }
        if (((PsiWildcardType) myT).isExtends() && ((PsiWildcardType) myS).isExtends() || ((PsiWildcardType) myT).isSuper() && ((PsiWildcardType) myS).isSuper()) {
            LOG.assertTrue(tBound != null);
            LOG.assertTrue(sBound != null);
            constraints.add(new TypeEqualityConstraint(tBound, sBound));
            return true;
        }
    }
    if (myT instanceof PsiWildcardType || myS instanceof PsiWildcardType) {
        session.registerIncompatibleErrorMessage("Incompatible equality constraint: " + session.getPresentableText(myT) + " and " + session.getPresentableText(myS));
        return false;
    }
    if (session.isProperType(myT) && session.isProperType(myS)) {
        final boolean equal = Comparing.equal(myT, myS);
        if (!equal) {
            session.registerIncompatibleErrorMessage("Incompatible equality constraint: " + session.getPresentableText(myT) + " and " + session.getPresentableText(myS));
        }
        return equal;
    }
    if (myT == null || myT == PsiType.NULL)
        return false;
    if (myS == null || myS == PsiType.NULL)
        return false;
    InferenceVariable inferenceVariable = session.getInferenceVariable(myS);
    if (inferenceVariable != null && !(myT instanceof PsiPrimitiveType)) {
        InferenceVariable.addBound(myS, myT, InferenceBound.EQ, session);
        return true;
    }
    inferenceVariable = session.getInferenceVariable(myT);
    if (inferenceVariable != null && !(myS instanceof PsiPrimitiveType)) {
        InferenceVariable.addBound(myT, myS, InferenceBound.EQ, session);
        return true;
    }
    if (myT instanceof PsiClassType && myS instanceof PsiClassType) {
        final PsiClassType.ClassResolveResult tResult = ((PsiClassType) myT).resolveGenerics();
        final PsiClassType.ClassResolveResult sResult = ((PsiClassType) myS).resolveGenerics();
        final PsiClass tClass = tResult.getElement();
        //equal erasure
        if (tClass != null && tClass.getManager().areElementsEquivalent(tClass, sResult.getElement())) {
            final PsiSubstitutor tSubstitutor = tResult.getSubstitutor();
            final PsiSubstitutor sSubstitutor = sResult.getSubstitutor();
            for (PsiTypeParameter typeParameter : tClass.getTypeParameters()) {
                final PsiType tSubstituted = tSubstitutor.substitute(typeParameter);
                final PsiType sSubstituted = sSubstitutor.substitute(typeParameter);
                if (tSubstituted != null && sSubstituted != null) {
                    constraints.add(new TypeEqualityConstraint(tSubstituted, sSubstituted));
                }
                if (tSubstituted == null ^ sSubstituted == null) {
                    session.registerIncompatibleErrorMessage("Incompatible equality constraint: " + session.getPresentableText(myT) + " and " + session.getPresentableText(myS));
                    return false;
                }
            }
            return true;
        }
    }
    if (myT instanceof PsiArrayType && myS instanceof PsiArrayType) {
        constraints.add(new TypeEqualityConstraint(((PsiArrayType) myT).getComponentType(), ((PsiArrayType) myS).getComponentType()));
        return true;
    }
    session.registerIncompatibleErrorMessage(session.getInferenceVariables(), session.getPresentableText(myS) + " conforms to " + session.getPresentableText(myT));
    return false;
}
Also used : InferenceVariable(com.intellij.psi.impl.source.resolve.graphInference.InferenceVariable)

Example 3 with InferenceVariable

use of com.intellij.psi.impl.source.resolve.graphInference.InferenceVariable 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 InferenceVariable

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

the class StrictSubtypingConstraint method doReduce.

private boolean doReduce(InferenceSession session, HashSet<InferenceVariable> dependencies, List<ConstraintFormula> constraints) {
    if (!session.collectDependencies(myS, dependencies) && !session.collectDependencies(myT, dependencies)) {
        if (myT == null)
            return myS == null || myS.equalsToText(CommonClassNames.JAVA_LANG_OBJECT);
        if (myS == null)
            return true;
        return TypeConversionUtil.isAssignable(myT, myS);
    }
    if (PsiType.NULL.equals(myT) || myT == null)
        return false;
    if (PsiType.NULL.equals(myS) || myS == null || myT.equalsToText(CommonClassNames.JAVA_LANG_OBJECT))
        return true;
    if (PsiType.VOID.equals(myS) ^ PsiType.VOID.equals(myT))
        return false;
    InferenceVariable inferenceVariable = session.getInferenceVariable(myS);
    if (inferenceVariable != null) {
        InferenceVariable.addBound(myS, myT, InferenceBound.UPPER, session);
        return true;
    }
    inferenceVariable = session.getInferenceVariable(myT);
    if (inferenceVariable != null) {
        InferenceVariable.addBound(myT, myS, InferenceBound.LOWER, session);
        return true;
    }
    if (myT instanceof PsiArrayType) {
        PsiType sType = myS;
        if (myS instanceof PsiCapturedWildcardType) {
            final PsiType upperBound = ((PsiCapturedWildcardType) myS).getUpperBound();
            if (upperBound instanceof PsiArrayType) {
                sType = upperBound;
            }
        }
        //todo most specific array supertype
        if (!(sType instanceof PsiArrayType))
            return false;
        final PsiType tComponentType = ((PsiArrayType) myT).getComponentType();
        final PsiType sComponentType = ((PsiArrayType) sType).getComponentType();
        if (!(tComponentType instanceof PsiPrimitiveType) && !(sComponentType instanceof PsiPrimitiveType)) {
            constraints.add(new StrictSubtypingConstraint(tComponentType, sComponentType));
            return true;
        }
        return sComponentType instanceof PsiPrimitiveType && sComponentType.equals(tComponentType);
    }
    if (myT instanceof PsiClassType) {
        final PsiClassType.ClassResolveResult TResult = ((PsiClassType) myT).resolveGenerics();
        final PsiClass CClass = TResult.getElement();
        if (CClass != null) {
            if (CClass instanceof PsiTypeParameter) {
                if (myS instanceof PsiIntersectionType) {
                    for (PsiType conjunct : ((PsiIntersectionType) myS).getConjuncts()) {
                        if (myT.equals(conjunct))
                            return true;
                    }
                }
                final PsiType lowerBound = InferenceSession.getLowerBound(CClass);
                if (lowerBound != null) {
                    constraints.add(new StrictSubtypingConstraint(lowerBound, myS));
                    return true;
                }
                return false;
            }
            PsiClassType sType = null;
            if (myS instanceof PsiIntersectionType) {
                for (PsiType conjunct : ((PsiIntersectionType) myS).getConjuncts()) {
                    if (conjunct instanceof PsiClassType) {
                        final PsiClassType.ClassResolveResult conjunctResult = ((PsiClassType) conjunct).resolveGenerics();
                        if (InheritanceUtil.isInheritorOrSelf(conjunctResult.getElement(), CClass, true)) {
                            sType = (PsiClassType) conjunct;
                            break;
                        }
                    }
                }
            } else if (myS instanceof PsiClassType) {
                sType = (PsiClassType) myS;
            } else if (myS instanceof PsiArrayType) {
                return myT.isAssignableFrom(myS);
            } else if (myS instanceof PsiCapturedWildcardType) {
                final PsiType upperBound = ((PsiCapturedWildcardType) myS).getUpperBound();
                if (upperBound instanceof PsiClassType) {
                    sType = (PsiClassType) upperBound;
                } else if (upperBound instanceof PsiIntersectionType) {
                    for (PsiType type : ((PsiIntersectionType) upperBound).getConjuncts()) {
                        PsiClass sCandidate = PsiUtil.resolveClassInClassTypeOnly(type);
                        if (sCandidate != null && InheritanceUtil.isInheritorOrSelf(sCandidate, CClass, true)) {
                            sType = (PsiClassType) type;
                            break;
                        }
                    }
                }
            }
            if (sType == null)
                return false;
            final PsiClassType.ClassResolveResult SResult = sType.resolveGenerics();
            PsiClass SClass = SResult.getElement();
            if (SClass == null)
                return false;
            PsiSubstitutor substitutor = SResult.getSubstitutor();
            for (PsiTypeParameter typeParameter : SClass.getTypeParameters()) {
                substitutor = substitutor.put(typeParameter, substitutor.substituteWithBoundsPromotion(typeParameter));
            }
            if (((PsiClassType) myT).isRaw()) {
                return InheritanceUtil.isInheritorOrSelf(SClass, CClass, true);
            }
            final PsiSubstitutor tSubstitutor = TResult.getSubstitutor();
            final PsiSubstitutor sSubstitutor = TypeConversionUtil.getClassSubstitutor(CClass, SClass, substitutor);
            if (sSubstitutor != null) {
                for (PsiTypeParameter parameter : CClass.getTypeParameters()) {
                    final PsiType tSubstituted = tSubstitutor.substitute(parameter);
                    final PsiType sSubstituted = sSubstitutor.substitute(parameter);
                    if (tSubstituted == null ^ sSubstituted == null) {
                        return false;
                    }
                    constraints.add(new SubtypingConstraint(tSubstituted, sSubstituted));
                }
                return true;
            }
        }
        return false;
    }
    if (myT instanceof PsiIntersectionType) {
        for (PsiType conjunct : ((PsiIntersectionType) myT).getConjuncts()) {
            constraints.add(new StrictSubtypingConstraint(conjunct, myS));
        }
        return true;
    }
    if (myT instanceof PsiCapturedWildcardType) {
        PsiType lowerBound = ((PsiCapturedWildcardType) myT).getLowerBound();
        if (lowerBound != PsiType.NULL) {
            constraints.add(new StrictSubtypingConstraint(lowerBound, myS));
        }
    }
    return true;
}
Also used : InferenceVariable(com.intellij.psi.impl.source.resolve.graphInference.InferenceVariable)

Aggregations

InferenceVariable (com.intellij.psi.impl.source.resolve.graphInference.InferenceVariable)4 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 FunctionalInterfaceParameterizationUtil (com.intellij.psi.impl.source.resolve.graphInference.FunctionalInterfaceParameterizationUtil)1 InferenceSession (com.intellij.psi.impl.source.resolve.graphInference.InferenceSession)1 PsiPolyExpressionUtil (com.intellij.psi.impl.source.resolve.graphInference.PsiPolyExpressionUtil)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 HashSet (java.util.HashSet)1 List (java.util.List)1 Set (java.util.Set)1