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 ddd44fe2c669..fc02d48081af 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 @@ -400,8 +400,8 @@ public class InferenceIncorporationPhase { } } - public PsiSubstitutor checkIncorporated(PsiSubstitutor substitutor) { - for (InferenceVariable variable : mySession.getInferenceVariables()) { //todo equals bounds? + public PsiSubstitutor checkIncorporated(PsiSubstitutor substitutor, Collection variables) { + for (InferenceVariable variable : variables) { //todo equals bounds? for (PsiType lowerBound : variable.getBounds(InferenceBound.LOWER)) { lowerBound = substitutor.substitute(lowerBound); if (mySession.isProperType(lowerBound)) { 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 02431e8a7f61..d851c5e9ecde 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 @@ -677,28 +677,57 @@ public class InferenceSession { private PsiSubstitutor resolveBounds(final Collection inferenceVariables, PsiSubstitutor substitutor) { - final List> independentVars = InferenceVariablesOrder.resolveOrder(inferenceVariables, this); - for (List vars : independentVars) { - substitutor = resolveSubset(vars, substitutor, true); - if (substitutor == null) { + final Collection allVars = new ArrayList(inferenceVariables); + while (!allVars.isEmpty()) { + final List vars = InferenceVariablesOrder.resolveOrder(allVars, this); + if (!myIncorporationPhase.hasCaptureConstraints(vars)) { + final PsiSubstitutor firstSubstitutor = resolveSubset(vars, substitutor, true); + if (firstSubstitutor != null) { + substitutor = firstSubstitutor; + allVars.removeAll(vars); + continue; + } + } + + for (InferenceVariable var : vars) { + final PsiTypeParameter copy = (PsiTypeParameter)var.getParameter().copy(); + final PsiType lub = getLowerBound(var, substitutor); + final PsiType glb = getUpperBound(var, substitutor); + final InferenceVariable zVariable = new InferenceVariable(copy); + zVariable.addBound(glb, InferenceBound.UPPER); + if (lub != PsiType.NULL) { + if (!TypeConversionUtil.isAssignable(glb, lub)) { + return null; + } + copy.putUserData(LOWER_BOUND, lub); + zVariable.addBound(lub, InferenceBound.LOWER); + } + myInferenceVariables.put(copy, zVariable); + } + myIncorporationPhase.forgetCaptures(vars); + if (!myIncorporationPhase.incorporate()) { return null; } } return substitutor; } - + + private PsiType getLowerBound(InferenceVariable var, PsiSubstitutor substitutor) { + return composeBound(var, InferenceBound.LOWER, new Function, PsiType>() { + @Override + public PsiType fun(Pair pair) { + return GenericsUtil.getLeastUpperBound(pair.first, pair.second, myManager); + } + }, substitutor); + } + @Nullable private PsiSubstitutor resolveSubset(Collection vars, PsiSubstitutor substitutor, boolean checkResult) { for (InferenceVariable var : vars) { LOG.assertTrue(var.getInstantiation() == PsiType.NULL); final PsiTypeParameter typeParameter = var.getParameter(); final PsiType eqBound = getEqualsBound(var, substitutor); - final PsiType lub = eqBound != PsiType.NULL && (myErased || eqBound != null) ? eqBound : composeBound(var, InferenceBound.LOWER, new Function, PsiType>() { - @Override - public PsiType fun(Pair pair) { - return GenericsUtil.getLeastUpperBound(pair.first, pair.second, myManager); - } - }, substitutor); + final PsiType lub = eqBound != PsiType.NULL && (myErased || eqBound != null) ? eqBound : getLowerBound(var, substitutor); if (lub != PsiType.NULL) { substitutor = substitutor.put(typeParameter, lub); } @@ -707,16 +736,20 @@ public class InferenceSession { substitutor = substitutor.put(typeParameter, runtimeException); } else { - substitutor = substitutor.put(typeParameter, composeBound(var, InferenceBound.UPPER, new Function, PsiType>() { - @Override - public PsiType fun(Pair pair) { - return GenericsUtil.getGreatestLowerBound(pair.first, pair.second); - } - }, substitutor)); + substitutor = substitutor.put(typeParameter, getUpperBound(var, substitutor)); } } - return checkResult ? myIncorporationPhase.checkIncorporated(substitutor) : substitutor; + return checkResult ? myIncorporationPhase.checkIncorporated(substitutor, vars) : substitutor; + } + + private PsiType getUpperBound(InferenceVariable var, PsiSubstitutor substitutor) { + return composeBound(var, InferenceBound.UPPER, new Function, PsiType>() { + @Override + public PsiType fun(Pair pair) { + return GenericsUtil.getGreatestLowerBound(pair.first, pair.second); + } + }, substitutor); } public PsiType getEqualsBound(InferenceVariable var, PsiSubstitutor substitutor) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceVariablesOrder.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceVariablesOrder.java index cd87df6af8a2..1c91b060b6a8 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceVariablesOrder.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceVariablesOrder.java @@ -28,7 +28,7 @@ import java.util.*; public class InferenceVariablesOrder { - public static List> resolveOrder(Collection vars, InferenceSession session) { + public static List resolveOrder(Collection vars, InferenceSession session) { Map> nodes = new LinkedHashMap>(); for (InferenceVariable var : vars) { @@ -52,7 +52,7 @@ public class InferenceVariablesOrder { public List fun(InferenceGraphNode node) { return node.getValue(); } - }); + }).iterator().next(); } public static List>> tarjan(Collection> nodes) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/StrictSubtypingConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/StrictSubtypingConstraint.java index 88accf95e0d4..6ceefff956de 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/StrictSubtypingConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/StrictSubtypingConstraint.java @@ -83,7 +83,11 @@ public class StrictSubtypingConstraint implements ConstraintFormula { if (myT.equals(conjunct)) return true; } } - //todo ((PsiTypeParameter)C).getLowerBound() + final PsiType lowerBound = CClass.getUserData(InferenceSession.LOWER_BOUND); + if (lowerBound != null) { + constraints.add(new StrictSubtypingConstraint(lowerBound, myS)); + return true; + } return false; }