Version 2.11.0-159.0.dev

Merge commit 'd3114bac63b8ec22e8dfee4bb91b3f4c8c1fab59' into 'dev'
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_constraint_gatherer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_constraint_gatherer.dart
index 874d7be..2464c9a 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_constraint_gatherer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_constraint_gatherer.dart
@@ -8,8 +8,6 @@
 
 import 'package:kernel/type_algebra.dart';
 
-import 'package:kernel/src/replacement_visitor.dart';
-
 import 'package:kernel/type_environment.dart';
 
 import 'type_schema.dart' show UnknownType;
@@ -877,12 +875,18 @@
           List<_ProtoConstraint> constraints =
               _protoConstraints.sublist(baseConstraintCount);
           _protoConstraints.length = baseConstraintCount;
-          _NullabilityAwareTypeVariableEliminator eliminator =
-              new _NullabilityAwareTypeVariableEliminator(
-                  freshTypeParameters.freshTypeParameters.toSet(),
-                  const NeverType(Nullability.nonNullable),
-                  coreTypes.objectNullableRawType,
-                  coreTypes.functionNonNullableRawType);
+          NullabilityAwareTypeVariableEliminator eliminator =
+              new NullabilityAwareTypeVariableEliminator(
+                  eliminationTargets:
+                      freshTypeParameters.freshTypeParameters.toSet(),
+                  bottomType: const NeverType(Nullability.nonNullable),
+                  topType: coreTypes.objectNullableRawType,
+                  topFunctionType: coreTypes.functionNonNullableRawType,
+                  unhandledTypeHandler: (DartType type, ignored) =>
+                      type is UnknownType
+                          ? false
+                          : throw new UnsupportedError(
+                              "Unsupported type '${type.runtimeType}'."));
           for (_ProtoConstraint constraint in constraints) {
             if (constraint.isUpper) {
               _constrainParameterUpper(constraint.parameter,
@@ -1177,85 +1181,3 @@
         : "$bound <: ${parameter.name}";
   }
 }
-
-/// Eliminates specified free type parameters in a type.
-///
-/// The algorithm for elimination of type variables is described in
-/// https://github.com/dart-lang/language/pull/957
-class _NullabilityAwareTypeVariableEliminator extends ReplacementVisitor {
-  final DartType bottomType;
-  final DartType topType;
-  final DartType topFunctionType;
-  final Set<TypeParameter> eliminationTargets;
-  bool isLeastClosure;
-  bool isCovariant = true;
-
-  _NullabilityAwareTypeVariableEliminator(this.eliminationTargets,
-      this.bottomType, this.topType, this.topFunctionType);
-
-  /// Returns a subtype of [type] for all values of [eliminationTargets].
-  DartType eliminateToLeast(DartType type) {
-    isCovariant = true;
-    isLeastClosure = true;
-    return type.accept(this) ?? type;
-  }
-
-  /// Returns a supertype of [type] for all values of [eliminationTargets].
-  DartType eliminateToGreatest(DartType type) {
-    isCovariant = true;
-    isLeastClosure = false;
-    return type.accept(this) ?? type;
-  }
-
-  DartType get typeParameterReplacement {
-    return isLeastClosure && isCovariant || (!isLeastClosure && !isCovariant)
-        ? bottomType
-        : topType;
-  }
-
-  DartType get functionReplacement {
-    return isLeastClosure && isCovariant || (!isLeastClosure && !isCovariant)
-        ? bottomType
-        : topFunctionType;
-  }
-
-  @override
-  void changeVariance() {
-    isCovariant = !isCovariant;
-  }
-
-  @override
-  DartType visitFunctionType(FunctionType node) {
-    // - if `S` is
-    //   `T Function<X0 extends B0, ...., Xk extends Bk>(T0 x0, ...., Tn xn,
-    //       [Tn+1 xn+1, ..., Tm xm])`
-    //   or `T Function<X0 extends B0, ...., Xk extends Bk>(T0 x0, ...., Tn xn,
-    //       {Tn+1 xn+1, ..., Tm xm})`
-    //   and `L` contains any free type variables from any of the `Bi`:
-    //  - The least closure of `S` with respect to `L` is `Never`
-    //  - The greatest closure of `S` with respect to `L` is `Function`
-    if (node.typeParameters.isNotEmpty) {
-      for (TypeParameter typeParameter in node.typeParameters) {
-        if (containsTypeVariable(typeParameter.bound, eliminationTargets,
-            unhandledTypeHandler: (DartType type, ignored) =>
-                type is UnknownType
-                    ? false
-                    : throw new UnsupportedError(
-                        "Unsupported type '${type.runtimeType}'."))) {
-          return functionReplacement;
-        }
-      }
-    }
-    return super.visitFunctionType(node);
-  }
-
-  @override
-  DartType visitTypeParameterType(TypeParameterType node) {
-    if (eliminationTargets.contains(node.parameter)) {
-      return typeParameterReplacement.withDeclaredNullability(
-          uniteNullabilities(
-              typeParameterReplacement.nullability, node.nullability));
-    }
-    return super.visitTypeParameterType(node);
-  }
-}
diff --git a/pkg/front_end/test/fasta/type_inference/type_schema_environment_nnbd_test.dart b/pkg/front_end/test/fasta/type_inference/type_schema_environment_nnbd_test.dart
index 0d4d9c9..5217ca9 100644
--- a/pkg/front_end/test/fasta/type_inference/type_schema_environment_nnbd_test.dart
+++ b/pkg/front_end/test/fasta/type_inference/type_schema_environment_nnbd_test.dart
@@ -661,7 +661,7 @@
           null,
           inferredTypes,
           testLib);
