import org.checkerframework.checker.nullness.qual.*;

interface Consumer<A extends @Nullable Object> {
  public void consume(A object);
}

class Utils {

  public static <B extends @Nullable Object> Consumer<B> cast(
      final @Nullable Consumer<? super B> consumer) {
    throw new RuntimeException();
  }

  public static <C extends @Nullable Object> Consumer<C> getConsumer() {
    // null for simplicity, but could be anything
    Consumer<@Nullable Object> nullConsumer = null;

    // Previous reasoning for this to generate an (argument) error was:
    // C could be @NonNull Object, so argument is incompatible?
    //
    // This is poor reasoning, however, because the type of the formal parameter should be:
    // @Nullable Consumer< ? [
    //                         super C[ extends @Nullable Object
    //                                  super @NonNull  Void
    //                                ]
    //                         extends @Nullable Object
    // ]
    // The primary annotations on nullConsumer and the formal parameter consumer are
    // identical, so it comes down to the annotations on the type arguments.

    // Let X stand in for the type argument of nullConsumer.  For it to be a valid parameter, X
    // must be contained by the type argument of the formal parameter, ? super C.
    //
    // In other words, the following constraints must hold:
    //
    // C1: X <: upper bound of (? super C)
    // C2: lower bound of (? super C) <: X
    //
    // we can simplify these constraints by substituting out the lower and upper bound of
    // ? super C.
    // C1: X <: @Nullable Object
    // C2: C <: X
    //
    // we can simplify the constraints again by substituting X with the actual type argument to
    // nullConsumer and in C2, we can substitute C with its upper bound, since for the
    // constraint to hold X must be above C's upper bound.  This yields:
    //
    // C1: @Nullable Object <: @Nullable Object
    // C2: @Nullable Object <: @Nullable Object
    //
    // Since, for all type's T => T <: T, both C1 and C2 are upheld and the following statement
    // should NOT report an error
    Consumer<C> result = Utils.<C>cast(nullConsumer);

    // on a side note, I am not sure why this is called unexpected raw
    return result;
  }
}
