diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceIncorporationPhase.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceIncorporationPhase.java index 47bd85bcee12..d98d0e5bda38 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceIncorporationPhase.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceIncorporationPhase.java @@ -15,6 +15,7 @@ */ package com.intellij.psi.impl.source.resolve.graphInference; +import com.intellij.openapi.util.Pair; import com.intellij.psi.*; import com.intellij.psi.impl.source.resolve.graphInference.constraints.ConstraintFormula; import com.intellij.psi.impl.source.resolve.graphInference.constraints.StrictSubtypingConstraint; @@ -22,6 +23,7 @@ import com.intellij.psi.impl.source.resolve.graphInference.constraints.TypeEqual import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.TypeConversionUtil; +import com.intellij.util.Processor; import java.util.LinkedHashSet; import java.util.List; @@ -168,7 +170,21 @@ public class InferenceIncorporationPhase { * there exists a supertype (4.10) of S of the form G and a supertype of T of the form G, * then for all i, 1 ≤ i ≤ n, if Si and Ti are types (not wildcards), the constraint ⟨Si = Ti⟩ is implied. */ - private void upUp(List upperBounds) { + private boolean upUp(List upperBounds) { + return findParameterizationOfTheSameGenericClass(upperBounds, new Processor>() { + @Override + public boolean process(Pair pair) { + final PsiType sType = pair.first; + final PsiType tType = pair.second; + if (!(sType instanceof PsiWildcardType) && !(tType instanceof PsiWildcardType) && sType != null && tType != null) { + addConstraint(new TypeEqualityConstraint(sType, tType)); + } + return true; + } + }); + } + + public static boolean findParameterizationOfTheSameGenericClass(List upperBounds, Processor> processor) { for (int i = 0; i < upperBounds.size(); i++) { final PsiType sBound = upperBounds.get(i); final PsiClass sClass = PsiUtil.resolveClassInClassTypeOnly(sBound); @@ -188,14 +204,15 @@ public class InferenceIncorporationPhase { for (PsiTypeParameter typeParameter : gClass.getTypeParameters()) { final PsiType sType = sSubstitutor.substitute(typeParameter); final PsiType tType = tSubstitutor.substitute(typeParameter); - if (!(sType instanceof PsiWildcardType) && !(tType instanceof PsiWildcardType) && sType != null && tType != null) { - addConstraint(new TypeEqualityConstraint(sType, tType)); + if (!processor.process(Pair.create(sType, tType))) { + return true; } } } } } } + return false; } private void addConstraint(ConstraintFormula constraint) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java index b299384e7e40..efa764768fd8 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java @@ -35,6 +35,7 @@ import com.intellij.psi.util.PsiTypesUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.TypeConversionUtil; import com.intellij.util.ArrayUtilRt; +import com.intellij.util.Processor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -345,10 +346,16 @@ public class InferenceSession { private InferenceVariable shouldResolveAndInstantiate(PsiType returnType, PsiType targetType) { final InferenceVariable inferenceVariable = getInferenceVariable(returnType); if (inferenceVariable != null) { - if (targetType instanceof PsiPrimitiveType && hasPrimitiveWrapperBound(inferenceVariable) || - targetType instanceof PsiClassType && (hasUncheckedBounds(inferenceVariable, (PsiClassType)targetType) || myErased)) { + if (targetType instanceof PsiPrimitiveType && hasPrimitiveWrapperBound(inferenceVariable)) { return inferenceVariable; } + if (targetType instanceof PsiClassType) { + if (myErased || + hasUncheckedBounds(inferenceVariable, (PsiClassType)targetType) || + hasWildcardParameterization(inferenceVariable, (PsiClassType)targetType)) { + return inferenceVariable; + } + } } return null; } @@ -381,6 +388,30 @@ public class InferenceSession { return false; } + private static boolean hasWildcardParameterization(InferenceVariable inferenceVariable, PsiClassType targetType) { + if (FunctionalInterfaceParameterizationUtil.isWildcardParameterized(targetType)) { + final List bounds = inferenceVariable.getBounds(InferenceBound.LOWER); + final Processor> differentParameterizationProcessor = new Processor>() { + @Override + public boolean process(Pair pair) { + return pair.first == null || pair.second == null || pair.first.equals(pair.second); + } + }; + if (InferenceIncorporationPhase.findParameterizationOfTheSameGenericClass(bounds, differentParameterizationProcessor)) return true; + final List eqBounds = inferenceVariable.getBounds(InferenceBound.EQ); + for (PsiType lowBound : bounds) { + if (FunctionalInterfaceParameterizationUtil.isWildcardParameterized(lowBound)) { + for (PsiType bound : eqBounds) { + if (lowBound.equals(bound)) { + return true; + } + } + } + } + } + return false; + } + private PsiType getTargetType(final PsiExpression context, PsiType returnType) { final PsiElement parent = PsiUtil.skipParenthesizedExprUp(context.getParent()); if (parent instanceof PsiExpressionList) {