public static List<List<InferenceVariable>> resolveOrder( Collection<InferenceVariable> vars, InferenceSession session) { Map<InferenceVariable, InferenceGraphNode<InferenceVariable>> nodes = new HashMap<InferenceVariable, InferenceGraphNode<InferenceVariable>>(); for (InferenceVariable var : vars) { nodes.put(var, new InferenceGraphNode<InferenceVariable>(var)); } for (InferenceVariable var : vars) { if (var.getInstantiation() != PsiType.NULL) continue; final InferenceGraphNode<InferenceVariable> node = nodes.get(var); final Set<InferenceVariable> dependencies = var.getDependencies(session); for (InferenceVariable dependentVariable : dependencies) { final InferenceGraphNode<InferenceVariable> dependency = nodes.get(dependentVariable); if (dependency != null) { node.addDependency(dependency); } } } final ArrayList<InferenceGraphNode<InferenceVariable>> acyclicNodes = initNodes(nodes.values()); return ContainerUtil.map( acyclicNodes, new Function<InferenceGraphNode<InferenceVariable>, List<InferenceVariable>>() { @Override public List<InferenceVariable> fun(InferenceGraphNode<InferenceVariable> node) { return node.getValue(); } }); }
private static CompoundInitialState createState(InferenceSession topLevelSession) { final PsiSubstitutor topInferenceSubstitutor = replaceVariables(topLevelSession.getInferenceVariables()); final Map<PsiElement, InitialInferenceState> nestedStates = new LinkedHashMap<PsiElement, InitialInferenceState>(); final InferenceSessionContainer copy = new InferenceSessionContainer() { @Override public PsiSubstitutor findNestedSubstitutor( PsiElement arg, @Nullable PsiSubstitutor defaultSession) { // for the case foo(bar(a -> m())): top level inference won't touch lambda "a -> m()" // for the case foo(a -> bar(b -> m())): top level inference would go till nested lambda // "b -> m()" and the state from top level could be found here by "bar(b -> m())" // but proceeding with additional constraints from saved point would produce new // expression constraints with different inference variables (could be found in // myNestedSessions) // which won't be found in the system if we won't reject stored sessions in such cases final PsiSubstitutor substitutor = super.findNestedSubstitutor(arg, null); if (substitutor != null) { return substitutor; } final InitialInferenceState state = nestedStates.get(PsiTreeUtil.getParentOfType(arg, PsiCall.class)); if (state != null) { return state.getInferenceSubstitutor(); } return super.findNestedSubstitutor(arg, defaultSession); } }; final Map<PsiElement, InferenceSession> nestedSessions = topLevelSession.getInferenceSessionContainer().myNestedSessions; for (Map.Entry<PsiElement, InferenceSession> entry : nestedSessions.entrySet()) { nestedStates.put( entry.getKey(), entry .getValue() .createInitialState( copy, topLevelSession.getInferenceVariables(), topInferenceSubstitutor)); } PsiSubstitutor substitutor = PsiSubstitutor.EMPTY; for (InferenceVariable variable : topLevelSession.getInferenceVariables()) { final PsiType instantiation = variable.getInstantiation(); if (instantiation != PsiType.NULL) { final PsiClass psiClass = PsiUtil.resolveClassInClassTypeOnly(topInferenceSubstitutor.substitute(variable)); if (psiClass instanceof InferenceVariable) { substitutor = substitutor.put((PsiTypeParameter) psiClass, instantiation); } } } return new CompoundInitialState(substitutor, nestedStates); }
boolean isFullyIncorporated() { boolean needFurtherIncorporation = false; for (InferenceVariable inferenceVariable : mySession.getInferenceVariables()) { if (inferenceVariable.getInstantiation() != PsiType.NULL) continue; final List<PsiType> eqBounds = inferenceVariable.getBounds(InferenceBound.EQ); final List<PsiType> upperBounds = inferenceVariable.getBounds(InferenceBound.UPPER); final List<PsiType> lowerBounds = inferenceVariable.getBounds(InferenceBound.LOWER); needFurtherIncorporation |= crossVariables(inferenceVariable, upperBounds, lowerBounds, InferenceBound.LOWER); needFurtherIncorporation |= crossVariables(inferenceVariable, lowerBounds, upperBounds, InferenceBound.UPPER); needFurtherIncorporation |= eqCrossVariables(inferenceVariable, eqBounds); } return !needFurtherIncorporation; }
public boolean incorporate() { final Collection<InferenceVariable> inferenceVariables = mySession.getInferenceVariables(); final PsiSubstitutor substitutor = mySession.retrieveNonPrimitiveEqualsBounds(inferenceVariables); for (InferenceVariable inferenceVariable : inferenceVariables) { if (inferenceVariable.getInstantiation() != PsiType.NULL) continue; final List<PsiType> eqBounds = inferenceVariable.getBounds(InferenceBound.EQ); final List<PsiType> upperBounds = inferenceVariable.getBounds(InferenceBound.UPPER); final List<PsiType> lowerBounds = inferenceVariable.getBounds(InferenceBound.LOWER); eqEq(eqBounds); upDown(lowerBounds, upperBounds, substitutor); upDown(eqBounds, upperBounds, substitutor); upDown(lowerBounds, eqBounds, substitutor); upUp(upperBounds); } for (Pair<PsiTypeParameter[], PsiClassType> capture : myCaptures) { final PsiClassType right = capture.second; final PsiClass gClass = right.resolve(); LOG.assertTrue(gClass != null); final PsiTypeParameter[] parameters = capture.first; PsiType[] typeArgs = right.getParameters(); if (parameters.length != typeArgs.length) continue; for (int i = 0; i < typeArgs.length; i++) { PsiType aType = typeArgs[i]; if (aType instanceof PsiCapturedWildcardType) { aType = ((PsiCapturedWildcardType) aType).getWildcard(); } final InferenceVariable inferenceVariable = mySession.getInferenceVariable(parameters[i]); LOG.assertTrue(inferenceVariable != null); final List<PsiType> eqBounds = inferenceVariable.getBounds(InferenceBound.EQ); final List<PsiType> upperBounds = inferenceVariable.getBounds(InferenceBound.UPPER); final List<PsiType> lowerBounds = inferenceVariable.getBounds(InferenceBound.LOWER); if (aType instanceof PsiWildcardType) { for (PsiType eqBound : eqBounds) { if (!isInferenceVariableOrFreshTypeParameter(eqBound)) return false; } final PsiClassType[] paramBounds = inferenceVariable.getParameter().getExtendsListTypes(); PsiType glb = null; for (PsiClassType paramBound : paramBounds) { if (glb == null) { glb = paramBound; } else { glb = GenericsUtil.getGreatestLowerBound(glb, paramBound); } } if (!((PsiWildcardType) aType).isBounded()) { for (PsiType upperBound : upperBounds) { if (glb != null && mySession.getInferenceVariable(upperBound) == null) { addConstraint( new StrictSubtypingConstraint( upperBound, mySession.substituteWithInferenceVariables(glb))); } } for (PsiType lowerBound : lowerBounds) { if (isInferenceVariableOrFreshTypeParameter(lowerBound)) return false; } } else if (((PsiWildcardType) aType).isExtends()) { final PsiType extendsBound = ((PsiWildcardType) aType).getExtendsBound(); for (PsiType upperBound : upperBounds) { if (mySession.getInferenceVariable(upperBound) == null) { if (paramBounds.length == 1 && paramBounds[0].equalsToText(CommonClassNames.JAVA_LANG_OBJECT) || paramBounds.length == 0) { addConstraint(new StrictSubtypingConstraint(upperBound, extendsBound)); } else if (extendsBound.equalsToText(CommonClassNames.JAVA_LANG_OBJECT) && glb != null) { addConstraint( new StrictSubtypingConstraint( upperBound, mySession.substituteWithInferenceVariables(glb))); } } } for (PsiType lowerBound : lowerBounds) { if (isInferenceVariableOrFreshTypeParameter(lowerBound)) return false; } } else { LOG.assertTrue(((PsiWildcardType) aType).isSuper()); final PsiType superBound = ((PsiWildcardType) aType).getSuperBound(); for (PsiType upperBound : upperBounds) { if (glb != null && mySession.getInferenceVariable(upperBound) == null) { addConstraint( new StrictSubtypingConstraint( mySession.substituteWithInferenceVariables(glb), upperBound)); } } for (PsiType lowerBound : lowerBounds) { if (mySession.getInferenceVariable(lowerBound) == null) { addConstraint(new StrictSubtypingConstraint(lowerBound, superBound)); } } } } else { inferenceVariable.addBound(aType, InferenceBound.EQ); } } } return true; }