-      expect(inferredTypes[0], coreTypes.numNonNullableRawType);
+      expect(inferredTypes[0], coreTypes.numLegacyRawType);
     }
   }
 
@@ -1066,13 +1066,13 @@
 
     // TODO(dmitryas): Test for various nullabilities.
     testUpper("T", "T", "T", typeParameters: "T extends Object");
-    testUpper("T", "List<Never>", "List<Object>",
+    testUpper("T", "List<Never>", "List<Object?>",
         typeParameters: "T extends List<T>");
-    testUpper("List<Never>", "T", "List<Object>",
+    testUpper("List<Never>", "T", "List<Object?>",
         typeParameters: "T extends List<T>");
-    testUpper("T", "U", "List<Object>",
+    testUpper("T", "U", "List<Object?>",
         typeParameters: "T extends List<T>, U extends List<Never>");
-    testUpper("U", "T", "List<Object>",
+    testUpper("U", "T", "List<Object?>",
         typeParameters: "T extends List<T>, U extends List<Never>");
   }
 
diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt
index 5985a19..fc4f4d0 100644
--- a/pkg/front_end/test/spell_checking_list_code.txt
+++ b/pkg/front_end/test/spell_checking_list_code.txt
@@ -73,6 +73,7 @@
 b0i
 b0m
 b0n
+b1a
 b1i
 b1m
 b1n
diff --git a/pkg/front_end/testcases/nnbd/issue43455.dart b/pkg/front_end/testcases/nnbd/issue43455.dart
new file mode 100644
index 0000000..8501673
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue43455.dart
@@ -0,0 +1,46 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+assertRightSubtype(dynamic x) {
+  x as Set<Object?>;
+}
+
+assertLeftSubtype<X>(X x) {
+  new Set<Object?>() as X;
+}
+
+class C<X extends Object?, Y extends Object> {
+  test(X x, Y? y) {
+    var v = {x, 42}; // Checking UP(X, int).
+    var w = {42, x}; // Checking UP(int, X).
+    var p = {y, 42}; // Checking UP(Y?, int).
+    var q = {42, y}; // Checking UP(int, Y?).
+
+    // Check that variable types are both subtype and supertype of Set<Object?>.
+    assertRightSubtype(v);
+    assertLeftSubtype(v);
+    assertRightSubtype(w);
+    assertLeftSubtype(w);
+    assertRightSubtype(p);
+    assertLeftSubtype(p);
+    assertRightSubtype(q);
+    assertLeftSubtype(q);
+
+    // Check the same for intersection types.
+    if (x is Object?) {
+      var v = {x, 42}; // Checking UP(X & Object?, int).
+      var w = {42, x}; // Checking UP(int, X & Object?).
+
+      assertRightSubtype(v);
+      assertLeftSubtype(v);
+      assertRightSubtype(w);
+      assertLeftSubtype(w);
+    }
+  }
+}
+
+main() {
+  new C<int?, int>().test(42, null);
+  new C<int?, int>().test(null, null);
+}
diff --git a/pkg/front_end/testcases/nnbd/issue43455.dart.outline.expect b/pkg/front_end/testcases/nnbd/issue43455.dart.outline.expect
new file mode 100644
index 0000000..d9fa31c
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue43455.dart.outline.expect
@@ -0,0 +1,16 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class C<X extends core::Object? = core::Object?, Y extends core::Object = core::Object> extends core::Object {
+  synthetic constructor •() → self::C<self::C::X%, self::C::Y>
+    ;
+  method test(generic-covariant-impl self::C::X% x, generic-covariant-impl self::C::Y? y) → dynamic
+    ;
+}
+static method assertRightSubtype(dynamic x) → dynamic
+  ;
+static method assertLeftSubtype<X extends core::Object? = dynamic>(self::assertLeftSubtype::X% x) → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/nnbd/issue43455.dart.strong.expect b/pkg/front_end/testcases/nnbd/issue43455.dart.strong.expect
new file mode 100644
index 0000000..0acee2d
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue43455.dart.strong.expect
@@ -0,0 +1,42 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:collection" as col;
+
+class C<X extends core::Object? = core::Object?, Y extends core::Object = core::Object> extends core::Object {
+  synthetic constructor •() → self::C<self::C::X%, self::C::Y>
+    : super core::Object::•()
+    ;
+  method test(generic-covariant-impl self::C::X% x, generic-covariant-impl self::C::Y? y) → dynamic {
+    core::Set<core::Object?> v = let final core::Set<core::Object?> #t1 = col::LinkedHashSet::•<core::Object?>() in let final dynamic #t2 = #t1.{core::Set::add}(x) in let final dynamic #t3 = #t1.{core::Set::add}(42) in #t1;
+    core::Set<core::Object?> w = let final core::Set<core::Object?> #t4 = col::LinkedHashSet::•<core::Object?>() in let final dynamic #t5 = #t4.{core::Set::add}(42) in let final dynamic #t6 = #t4.{core::Set::add}(x) in #t4;
+    core::Set<core::Object?> p = let final core::Set<core::Object?> #t7 = col::LinkedHashSet::•<core::Object?>() in let final dynamic #t8 = #t7.{core::Set::add}(y) in let final dynamic #t9 = #t7.{core::Set::add}(42) in #t7;
+    core::Set<core::Object?> q = let final core::Set<core::Object?> #t10 = col::LinkedHashSet::•<core::Object?>() in let final dynamic #t11 = #t10.{core::Set::add}(42) in let final dynamic #t12 = #t10.{core::Set::add}(y) in #t10;
+    self::assertRightSubtype(v);
+    self::assertLeftSubtype<core::Set<core::Object?>>(v);
+    self::assertRightSubtype(w);
+    self::assertLeftSubtype<core::Set<core::Object?>>(w);
+    self::assertRightSubtype(p);
+    self::assertLeftSubtype<core::Set<core::Object?>>(p);
+    self::assertRightSubtype(q);
+    self::assertLeftSubtype<core::Set<core::Object?>>(q);
+    if(x is{ForNonNullableByDefault} core::Object?) {
+      core::Set<core::Object?> v = let final core::Set<core::Object?> #t13 = col::LinkedHashSet::•<core::Object?>() in let final dynamic #t14 = #t13.{core::Set::add}(x{self::C::X% & core::Object? /* '%' & '?' = '%' */}) in let final dynamic #t15 = #t13.{core::Set::add}(42) in #t13;
+      core::Set<core::Object?> w = let final core::Set<core::Object?> #t16 = col::LinkedHashSet::•<core::Object?>() in let final dynamic #t17 = #t16.{core::Set::add}(42) in let final dynamic #t18 = #t16.{core::Set::add}(x{self::C::X% & core::Object? /* '%' & '?' = '%' */}) in #t16;
+      self::assertRightSubtype(v);
+      self::assertLeftSubtype<core::Set<core::Object?>>(v);
+      self::assertRightSubtype(w);
+      self::assertLeftSubtype<core::Set<core::Object?>>(w);
+    }
+  }
+}
+static method assertRightSubtype(dynamic x) → dynamic {
+  x as{ForNonNullableByDefault} core::Set<core::Object?>;
+}
+static method assertLeftSubtype<X extends core::Object? = dynamic>(self::assertLeftSubtype::X% x) → dynamic {
+  col::LinkedHashSet::•<core::Object?>() as{ForNonNullableByDefault} self::assertLeftSubtype::X%;
+}
+static method main() → dynamic {
+  new self::C::•<core::int?, core::int>().{self::C::test}(42, null);
+  new self::C::•<core::int?, core::int>().{self::C::test}(null, null);
+}
diff --git a/pkg/front_end/testcases/nnbd/issue43455.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/issue43455.dart.strong.transformed.expect
new file mode 100644
index 0000000..49327f3
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue43455.dart.strong.transformed.expect
@@ -0,0 +1,42 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:collection" as col;
+
+class C<X extends core::Object? = core::Object?, Y extends core::Object = core::Object> extends core::Object {
+  synthetic constructor •() → self::C<self::C::X%, self::C::Y>
+    : super core::Object::•()
+    ;
+  method test(generic-covariant-impl self::C::X% x, generic-covariant-impl self::C::Y? y) → dynamic {
+    core::Set<core::Object?> v = let final core::Set<core::Object?> #t1 = new col::_CompactLinkedHashSet::•<core::Object?>() in let final core::bool #t2 = #t1.{core::Set::add}(x) in let final core::bool #t3 = #t1.{core::Set::add}(42) in #t1;
+    core::Set<core::Object?> w = let final core::Set<core::Object?> #t4 = new col::_CompactLinkedHashSet::•<core::Object?>() in let final core::bool #t5 = #t4.{core::Set::add}(42) in let final core::bool #t6 = #t4.{core::Set::add}(x) in #t4;
+    core::Set<core::Object?> p = let final core::Set<core::Object?> #t7 = new col::_CompactLinkedHashSet::•<core::Object?>() in let final core::bool #t8 = #t7.{core::Set::add}(y) in let final core::bool #t9 = #t7.{core::Set::add}(42) in #t7;
+    core::Set<core::Object?> q = let final core::Set<core::Object?> #t10 = new col::_CompactLinkedHashSet::•<core::Object?>() in let final core::bool #t11 = #t10.{core::Set::add}(42) in let final core::bool #t12 = #t10.{core::Set::add}(y) in #t10;
+    self::assertRightSubtype(v);
+    self::assertLeftSubtype<core::Set<core::Object?>>(v);
+    self::assertRightSubtype(w);
+    self::assertLeftSubtype<core::Set<core::Object?>>(w);
+    self::assertRightSubtype(p);
+    self::assertLeftSubtype<core::Set<core::Object?>>(p);
+    self::assertRightSubtype(q);
+    self::assertLeftSubtype<core::Set<core::Object?>>(q);
+    if(x is{ForNonNullableByDefault} core::Object?) {
+      core::Set<core::Object?> v = let final core::Set<core::Object?> #t13 = new col::_CompactLinkedHashSet::•<core::Object?>() in let final core::bool #t14 = #t13.{core::Set::add}(x{self::C::X% & core::Object? /* '%' & '?' = '%' */}) in let final core::bool #t15 = #t13.{core::Set::add}(42) in #t13;
+      core::Set<core::Object?> w = let final core::Set<core::Object?> #t16 = new col::_CompactLinkedHashSet::•<core::Object?>() in let final core::bool #t17 = #t16.{core::Set::add}(42) in let final core::bool #t18 = #t16.{core::Set::add}(x{self::C::X% & core::Object? /* '%' & '?' = '%' */}) in #t16;
+      self::assertRightSubtype(v);
+      self::assertLeftSubtype<core::Set<core::Object?>>(v);
+      self::assertRightSubtype(w);
+      self::assertLeftSubtype<core::Set<core::Object?>>(w);
+    }
+  }
+}
+static method assertRightSubtype(dynamic x) → dynamic {
+  x as{ForNonNullableByDefault} core::Set<core::Object?>;
+}
+static method assertLeftSubtype<X extends core::Object? = dynamic>(self::assertLeftSubtype::X% x) → dynamic {
+  new col::_CompactLinkedHashSet::•<core::Object?>() as{ForNonNullableByDefault} self::assertLeftSubtype::X%;
+}
+static method main() → dynamic {
+  new self::C::•<core::int?, core::int>().{self::C::test}(42, null);
+  new self::C::•<core::int?, core::int>().{self::C::test}(null, null);
+}
diff --git a/pkg/front_end/testcases/nnbd/issue43455.dart.textual_outline.expect b/pkg/front_end/testcases/nnbd/issue43455.dart.textual_outline.expect
new file mode 100644
index 0000000..4ec51c7
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue43455.dart.textual_outline.expect
@@ -0,0 +1,8 @@
+assertRightSubtype(dynamic x) {}
+assertLeftSubtype<X>(X x) {}
+
+class C<X extends Object?, Y extends Object> {
+  test(X x, Y? y) {}
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue43455.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd/issue43455.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..287d84a
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue43455.dart.textual_outline_modelled.expect
@@ -0,0 +1,8 @@
+assertLeftSubtype<X>(X x) {}
+assertRightSubtype(dynamic x) {}
+
+class C<X extends Object?, Y extends Object> {
+  test(X x, Y? y) {}
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue43455.dart.weak.expect b/pkg/front_end/testcases/nnbd/issue43455.dart.weak.expect
new file mode 100644
index 0000000..0acee2d
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue43455.dart.weak.expect
@@ -0,0 +1,42 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:collection" as col;
+
+class C<X extends core::Object? = core::Object?, Y extends core::Object = core::Object> extends core::Object {
+  synthetic constructor •() → self::C<self::C::X%, self::C::Y>
+    : super core::Object::•()
+    ;
+  method test(generic-covariant-impl self::C::X% x, generic-covariant-impl self::C::Y? y) → dynamic {
+    core::Set<core::Object?> v = let final core::Set<core::Object?> #t1 = col::LinkedHashSet::•<core::Object?>() in let final dynamic #t2 = #t1.{core::Set::add}(x) in let final dynamic #t3 = #t1.{core::Set::add}(42) in #t1;
+    core::Set<core::Object?> w = let final core::Set<core::Object?> #t4 = col::LinkedHashSet::•<core::Object?>() in let final dynamic #t5 = #t4.{core::Set::add}(42) in let final dynamic #t6 = #t4.{core::Set::add}(x) in #t4;
+    core::Set<core::Object?> p = let final core::Set<core::Object?> #t7 = col::LinkedHashSet::•<core::Object?>() in let final dynamic #t8 = #t7.{core::Set::add}(y) in let final dynamic #t9 = #t7.{core::Set::add}(42) in #t7;
+    core::Set<core::Object?> q = let final core::Set<core::Object?> #t10 = col::LinkedHashSet::•<core::Object?>() in let final dynamic #t11 = #t10.{core::Set::add}(42) in let final dynamic #t12 = #t10.{core::Set::add}(y) in #t10;
+    self::assertRightSubtype(v);
+    self::assertLeftSubtype<core::Set<core::Object?>>(v);
+    self::assertRightSubtype(w);
+    self::assertLeftSubtype<core::Set<core::Object?>>(w);
+    self::assertRightSubtype(p);
+    self::assertLeftSubtype<core::Set<core::Object?>>(p);
+    self::assertRightSubtype(q);
+    self::assertLeftSubtype<core::Set<core::Object?>>(q);
+    if(x is{ForNonNullableByDefault} core::Object?) {
+      core::Set<core::Object?> v = let final core::Set<core::Object?> #t13 = col::LinkedHashSet::•<core::Object?>() in let final dynamic #t14 = #t13.{core::Set::add}(x{self::C::X% & core::Object? /* '%' & '?' = '%' */}) in let final dynamic #t15 = #t13.{core::Set::add}(42) in #t13;
+      core::Set<core::Object?> w = let final core::Set<core::Object?> #t16 = col::LinkedHashSet::•<core::Object?>() in let final dynamic #t17 = #t16.{core::Set::add}(42) in let final dynamic #t18 = #t16.{core::Set::add}(x{self::C::X% & core::Object? /* '%' & '?' = '%' */}) in #t16;
+      self::assertRightSubtype(v);
+      self::assertLeftSubtype<core::Set<core::Object?>>(v);
+      self::assertRightSubtype(w);
+      self::assertLeftSubtype<core::Set<core::Object?>>(w);
+    }
+  }
+}
+static method assertRightSubtype(dynamic x) → dynamic {
+  x as{ForNonNullableByDefault} core::Set<core::Object?>;
+}
+static method assertLeftSubtype<X extends core::Object? = dynamic>(self::assertLeftSubtype::X% x) → dynamic {
+  col::LinkedHashSet::•<core::Object?>() as{ForNonNullableByDefault} self::assertLeftSubtype::X%;
+}
+static method main() → dynamic {
+  new self::C::•<core::int?, core::int>().{self::C::test}(42, null);
+  new self::C::•<core::int?, core::int>().{self::C::test}(null, null);
+}
diff --git a/pkg/front_end/testcases/nnbd/issue43455.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/issue43455.dart.weak.transformed.expect
new file mode 100644
index 0000000..49327f3
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue43455.dart.weak.transformed.expect
@@ -0,0 +1,42 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:collection" as col;
+
+class C<X extends core::Object? = core::Object?, Y extends core::Object = core::Object> extends core::Object {
+  synthetic constructor •() → self::C<self::C::X%, self::C::Y>
+    : super core::Object::•()
+    ;
+  method test(generic-covariant-impl self::C::X% x, generic-covariant-impl self::C::Y? y) → dynamic {
+    core::Set<core::Object?> v = let final core::Set<core::Object?> #t1 = new col::_CompactLinkedHashSet::•<core::Object?>() in let final core::bool #t2 = #t1.{core::Set::add}(x) in let final core::bool #t3 = #t1.{core::Set::add}(42) in #t1;
+    core::Set<core::Object?> w = let final core::Set<core::Object?> #t4 = new col::_CompactLinkedHashSet::•<core::Object?>() in let final core::bool #t5 = #t4.{core::Set::add}(42) in let final core::bool #t6 = #t4.{core::Set::add}(x) in #t4;
+    core::Set<core::Object?> p = let final core::Set<core::Object?> #t7 = new col::_CompactLinkedHashSet::•<core::Object?>() in let final core::bool #t8 = #t7.{core::Set::add}(y) in let final core::bool #t9 = #t7.{core::Set::add}(42) in #t7;
+    core::Set<core::Object?> q = let final core::Set<core::Object?> #t10 = new col::_CompactLinkedHashSet::•<core::Object?>() in let final core::bool #t11 = #t10.{core::Set::add}(42) in let final core::bool #t12 = #t10.{core::Set::add}(y) in #t10;
+    self::assertRightSubtype(v);
+    self::assertLeftSubtype<core::Set<core::Object?>>(v);
+    self::assertRightSubtype(w);
+    self::assertLeftSubtype<core::Set<core::Object?>>(w);
+    self::assertRightSubtype(p);
+    self::assertLeftSubtype<core::Set<core::Object?>>(p);
+    self::assertRightSubtype(q);
+    self::assertLeftSubtype<core::Set<core::Object?>>(q);
+    if(x is{ForNonNullableByDefault} core::Object?) {
+      core::Set<core::Object?> v = let final core::Set<core::Object?> #t13 = new col::_CompactLinkedHashSet::•<core::Object?>() in let final core::bool #t14 = #t13.{core::Set::add}(x{self::C::X% & core::Object? /* '%' & '?' = '%' */}) in let final core::bool #t15 = #t13.{core::Set::add}(42) in #t13;
+      core::Set<core::Object?> w = let final core::Set<core::Object?> #t16 = new col::_CompactLinkedHashSet::•<core::Object?>() in let final core::bool #t17 = #t16.{core::Set::add}(42) in let final core::bool #t18 = #t16.{core::Set::add}(x{self::C::X% & core::Object? /* '%' & '?' = '%' */}) in #t16;
+      self::assertRightSubtype(v);
+      self::assertLeftSubtype<core::Set<core::Object?>>(v);
+      self::assertRightSubtype(w);
+      self::assertLeftSubtype<core::Set<core::Object?>>(w);
+    }
+  }
+}
+static method assertRightSubtype(dynamic x) → dynamic {
+  x as{ForNonNullableByDefault} core::Set<core::Object?>;
+}
+static method assertLeftSubtype<X extends core::Object? = dynamic>(self::assertLeftSubtype::X% x) → dynamic {
+  new col::_CompactLinkedHashSet::•<core::Object?>() as{ForNonNullableByDefault} self::assertLeftSubtype::X%;
+}
+static method main() → dynamic {
+  new self::C::•<core::int?, core::int>().{self::C::test}(42, null);
+  new self::C::•<core::int?, core::int>().{self::C::test}(null, null);
+}
diff --git a/pkg/front_end/testcases/nnbd/upper_bound_on_promoted_type.dart.strong.expect b/pkg/front_end/testcases/nnbd/upper_bound_on_promoted_type.dart.strong.expect
index 78aceb3..15fcd35 100644
--- a/pkg/front_end/testcases/nnbd/upper_bound_on_promoted_type.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/upper_bound_on_promoted_type.dart.strong.expect
@@ -11,7 +11,7 @@
   method qux() → dynamic {
     final self::Foo::T? v = this.{self::Foo::bar} as{TypeError,ForDynamic,ForNonNullableByDefault} self::Foo::T?;
     if(v is{ForNonNullableByDefault} core::num) {
-      this.{self::Foo::baz}.[]=("value", v{self::Foo::T? & core::num /* '?' & '!' = '!' */}.{core::num::isFinite} ?{core::Object?} v{self::Foo::T? & core::num /* '?' & '!' = '!' */} : v{self::Foo::T? & core::num /* '?' & '!' = '!' */}.{core::num::toString}());
+      this.{self::Foo::baz}.[]=("value", v{self::Foo::T? & core::num /* '?' & '!' = '!' */}.{core::num::isFinite} ?{core::Object} v{self::Foo::T? & core::num /* '?' & '!' = '!' */} : v{self::Foo::T? & core::num /* '?' & '!' = '!' */}.{core::num::toString}());
     }
   }
 }
diff --git a/pkg/front_end/testcases/nnbd/upper_bound_on_promoted_type.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/upper_bound_on_promoted_type.dart.strong.transformed.expect
index 78aceb3..15fcd35 100644
--- a/pkg/front_end/testcases/nnbd/upper_bound_on_promoted_type.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/upper_bound_on_promoted_type.dart.strong.transformed.expect
@@ -11,7 +11,7 @@
   method qux() → dynamic {
     final self::Foo::T? v = this.{self::Foo::bar} as{TypeError,ForDynamic,ForNonNullableByDefault} self::Foo::T?;
     if(v is{ForNonNullableByDefault} core::num) {
-      this.{self::Foo::baz}.[]=("value", v{self::Foo::T? & core::num /* '?' & '!' = '!' */}.{core::num::isFinite} ?{core::Object?} v{self::Foo::T? & core::num /* '?' & '!' = '!' */} : v{self::Foo::T? & core::num /* '?' & '!' = '!' */}.{core::num::toString}());
+      this.{self::Foo::baz}.[]=("value", v{self::Foo::T? & core::num /* '?' & '!' = '!' */}.{core::num::isFinite} ?{core::Object} v{self::Foo::T? & core::num /* '?' & '!' = '!' */} : v{self::Foo::T? & core::num /* '?' & '!' = '!' */}.{core::num::toString}());
     }
   }
 }
diff --git a/pkg/front_end/testcases/nnbd/upper_bound_on_promoted_type.dart.weak.expect b/pkg/front_end/testcases/nnbd/upper_bound_on_promoted_type.dart.weak.expect
index 78aceb3..15fcd35 100644
--- a/pkg/front_end/testcases/nnbd/upper_bound_on_promoted_type.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/upper_bound_on_promoted_type.dart.weak.expect
@@ -11,7 +11,7 @@
   method qux() → dynamic {
     final self::Foo::T? v = this.{self::Foo::bar} as{TypeError,ForDynamic,ForNonNullableByDefault} self::Foo::T?;
     if(v is{ForNonNullableByDefault} core::num) {
-      this.{self::Foo::baz}.[]=("value", v{self::Foo::T? & core::num /* '?' & '!' = '!' */}.{core::num::isFinite} ?{core::Object?} v{self::Foo::T? & core::num /* '?' & '!' = '!' */} : v{self::Foo::T? & core::num /* '?' & '!' = '!' */}.{core::num::toString}());
+      this.{self::Foo::baz}.[]=("value", v{self::Foo::T? & core::num /* '?' & '!' = '!' */}.{core::num::isFinite} ?{core::Object} v{self::Foo::T? & core::num /* '?' & '!' = '!' */} : v{self::Foo::T? & core::num /* '?' & '!' = '!' */}.{core::num::toString}());
     }
   }
 }
diff --git a/pkg/front_end/testcases/nnbd/upper_bound_on_promoted_type.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/upper_bound_on_promoted_type.dart.weak.transformed.expect
index 78aceb3..15fcd35 100644
--- a/pkg/front_end/testcases/nnbd/upper_bound_on_promoted_type.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/upper_bound_on_promoted_type.dart.weak.transformed.expect
@@ -11,7 +11,7 @@
   method qux() → dynamic {
     final self::Foo::T? v = this.{self::Foo::bar} as{TypeError,ForDynamic,ForNonNullableByDefault} self::Foo::T?;
     if(v is{ForNonNullableByDefault} core::num) {
-      this.{self::Foo::baz}.[]=("value", v{self::Foo::T? & core::num /* '?' & '!' = '!' */}.{core::num::isFinite} ?{core::Object?} v{self::Foo::T? & core::num /* '?' & '!' = '!' */} : v{self::Foo::T? & core::num /* '?' & '!' = '!' */}.{core::num::toString}());
+      this.{self::Foo::baz}.[]=("value", v{self::Foo::T? & core::num /* '?' & '!' = '!' */}.{core::num::isFinite} ?{core::Object} v{self::Foo::T? & core::num /* '?' & '!' = '!' */} : v{self::Foo::T? & core::num /* '?' & '!' = '!' */}.{core::num::toString}());
     }
   }
 }
diff --git a/pkg/kernel/lib/src/standard_bounds.dart b/pkg/kernel/lib/src/standard_bounds.dart
index e57f264..51a5ab9 100644
--- a/pkg/kernel/lib/src/standard_bounds.dart
+++ b/pkg/kernel/lib/src/standard_bounds.dart
@@ -710,9 +710,9 @@
             type1.declaredNullability, type2.declaredNullability));
       }
 
