public ReductionSystem[] isolate() {
    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;
  }
public ReductionSystem[] isolate()