private static PuritySolver collectPurityEquations(EKey key, EquationProvider<?> provider) throws EquationsLimitException {
    PuritySolver puritySolver = new PuritySolver();
    Set<EKey> queued = new HashSet<>();
    Deque<EKey> queue = new ArrayDeque<>();

    queue.push(key);
    queued.add(key);
    DataValue returnValue = null;

    while (!queue.isEmpty()) {
      if (queued.size() > EQUATIONS_LIMIT) {
        throw new EquationsLimitException();
      }
      ProgressManager.checkCanceled();
      EKey curKey = queue.pop();

      boolean stable = true;
      Effects combined = null;
      for (Equations equations : provider.getEquations(curKey.member)) {
        stable &= equations.stable;
        Effects effects = (Effects)equations.find(curKey.getDirection())
          .orElseGet(() -> new Effects(DataValue.UnknownDataValue1,
                                       curKey.getDirection() == Volatile ? Collections.emptySet() : Effects.TOP_EFFECTS));
        combined = combined == null ? effects : combined.combine(effects);
      }
      if (combined != null) {
        if (curKey == key && combined.returnValue.dependencies().findFirst().isEmpty()) {
          returnValue = combined.returnValue;
          if (combined.isTop()) {
            return puritySolver;
          }
        }
        else if (returnValue != null && combined.isTop()) {
          PuritySolver trivialSolver = new PuritySolver();
          trivialSolver.addEquation(key, new Effects(returnValue, Effects.TOP_EFFECTS));
          return trivialSolver;
        }
        combined.processDependencies(dep -> {
          if (queued.add(dep)) {
            queue.push(dep);
          }
        });
        puritySolver.addEquation(withStability(curKey, stable), combined);
      }
    }
    puritySolver.addPlainFieldEquations(md -> true);
    return puritySolver;
  }
private static PuritySolver collectPurityEquations(EKey key, EquationProvider<?> provider)