anchor.diff:      //   Null if Null <: T2
       //   Never otherwise
       for (String t1 in nullPredicateEnumeration.keys) {
  -      testLower(t1, "A*", t1, typeParameters: nullPredicateEnumeration[t1]);
  -      testLower(t1, "A?", t1, typeParameters: nullPredicateEnumeration[t1]);
  -      testLower(t1, "A", "Never", typeParameters: nullPredicateEnumeration[t1]);
  +      checkLowerBound(
  +          type1: t1,
  +          type2: "A*",
  +          lowerBound: t1,
  +          typeParameters: nullPredicateEnumeration[t1]);
  +      checkLowerBound(
  +          type1: t1,
  +          type2: "A?",
  +          lowerBound: t1,
  +          typeParameters: nullPredicateEnumeration[t1]);
  +      checkLowerBound(
  +          type1: t1,
  +          type2: "A",
  +          lowerBound: "Never",
  +          typeParameters: nullPredicateEnumeration[t1]);
       }
   
       // DOWN(T1, Null) =
       //   Null if Null <: T1
       //   Never otherwise
       for (String t2 in nullPredicateEnumeration.keys) {
  -      testLower("A*", t2, t2, typeParameters: nullPredicateEnumeration[t2]);
  -      testLower("A?", t2, t2, typeParameters: nullPredicateEnumeration[t2]);
  -      testLower("A", t2, "Never", typeParameters: nullPredicateEnumeration[t2]);
  +      checkLowerBound(
  +          type1: "A*",
  +          type2: t2,
  +          lowerBound: t2,
  +          typeParameters: nullPredicateEnumeration[t2]);
  +      checkLowerBound(
  +          type1: "A?",
  +          type2: t2,
  +          lowerBound: t2,
  +          typeParameters: nullPredicateEnumeration[t2]);
  +      checkLowerBound(
  +          type1: "A",
  +          type2: t2,
  +          lowerBound: "Never",
  +          typeParameters: nullPredicateEnumeration[t2]);
       }
     }
   
     void test_lower_bound_object() {
  -    _initialize("");
  -
  -    testLower("Object", "FutureOr<Null>", "FutureOr<Never>");
  -    testLower("FutureOr<Null>", "Object", "FutureOr<Never>");
  +    parseTestLibrary("");
  +
  +    checkLowerBound(
  +        type1: "Object",
  +        type2: "FutureOr<Null>",
  +        lowerBound: "FutureOr<Never>");
  +    checkLowerBound(
  +        type1: "FutureOr<Null>",
  +        type2: "Object",
  +        lowerBound: "FutureOr<Never>");
   
       // FutureOr<dynamic> is top.
  -    testLower("Object", "FutureOr<dynamic>", "Object");
  -    testLower("FutureOr<dynamic>", "Object", "Object");
  +    checkLowerBound(
  +        type1: "Object", type2: "FutureOr<dynamic>", lowerBound: "Object");
  +    checkLowerBound(
  +        type1: "FutureOr<dynamic>", type2: "Object", lowerBound: "Object");
   
       // FutureOr<X> is not top and cannot be made non-nullable.
  -    testLower("Object", "FutureOr<X>", "Never",
  +    checkLowerBound(
  +        type1: "Object",
  +        type2: "FutureOr<X>",
  +        lowerBound: "Never",
           typeParameters: 'X extends dynamic');
  -    testLower("FutureOr<X>", "Object", "Never",
  +    checkLowerBound(
  +        type1: "FutureOr<X>",
  +        type2: "Object",
  +        lowerBound: "Never",
           typeParameters: 'X extends dynamic');
   
       // FutureOr<void> is top.
  -    testLower("Object", "FutureOr<void>", "Object");
  -    testLower("FutureOr<void>", "Object", "Object");
  +    checkLowerBound(
  +        type1: "Object", type2: "FutureOr<void>", lowerBound: "Object");
  +    checkLowerBound(
  +        type1: "FutureOr<void>", type2: "Object", lowerBound: "Object");
     }
   
     void test_lower_bound_function() {
  -    const String testSdk = """
  +    parseTestLibrary("""
         class A;
         class B extends A;
  -    """;
  -    _initialize(testSdk);
  +    """);
   
       // TODO(dmitryas): Test for various nullabilities.
  -    testLower("() ->* A*", "() ->* B*", "() ->* B*");
  -    testLower("() ->* void", "(A*, B*) ->* void", "([A*, B*]) ->* void");
  -    testLower("(A*, B*) ->* void", "() ->* void", "([A*, B*]) ->* void");
  -    testLower("(A*) ->* void", "(B*) ->* void", "(A*) ->* void");
  -    testLower("(B*) ->* void", "(A*) ->* void", "(A*) ->* void");
  -    testLower(
  -        "({A* a}) ->* void", "({B* b}) ->* void", "({A* a, B* b}) ->* void");
  -    testLower(
  -        "({B* b}) ->* void", "({A* a}) ->* void", "({A* a, B* b}) ->* void");
  -    testLower("({A* a, A* c}) ->* void", "({B* b, B* d}) ->* void",
  -        "({A* a, B* b, A* c, B* d}) ->* void");
  -    testLower("({A* a, B* b}) ->* void", "({B* a, A* b}) ->* void",
  -        "({A* a, A* b}) ->* void");
  -    testLower("({B* a, A* b}) ->* void", "({A* a, B* b}) ->* void",
  -        "({A* a, A* b}) ->* void");
  -    testLower(
  -        "(B*, {A* a}) ->* void", "(B*) ->* void", "(B*, {A* a}) ->* void");
  -    testLower("({A* a}) -> void", "(B*) -> void", "Never");
  -    testLower("({A* a}) -> void", "([B*]) ->* void", "Never");
  -    testLower("<X>() -> void", "<Y>() -> void", "<Z>() -> void");
  -    testLower("<X>(X) -> List<X>", "<Y>(Y) -> List<Y>", "<Z>(Z) -> List<Z>");
  -    testLower(
  -        "<X1, X2 extends List<X1>>(X1) -> X2",
  -        "<Y1, Y2 extends List<Y1>>(Y1) -> Y2",
  -        "<Z1, Z2 extends List<Z1>>(Z1) -> Z2");
  -    testLower(
  -        "<X extends int>(X) -> void", "<Y extends double>(Y) -> void", "Never");
  -
  -    testLower(
  -        "({required A a, A b, required A c, A d, required A e}) -> A",
  -        "({required B a, required B b, B c, B f, required B g}) -> B",
  -        "({required A a, A b, A c, A d, A e, B f, B g}) -> B");
  -
  -    testLower("<X extends dynamic>() -> void", "<Y extends Object?>() -> void",
  -        "<Z extends dynamic>() -> void");
  -    testLower("<X extends Null>() -> void", "<Y extends Never?>() -> void",
  -        "<Z extends Null>() -> void");
  -    testLower(
  -        "<X extends FutureOr<dynamic>?>() -> void",
  -        "<Y extends FutureOr<Object?>>() -> void",
  -        "<Z extends FutureOr<dynamic>?>() -> void");
  +    checkLowerBound(
  +        type1: "() ->* A*", type2: "() ->* B*", lowerBound: "() ->* B*");
  +    checkLowerBound(
  +        type1: "() ->* void",
  +        type2: "(A*, B*) ->* void",
  +        lowerBound: "([A*, B*]) ->* void");
  +    checkLowerBound(
  +        type1: "(A*, B*) ->* void",
  +        type2: "() ->* void",
  +        lowerBound: "([A*, B*]) ->* void");
  +    checkLowerBound(
  +        type1: "(A*) ->* void",
  +        type2: "(B*) ->* void",
  +        lowerBound: "(A*) ->* void");
  +    checkLowerBound(
  +        type1: "(B*) ->* void",
  +        type2: "(A*) ->* void",
  +        lowerBound: "(A*) ->* void");
  +    checkLowerBound(
  +        type1: "({A* a}) ->* void",
  +        type2: "({B* b}) ->* void",
  +        lowerBound: "({A* a, B* b}) ->* void");
  +    checkLowerBound(
  +        type1: "({B* b}) ->* void",
  +        type2: "({A* a}) ->* void",
  +        lowerBound: "({A* a, B* b}) ->* void");
  +    checkLowerBound(
  +        type1: "({A* a, A* c}) ->* void",
  +        type2: "({B* b, B* d}) ->* void",
  +        lowerBound: "({A* a, B* b, A* c, B* d}) ->* void");
  +    checkLowerBound(
  +        type1: "({A* a, B* b}) ->* void",
  +        type2: "({B* a, A* b}) ->* void",
  +        lowerBound: "({A* a, A* b}) ->* void");
  +    checkLowerBound(
  +        type1: "({B* a, A* b}) ->* void",
  +        type2: "({A* a, B* b}) ->* void",
  +        lowerBound: "({A* a, A* b}) ->* void");
  +    checkLowerBound(
  +        type1: "(B*, {A* a}) ->* void",
  +        type2: "(B*) ->* void",
  +        lowerBound: "(B*, {A* a}) ->* void");
  +    checkLowerBound(
  +        type1: "({A* a}) -> void", type2: "(B*) -> void", lowerBound: "Never");
  +    checkLowerBound(
  +        type1: "({A* a}) -> void",
  +        type2: "([B*]) ->* void",
  +        lowerBound: "Never");
  +    checkLowerBound(
  +        type1: "<X>() -> void",
  +        type2: "<Y>() -> void",
  +        lowerBound: "<Z>() -> void");
  +    checkLowerBound(
  +        type1: "<X>(X) -> List<X>",
  +        type2: "<Y>(Y) -> List<Y>",
  +        lowerBound: "<Z>(Z) -> List<Z>");
  +    checkLowerBound(
  +        type1: "<X1, X2 extends List<X1>>(X1) -> X2",
  +        type2: "<Y1, Y2 extends List<Y1>>(Y1) -> Y2",
  +        lowerBound: "<Z1, Z2 extends List<Z1>>(Z1) -> Z2");
  +    checkLowerBound(
  +        type1: "<X extends int>(X) -> void",
  +        type2: "<Y extends double>(Y) -> void",
  +        lowerBound: "Never");
  +
  +    checkLowerBound(
  +        type1: "({required A a, A b, required A c, A d, required A e}) -> A",
  +        type2: "({required B a, required B b, B c, B f, required B g}) -> B",
  +        lowerBound: "({required A a, A b, A c, A d, A e, B f, B g}) -> B");
  +
  +    checkLowerBound(
  +        type1: "<X extends dynamic>() -> void",
  +        type2: "<Y extends Object?>() -> void",
  +        lowerBound: "<Z extends dynamic>() -> void");
  +    checkLowerBound(
  +        type1: "<X extends Null>() -> void",
  +        type2: "<Y extends Never?>() -> void",
  +        lowerBound: "<Z extends Null>() -> void");
  +    checkLowerBound(
  +        type1: "<X extends FutureOr<dynamic>?>() -> void",
  +        type2: "<Y extends FutureOr<Object?>>() -> void",
  +        lowerBound: "<Z extends FutureOr<dynamic>?>() -> void");
     }
   
     void test_lower_bound_identical() {
  -    _initialize("class A;");
  -
  -    testLower("A*", "A*", "A*");
  -    testLower("A?", "A?", "A?");
  -    testLower("A", "A", "A");
  +    parseTestLibrary("class A;");
  +
  +    checkLowerBound(type1: "A*", type2: "A*", lowerBound: "A*");
  +    checkLowerBound(type1: "A?", type2: "A?", lowerBound: "A?");
  +    checkLowerBound(type1: "A", type2: "A", lowerBound: "A");
     }
   
     void test_lower_bound_subtype() {
  -    const String testSdk = """
  +    parseTestLibrary("""
         class A;
         class B extends A;
  -    """;
  -    _initialize(testSdk);
  -
  -    testLower("A*", "B*", "B*");
  -    testLower("A*", "B?", "B*");
  -    testLower("A*", "B", "B");
  -
  -    testLower("A?", "B*", "B*");
  -    testLower("A?", "B?", "B?");
  -    testLower("A?", "B", "B");
  -
  -    testLower("A", "B*", "B");
  -    testLower("A", "B?", "B");
  -    testLower("A", "B", "B");
  -
  -    testLower("B*", "A*", "B*");
  -    testLower("B?", "A*", "B*");
  -    testLower("B", "A*", "B");
  -
  -    testLower("B*", "A?", "B*");
  -    testLower("B?", "A?", "B?");
  -    testLower("B", "A?", "B");
  -
  -    testLower("B*", "A", "B");
  -    testLower("B?", "A", "B");
  -    testLower("B", "A", "B");
  -
  -    testLower("Iterable<A>*", "List<B>*", "List<B>*");
  -    testLower("Iterable<A>*", "List<B>?", "List<B>*");
  -    testLower("Iterable<A>*", "List<B>", "List<B>");
  -
  -    testLower("Iterable<A>?", "List<B>*", "List<B>*");
  -    testLower("Iterable<A>?", "List<B>?", "List<B>?");
  -    testLower("Iterable<A>?", "List<B>", "List<B>");
  -
  -    testLower("Iterable<A>", "List<B>*", "List<B>");
  -    testLower("Iterable<A>", "List<B>?", "List<B>");
  -    testLower("Iterable<A>", "List<B>", "List<B>");
  -
  -    testLower("List<B>*", "Iterable<A>*", "List<B>*");
  -    testLower("List<B>?", "Iterable<A>*", "List<B>*");
  -    testLower("List<B>", "Iterable<A>*", "List<B>");
  -
  -    testLower("List<B>*", "Iterable<A>?", "List<B>*");
  -    testLower("List<B>?", "Iterable<A>?", "List<B>?");
  -    testLower("List<B>", "Iterable<A>?", "List<B>");
  -
  -    testLower("List<B>*", "Iterable<A>", "List<B>");
  -    testLower("List<B>?", "Iterable<A>", "List<B>");
  -    testLower("List<B>", "Iterable<A>", "List<B>");
  +    """);
  +
  +    checkLowerBound(type1: "A*", type2: "B*", lowerBound: "B*");
  +    checkLowerBound(type1: "A*", type2: "B?", lowerBound: "B*");
  +    checkLowerBound(type1: "A*", type2: "B", lowerBound: "B");
  +
  +    checkLowerBound(type1: "A?", type2: "B*", lowerBound: "B*");
  +    checkLowerBound(type1: "A?", type2: "B?", lowerBound: "B?");
  +    checkLowerBound(type1: "A?", type2: "B", lowerBound: "B");
  +
  +    checkLowerBound(type1: "A", type2: "B*", lowerBound: "B");
  +    checkLowerBound(type1: "A", type2: "B?", lowerBound: "B");
  +    checkLowerBound(type1: "A", type2: "B", lowerBound: "B");
  +
  +    checkLowerBound(type1: "B*", type2: "A*", lowerBound: "B*");
  +    checkLowerBound(type1: "B?", type2: "A*", lowerBound: "B*");
  +    checkLowerBound(type1: "B", type2: "A*", lowerBound: "B");
  +
  +    checkLowerBound(type1: "B*", type2: "A?", lowerBound: "B*");
  +    checkLowerBound(type1: "B?", type2: "A?", lowerBound: "B?");
  +    checkLowerBound(type1: "B", type2: "A?", lowerBound: "B");
  +
  +    checkLowerBound(type1: "B*", type2: "A", lowerBound: "B");
  +    checkLowerBound(type1: "B?", type2: "A", lowerBound: "B");
  +    checkLowerBound(type1: "B", type2: "A", lowerBound: "B");
  +
  +    checkLowerBound(
  +        type1: "Iterable<A>*", type2: "List<B>*", lowerBound: "List<B>*");
  +    checkLowerBound(
  +        type1: "Iterable<A>*", type2: "List<B>?", lowerBound: "List<B>*");
  +    checkLowerBound(
  +        type1: "Iterable<A>*", type2: "List<B>", lowerBound: "List<B>");
  +
  +    checkLowerBound(
  +        type1: "Iterable<A>?", type2: "List<B>*", lowerBound: "List<B>*");
  +    checkLowerBound(
  +        type1: "Iterable<A>?", type2: "List<B>?", lowerBound: "List<B>?");
  +    checkLowerBound(
  +        type1: "Iterable<A>?", type2: "List<B>", lowerBound: "List<B>");
  +
  +    checkLowerBound(
  +        type1: "Iterable<A>", type2: "List<B>*", lowerBound: "List<B>");
  +    checkLowerBound(
  +        type1: "Iterable<A>", type2: "List<B>?", lowerBound: "List<B>");
  +    checkLowerBound(
  +        type1: "Iterable<A>", type2: "List<B>", lowerBound: "List<B>");
  +
  +    checkLowerBound(
  +        type1: "List<B>*", type2: "Iterable<A>*", lowerBound: "List<B>*");
  +    checkLowerBound(
  +        type1: "List<B>?", type2: "Iterable<A>*", lowerBound: "List<B>*");
  +    checkLowerBound(
  +        type1: "List<B>", type2: "Iterable<A>*", lowerBound: "List<B>");
  +
  +    checkLowerBound(
  +        type1: "List<B>*", type2: "Iterable<A>?", lowerBound: "List<B>*");
  +    checkLowerBound(
  +        type1: "List<B>?", type2: "Iterable<A>?", lowerBound: "List<B>?");
  +    checkLowerBound(
  +        type1: "List<B>", type2: "Iterable<A>?", lowerBound: "List<B>");
  +
  +    checkLowerBound(
  +        type1: "List<B>*", type2: "Iterable<A>", lowerBound: "List<B>");
  +    checkLowerBound(
  +        type1: "List<B>?", type2: "Iterable<A>", lowerBound: "List<B>");
  +    checkLowerBound(
  +        type1: "List<B>", type2: "Iterable<A>", lowerBound: "List<B>");
     }
   
     void test_lower_bound_top() {
  -    _initialize("class A;");
  +    parseTestLibrary("class A;");
   
       // TODO(dmitryas): Test for various nullabilities.
  -    testLower("dynamic", "A*", "A*");
  -    testLower("A*", "dynamic", "A*");
  -    testLower("Object?", "A*", "A*");
  -    testLower("A*", "Object?", "A*");
  -    testLower("void", "A*", "A*");
  -    testLower("A*", "void", "A*");
  +    checkLowerBound(type1: "dynamic", type2: "A*", lowerBound: "A*");
  +    checkLowerBound(type1: "A*", type2: "dynamic", lowerBound: "A*");
  +    checkLowerBound(type1: "Object?", type2: "A*", lowerBound: "A*");
  +    checkLowerBound(type1: "A*", type2: "Object?", lowerBound: "A*");
  +    checkLowerBound(type1: "void", type2: "A*", lowerBound: "A*");
  +    checkLowerBound(type1: "A*", type2: "void", lowerBound: "A*");
   
       // DOWN(T1, T2) where TOP(T1) and TOP(T2) =
       //   T1 if MORETOP(T2, T1)
  
positive.code:       for (String t2 in objectPredicateEnumeration.keys) {
          String typeParameters = joinTypeParameters(
              objectPredicateEnumeration[t1], objectPredicateEnumeration[t2]);
          String expected = env.moretop(
                  toType(t1, typeParameters: typeParameters),
                  toType(t2, typeParameters: typeParameters))
              ? t1
              : t2;
          testUpper(t1, t2, expected, typeParameters: typeParameters);
        }
      }
  
  
negative.code:       for (String t2 in nullPredicateEnumeration.keys) {
          String typeParameters = joinTypeParameters(
              nullPredicateEnumeration[t1], nullPredicateEnumeration[t2]);
          typeParserEnvironment.withTypeParameters(typeParameters, (_) {
            String expected =
                typeSchemaEnvironment.morebottom(parseType(t1), parseType(t2))
                    ? t2
                    : t1;
            checkUpperBound(
                type1: t1,
                type2: t2,
                upperBound: expected,
                typeParameters: typeParameters);
          });
        }
      }
  
  