ReductionSystem[] () { class Node { int myComponent = -1; final Constraint myConstraint; final Set<Node> myNeighbours = new HashSet<>(); Node() { myConstraint = null; } Node(final Constraint c) { myConstraint = c; } public Constraint getConstraint() { return myConstraint; } public void addEdge(final Node n) { if (!myNeighbours.contains(n)) { myNeighbours.add(n); n.addEdge(this); } } } final Node[] typeVariableNodes = new Node[myTypeVariableFactory.getNumber()]; final Node[] constraintNodes = new Node[myConstraints.size()]; final Map<Constraint, Set<PsiTypeVariable>> boundVariables = new HashMap<>(); for (int i = 0; i < typeVariableNodes.length; i++) { typeVariableNodes[i] = new Node(); } { int j = 0; for (final Constraint constraint : myConstraints) { constraintNodes[j++] = new Node(constraint); } } { int l = 0; for (final Constraint constraint : myConstraints) { final Set<PsiTypeVariable> boundVars = new LinkedHashSet<>(); final Node constraintNode = constraintNodes[l++]; new Object() { void visit(final Constraint c) { visit(c.getLeft()); visit(c.getRight()); } private void visit(final PsiType t) { if (t instanceof PsiTypeVariable) { boundVars.add((PsiTypeVariable)t); } else if (t instanceof PsiArrayType) { visit(t.getDeepComponentType()); } else if (t instanceof PsiClassType) { final PsiSubstitutor subst = Util.resolveType(t).getSubstitutor(); for (final PsiType type : subst.getSubstitutionMap().values()) { visit(type); } } else if (t instanceof PsiIntersectionType) { final PsiType[] conjuncts = ((PsiIntersectionType)t).getConjuncts(); for (PsiType conjunct : conjuncts) { visit(conjunct); } } else if (t instanceof PsiWildcardType) { final PsiType bound = ((PsiWildcardType)t).getBound(); if (bound != null) { visit(bound); } } } }.visit(constraint); final PsiTypeVariable[] bound = boundVars.toArray(new PsiTypeVariable[]{}); for (int j = 0; j < bound.length; j++) { final int x = bound[j].getIndex(); final Node typeVariableNode = typeVariableNodes[x]; typeVariableNode.addEdge(constraintNode); for (int k = j + 1; k < bound.length; k++) { final int y = bound[k].getIndex(); typeVariableNode.addEdge(typeVariableNodes[y]); } } boundVariables.put(constraint, boundVars); } } List<Set<PsiTypeVariable>> clusters = myTypeVariableFactory.getClusters(); for (final Set<PsiTypeVariable> cluster : clusters) { Node prev = null; for (final PsiTypeVariable variable : cluster) { final Node curr = typeVariableNodes[variable.getIndex()]; if (prev != null) { prev.addEdge(curr); } prev = curr; } } int currComponent = 0; for (final Node node : typeVariableNodes) { if (node.myComponent == -1) { final int component = currComponent; new Object() { void selectComponent(final Node n) { final LinkedList<Node> frontier = new LinkedList<>(); frontier.addFirst(n); while (frontier.size() > 0) { final Node curr = frontier.removeFirst(); curr.myComponent = component; for (final Node p : curr.myNeighbours) { if (p.myComponent == -1) { frontier.addFirst(p); } } } } }.selectComponent(node); currComponent++; } } final ReductionSystem[] systems = new ReductionSystem[currComponent]; for (final Node node : constraintNodes) { final Constraint constraint = node.getConstraint(); final int index = node.myComponent; if (systems[index] == null) { systems[index] = new ReductionSystem(myProject, myElements, myTypes, myTypeVariableFactory, mySettings); } systems[index].addConstraint(constraint, boundVariables.get(constraint)); } return systems; }