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;
}
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;
}
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;
}
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;
}
Aggregations