public class InferTypeArgs2<V extends InferTypeArgs2<V>> {}

// having a concrete extension of InferTypeArgs2 is the key difference between this and
// InferTypeArgs1.java.  In this case we end up comparing CFValue with V extends InferTypeArgs2<V>
// which kicks off the DefaultRawnessComparer.  Before I fixed it, it then blew the stack
class CFValue extends InferTypeArgs2<CFValue> {
  public CFValue(InferTypeArgsAnalysis<CFValue, ?, ?> analysis) {}
}

class CFAbstractStore<V extends InferTypeArgs2<V>, S extends CFAbstractStore<V, S>> {}

class CFAbstractTransfer<
    V extends InferTypeArgs2<V>,
    S extends CFAbstractStore<V, S>,
    T extends CFAbstractTransfer<V, S, T>> {}

class InferTypeArgsAnalysis<
    V extends InferTypeArgs2<V>,
    S extends CFAbstractStore<V, S>,
    T extends CFAbstractTransfer<V, S, T>> {
  public CFValue defaultCreateAbstractValue(InferTypeArgsAnalysis<CFValue, ?, ?> analysis) {
    return new CFValue(analysis);
  }
}