-      // UP(T Function<...>(...), T2) = Object
-      return coreTypes.objectRawType(uniteNullabilities(
-          type1.declaredNullability, type2.declaredNullability));
+      // UP(T Function<...>(...), T2) = UP(Object, T2)
+      return _getNullabilityAwareStandardUpperBound(
+          coreTypes.objectNonNullableRawType, type2, clientLibrary);
     } else if (type2 is FunctionType) {
       if (type1 is InterfaceType &&
           type1.classNode == coreTypes.functionClass) {
@@ -721,9 +721,9 @@
             type1.declaredNullability, type2.declaredNullability));
       }
 
-      // UP(T1, T Function<...>(...)) = Object
-      return coreTypes.objectRawType(uniteNullabilities(
-          type1.declaredNullability, type2.declaredNullability));
+      // UP(T1, T Function<...>(...)) = UP(T1, Object)
+      return _getNullabilityAwareStandardUpperBound(
+          type1, coreTypes.objectNonNullableRawType, clientLibrary);
     }
 
     if (type1 is FutureOrType || type2 is FutureOrType) {
@@ -1148,7 +1148,9 @@
       // UP(X1 extends B1, T2) =
       //   T2 if X1 <: T2
       //   otherwise X1 if T2 <: X1
-      //   otherwise UP(B1[Object/X1], T2)
+      //   otherwise UP(B1a, T2)
+      //     where B1a is the greatest closure of B1 with respect to X1,
+      //     as defined in [inference.md].
       if (isSubtypeOf(type1, type2, SubtypeCheckMode.withNullabilities)) {
         return type2.withDeclaredNullability(uniteNullabilities(
             type1.declaredNullability, type2.declaredNullability));
@@ -1157,20 +1159,28 @@
         return type1.withDeclaredNullability(uniteNullabilities(
             type1.declaredNullability, type2.declaredNullability));
       }
-      Map<TypeParameter, DartType> substitution = <TypeParameter, DartType>{
-        type1.parameter: coreTypes.objectNonNullableRawType
-      };
+      NullabilityAwareTypeVariableEliminator eliminator =
+          new NullabilityAwareTypeVariableEliminator(
+              eliminationTargets: <TypeParameter>{type1.parameter},
+              bottomType: const NeverType(Nullability.nonNullable),
+              topType: coreTypes.objectNullableRawType,
+              topFunctionType: coreTypes.functionNonNullableRawType,
+              unhandledTypeHandler: (type, recursor) => false);
       return _getNullabilityAwareStandardUpperBound(
-              substitute(type1.parameter.bound, substitution),
+              eliminator.eliminateToGreatest(type1.parameter.bound),
               type2,
               clientLibrary)
           .withDeclaredNullability(uniteNullabilities(
-              type1.declaredNullability, type2.declaredNullability));
+              type1.declaredNullability,
+              uniteNullabilities(type1.parameter.bound.declaredNullability,
+                  type2.declaredNullability)));
     } else {
       // UP(X1 & B1, T2) =
       //   T2 if X1 <: T2
       //   otherwise X1 if T2 <: X1
-      //   otherwise UP(B1[Object/X1], T2)
+      //   otherwise UP(B1a, T2)
+      //     where B1a is the greatest closure of B1 with respect to X1,
+      //     as defined in [inference.md].
       DartType demoted =
           new TypeParameterType(type1.parameter, type1.declaredNullability);
       if (isSubtypeOf(demoted, type2, SubtypeCheckMode.withNullabilities)) {
@@ -1181,15 +1191,20 @@
         return demoted.withDeclaredNullability(uniteNullabilities(
             type1.declaredNullability, type2.declaredNullability));
       }
-      Map<TypeParameter, DartType> substitution = <TypeParameter, DartType>{
-        type1.parameter: coreTypes.objectNonNullableRawType
-      };
+      NullabilityAwareTypeVariableEliminator eliminator =
+          new NullabilityAwareTypeVariableEliminator(
+              eliminationTargets: <TypeParameter>{type1.parameter},
+              bottomType: const NeverType(Nullability.nonNullable),
+              topType: coreTypes.objectNullableRawType,
+              topFunctionType: coreTypes.functionNonNullableRawType,
+              unhandledTypeHandler: (type, recursor) => false);
       return _getNullabilityAwareStandardUpperBound(
-              substitute(type1.promotedBound, substitution),
+              eliminator.eliminateToGreatest(type1.promotedBound),
               type2,
               clientLibrary)
           .withDeclaredNullability(uniteNullabilities(
-              type1.declaredNullability, type2.declaredNullability));
+              type1.promotedBound.declaredNullability,
+              type2.declaredNullability));
     }
   }
 
diff --git a/pkg/kernel/lib/type_algebra.dart b/pkg/kernel/lib/type_algebra.dart
index 4661aeb..632c18d 100644
--- a/pkg/kernel/lib/type_algebra.dart
+++ b/pkg/kernel/lib/type_algebra.dart
@@ -5,6 +5,7 @@
 
 import 'ast.dart';
 import 'core_types.dart';
+import 'src/replacement_visitor.dart';
 
 /// Returns a type where all occurrences of the given type parameters have been
 /// replaced with the corresponding types.
@@ -1096,3 +1097,91 @@
   @override
   DartType visitVoidType(VoidType node, CoreTypes coreTypes) => node;
 }
+
+/// Eliminates specified free type parameters in a type.
+///
+/// The algorithm for elimination of type variables is described in
+/// https://github.com/dart-lang/language/pull/957
+class NullabilityAwareTypeVariableEliminator extends ReplacementVisitor {
+  final DartType bottomType;
+  final DartType topType;
+  final DartType topFunctionType;
+  final Set<TypeParameter> eliminationTargets;
+  bool isLeastClosure;
+  bool isCovariant = true;
+  bool Function(DartType type, bool Function(DartType type) recursor)
+      unhandledTypeHandler; // Can be null.
+
+  NullabilityAwareTypeVariableEliminator(
+      {this.eliminationTargets,
+      this.bottomType,
+      this.topType,
+      this.topFunctionType,
+      this.unhandledTypeHandler})
+      : assert(eliminationTargets != null),
+        assert(bottomType != null),
+        assert(topType != null),
+        assert(topFunctionType != null);
+
+  /// Returns a subtype of [type] for all values of [eliminationTargets].
+  DartType eliminateToLeast(DartType type) {
+    isCovariant = true;
+    isLeastClosure = true;
+    return type.accept(this) ?? type;
+  }
+
+  /// Returns a supertype of [type] for all values of [eliminationTargets].
+  DartType eliminateToGreatest(DartType type) {
+    isCovariant = true;
+    isLeastClosure = false;
+    return type.accept(this) ?? type;
+  }
+
+  DartType get typeParameterReplacement {
+    return isLeastClosure && isCovariant || (!isLeastClosure && !isCovariant)
+        ? bottomType
+        : topType;
+  }
+
+  DartType get functionReplacement {
+    return isLeastClosure && isCovariant || (!isLeastClosure && !isCovariant)
+        ? bottomType
+        : topFunctionType;
+  }
+
+  @override
+  void changeVariance() {
+    isCovariant = !isCovariant;
+  }
+
+  @override
+  DartType visitFunctionType(FunctionType node) {
+    // - if `S` is
+    //   `T Function<X0 extends B0, ...., Xk extends Bk>(T0 x0, ...., Tn xn,
+    //       [Tn+1 xn+1, ..., Tm xm])`
+    //   or `T Function<X0 extends B0, ...., Xk extends Bk>(T0 x0, ...., Tn xn,
+    //       {Tn+1 xn+1, ..., Tm xm})`
+    //   and `L` contains any free type variables from any of the `Bi`:
+    //  - The least closure of `S` with respect to `L` is `Never`
+    //  - The greatest closure of `S` with respect to `L` is `Function`
+    if (node.typeParameters.isNotEmpty) {
+      for (TypeParameter typeParameter in node.typeParameters) {
+        if (containsTypeVariable(typeParameter.bound, eliminationTargets,
+            unhandledTypeHandler: unhandledTypeHandler)) {
+          return functionReplacement;
+        }
+      }
+    }
+    return super.visitFunctionType(node);
+  }
+
+  @override
+  DartType visitTypeParameterType(TypeParameterType node) {
+    if (eliminationTargets.contains(node.parameter)) {
+      return typeParameterReplacement.withDeclaredNullability(
+          uniteNullabilities(
+              typeParameterReplacement.nullability, node.nullability));
+    }
+    return super.visitTypeParameterType(node);
+  }
+}
diff --git a/tools/VERSION b/tools/VERSION
index cd329e1..452c461 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 11
 PATCH 0
-PRERELEASE 158
+PRERELEASE 159
 PRERELEASE_PATCH 0
\ No newline at end of file