Version 2.13.0-179.0.dev

Merge commit '13556d623fc3330a4206c660432b2ff2223fd194' into 'dev'
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/nullability/data/null_check.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/nullability/data/null_check.dart
index 51ba181..d00347b 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/nullability/data/null_check.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/nullability/data/null_check.dart
@@ -2,6 +2,8 @@
 // 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.
 
+import 'dart:async';
+
 void bang_promotes(int? x) {
   x!;
   /*nonNullable*/ x;
@@ -33,3 +35,18 @@
   x!;
   /*nonNullable*/ x;
 }
+
+void bang_promotesNullableFutureInt(FutureOr<int>? x) {
+  x!;
+  /*nonNullable*/ x;
+}
+
+void bang_promotesFutureNullableInt(FutureOr<int?> x) {
+  x!;
+  x;
+}
+
+void bang_promotesNullableFutureNullableInt(FutureOr<int?>? x) {
+  x!;
+  x;
+}
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/data/type_parameter.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/data/type_parameter.dart
index 1b4354d..c818df6 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/data/type_parameter.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/data/type_parameter.dart
@@ -50,7 +50,7 @@
 class F<S, T extends S> {
   void nonNull(T t) {
     if (t != null) {
-      /*analyzer.T & S & Object*/ /*cfe.T & S*/ t;
+      /*T & S & Object*/ t;
     }
   }
 }
diff --git a/pkg/front_end/lib/src/fasta/kernel/implicit_field_type.dart b/pkg/front_end/lib/src/fasta/kernel/implicit_field_type.dart
index b45a75c..f9c2d18 100644
--- a/pkg/front_end/lib/src/fasta/kernel/implicit_field_type.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/implicit_field_type.dart
@@ -61,6 +61,12 @@
   }
 
   @override
+  ImplicitFieldType toNonNull() {
+    return unsupported(
+        "toNonNullable", fieldBuilder.charOffset, fieldBuilder.fileUri);
+  }
+
+  @override
   void toTextInternal(AstPrinter printer) {
     printer.write('<implicit-field-type:$fieldBuilder>');
   }
diff --git a/pkg/front_end/lib/src/fasta/kernel/implicit_type_argument.dart b/pkg/front_end/lib/src/fasta/kernel/implicit_type_argument.dart
index c6daddf..3f27451 100644
--- a/pkg/front_end/lib/src/fasta/kernel/implicit_type_argument.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/implicit_type_argument.dart
@@ -49,6 +49,11 @@
   }
 
   @override
+  ImplicitTypeArgument toNonNull() {
+    return unsupported("toNonNullable", -1, null);
+  }
+
+  @override
   bool equals(Object other, Assumptions assumptions) => this == other;
 
   @override
diff --git a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
index a86117d..13c72b9 100644
--- a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
@@ -1249,7 +1249,7 @@
     //   UP(t0, t1)
     // - Then the inferred type is T.
     DartType originalLhsType = lhsResult.inferredType;
-    DartType nonNullableLhsType = inferrer.computeNonNullable(originalLhsType);
+    DartType nonNullableLhsType = originalLhsType.toNonNull();
     DartType inferredType = inferrer.typeSchemaEnvironment
         .getStandardUpperBound(nonNullableLhsType, rhsResult.inferredType,
             inferrer.library.library);
@@ -2725,7 +2725,7 @@
     reportNonNullableInNullAwareWarningIfNeeded(
         operandType, "!", node.operand.fileOffset);
     inferrer.flowAnalysis.nonNullAssert_end(node.operand);
-    DartType nonNullableResultType = inferrer.computeNonNullable(operandType);
+    DartType nonNullableResultType = operandType.toNonNull();
     return inferrer.createNullAwareExpressionInferenceResult(
         nonNullableResultType, node, nullAwareGuards);
   }
@@ -2967,7 +2967,7 @@
         .findInterfaceMember(readType, equalsName, node.fileOffset)
         .member;
 
-    DartType nonNullableReadType = inferrer.computeNonNullable(readType);
+    DartType nonNullableReadType = readType.toNonNull();
     DartType inferredType = inferrer.typeSchemaEnvironment
         .getStandardUpperBound(
             nonNullableReadType, writeType, inferrer.library.library);
@@ -3032,8 +3032,7 @@
         .member;
 
     DartType originalReadType = readType;
-    DartType nonNullableReadType =
-        inferrer.computeNonNullable(originalReadType);
+    DartType nonNullableReadType = originalReadType.toNonNull();
     DartType inferredType = inferrer.typeSchemaEnvironment
         .getStandardUpperBound(nonNullableReadType, writeResult.inferredType,
             inferrer.library.library);
@@ -3411,7 +3410,7 @@
     Expression value = inferrer.ensureAssignableResult(valueType, valueResult);
     inferrer.flowAnalysis.ifNullExpression_end();
 
-    DartType nonNullableReadType = inferrer.computeNonNullable(readType);
+    DartType nonNullableReadType = readType.toNonNull();
     DartType inferredType = inferrer.typeSchemaEnvironment
         .getStandardUpperBound(nonNullableReadType, valueResult.inferredType,
             inferrer.library.library);
@@ -3592,7 +3591,7 @@
     Expression value = inferrer.ensureAssignableResult(valueType, valueResult);
     inferrer.flowAnalysis.ifNullExpression_end();
 
-    DartType nonNullableReadType = inferrer.computeNonNullable(readType);
+    DartType nonNullableReadType = readType.toNonNull();
     DartType inferredType = inferrer.typeSchemaEnvironment
         .getStandardUpperBound(nonNullableReadType, valueResult.inferredType,
             inferrer.library.library);
@@ -3767,7 +3766,7 @@
     Expression value = inferrer.ensureAssignableResult(valueType, valueResult);
     inferrer.flowAnalysis.ifNullExpression_end();
 
-    DartType nonNullableReadType = inferrer.computeNonNullable(readType);
+    DartType nonNullableReadType = readType.toNonNull();
     DartType inferredType = inferrer.typeSchemaEnvironment
         .getStandardUpperBound(nonNullableReadType, valueResult.inferredType,
             inferrer.library.library);
@@ -5211,7 +5210,7 @@
         inferrer.createNullAwareGuard(receiverVariable);
     Expression readReceiver = createVariableGet(receiverVariable);
     Expression writeReceiver = createVariableGet(receiverVariable);
-    DartType nonNullReceiverType = inferrer.computeNonNullable(receiverType);
+    DartType nonNullReceiverType = receiverType.toNonNull();
 
     ExpressionInferenceResult readResult = _computePropertyGet(
         node.readOffset,
@@ -5747,7 +5746,7 @@
         inferrer.createNullAwareGuard(receiverVariable);
     Expression readReceiver = createVariableGet(receiverVariable);
     Expression writeReceiver = createVariableGet(receiverVariable);
-    DartType nonNullReceiverType = inferrer.computeNonNullable(receiverType);
+    DartType nonNullReceiverType = receiverType.toNonNull();
 
     ExpressionInferenceResult readResult = _computePropertyGet(node.readOffset,
         readReceiver, nonNullReceiverType, node.name, typeContext,
@@ -5783,7 +5782,7 @@
 
     inferrer.flowAnalysis.ifNullExpression_end();
 
-    DartType nonNullableReadType = inferrer.computeNonNullable(readType);
+    DartType nonNullableReadType = readType.toNonNull();
     DartType inferredType = inferrer.typeSchemaEnvironment
         .getStandardUpperBound(nonNullableReadType, valueResult.inferredType,
             inferrer.library.library);
@@ -6710,7 +6709,7 @@
       inferrer.flowAnalysis.thisOrSuper(node, variable.type);
     } else if (inferrer.isNonNullableByDefault) {
       if (node.forNullGuardedAccess) {
-        DartType nonNullableType = inferrer.computeNonNullable(variable.type);
+        DartType nonNullableType = variable.type.toNonNull();
         if (nonNullableType != variable.type) {
           promotedType = nonNullableType;
         }
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart
index 2e20f55..4a87e32 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart
@@ -18,9 +18,7 @@
         InterfaceType,
         Member,
         NamedType,
-        NeverType,
         NullType,
-        Nullability,
         Statement,
         TreeNode,
         TypeParameter,
@@ -310,19 +308,7 @@
 
   @override
   DartType promoteToNonNull(DartType type) {
-    if (type is TypeParameterType &&
-        type.declaredNullability != Nullability.nullable) {
-      DartType bound =
-          type.bound.withDeclaredNullability(Nullability.nonNullable);
-      if (bound != type.bound) {
-        return new TypeParameterType(
-            type.parameter, type.declaredNullability, bound);
-      }
-      return type;
-    } else if (type is NullType) {
-      return const NeverType.nonNullable();
-    }
-    return type.withDeclaredNullability(Nullability.nonNullable);
+    return type.toNonNull();
   }
 
   @override
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
index 2d7a818..38e0a42 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
@@ -264,17 +264,6 @@
     return type.withDeclaredNullability(library.nullable);
   }
 
-  DartType computeNonNullable(DartType type) {
-    if (type is NullType) {
-      return isNonNullableByDefault ? const NeverType.nonNullable() : type;
-    }
-    if (type is TypeParameterType && type.promotedBound != null) {
-      return new TypeParameterType(type.parameter, Nullability.nonNullable,
-          computeNonNullable(type.promotedBound));
-    }
-    return type.withDeclaredNullability(library.nonNullable);
-  }
-
   Expression createReachabilityError(
       int fileOffset, Message errorMessage, Message warningMessage) {
     if (library.loader.target.context.options.warnOnReachabilityCheck &&
@@ -1192,8 +1181,8 @@
         // invalid.
         target = _findExtensionMember(
             isNonNullableByDefault
-                ? computeNonNullable(receiverType)
-                : computeNonNullable(receiverBound),
+                ? receiverType.toNonNull()
+                : receiverBound.toNonNull(),
             classNode,
             name,
             fileOffset,
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_schema.dart b/pkg/front_end/lib/src/fasta/type_inference/type_schema.dart
index 883df40..cce226f 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_schema.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_schema.dart
@@ -95,6 +95,9 @@
   UnknownType withDeclaredNullability(Nullability nullability) => this;
 
   @override
+  UnknownType toNonNull() => this;
+
+  @override
   void toTextInternal(AstPrinter printer) {
     printer.write('?');
   }
diff --git a/pkg/front_end/test/fasta/testing/suite.dart b/pkg/front_end/test/fasta/testing/suite.dart
index bdc0a87..0da4649 100644
--- a/pkg/front_end/test/fasta/testing/suite.dart
+++ b/pkg/front_end/test/fasta/testing/suite.dart
@@ -874,7 +874,6 @@
             result, runResult.outcome, runResult.error);
       case "aot":
       case "none":
-      case "noneWithJs":
       case "dart2js":
       case "dartdevc":
         // TODO(johnniwinther): Support running vm aot, dart2js and/or dartdevc.
@@ -1725,9 +1724,6 @@
     case "none":
       target = new NoneTarget(targetFlags);
       break;
-    case "noneWithJs":
-      target = new NoneWithJsTarget(targetFlags);
-      break;
     case "dart2js":
       target = new TestDart2jsTarget('dart2js', targetFlags);
       break;
@@ -2140,14 +2136,6 @@
   }
 }
 
-class NoneWithJsTarget extends NoneTarget {
-  NoneWithJsTarget(TargetFlags flags) : super(flags);
-
-  @override
-  ConstantsBackend constantsBackend(CoreTypes coreTypes) =>
-      const NoneConstantsBackendWithJs(supportsUnevaluatedConstants: true);
-}
-
 class NoneConstantsBackendWithJs extends NoneConstantsBackend {
   const NoneConstantsBackendWithJs({bool supportsUnevaluatedConstants})
       : super(supportsUnevaluatedConstants: supportsUnevaluatedConstants);
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 6ceb6c7..67cfacc 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
@@ -383,13 +383,9 @@
     parseTestLibrary("");
 
     checkLowerBound(
-        type1: "Object",
-        type2: "FutureOr<Null>",
-        lowerBound: "FutureOr<Never>");
+        type1: "Object", type2: "FutureOr<Null>", lowerBound: "Never");
     checkLowerBound(
-        type1: "FutureOr<Null>",
-        type2: "Object",
-        lowerBound: "FutureOr<Never>");
+        type1: "FutureOr<Null>", type2: "Object", lowerBound: "Never");
 
     // FutureOr<dynamic> is top.
     checkLowerBound(
@@ -1329,6 +1325,59 @@
         type2: "T",
         upperBound: "List<Object?>",
         typeParameters: "T extends List<T>, U extends List<Never>");
+    checkUpperBound(
+        type1: "T",
+        type2: "T",
+        upperBound: "T",
+        typeParameters: "T extends Object?");
+
+    // These cases are observed through `a ?? b`. Here the resulting type
+    // is `UP(NonNull(a),b)`, if `b` is `null`, is `NonNull(a)?`.
+
+    // We have
+    //
+    //     NonNull(T extends Object?) = T & Object
+    //
+    // resulting in
+    //
+    //     (T & Object)? = T? & Object
+    //
+    checkUpperBound(
+        type1: "T",
+        type2: "Null",
+        upperBound: "T? & Object",
+        typeParameters: "T extends Object?",
+        nonNull1: true);
+
+    // We have
+    //
+    //     NonNull(T extends bool?) = T & bool
+    //
+    // resulting in
+    //
+    //     (T & bool)? = T? & bool
+    //
+    checkUpperBound(
+        type1: "T",
+        type2: "Null",
+        upperBound: "T? & bool",
+        typeParameters: "T extends bool?",
+        nonNull1: true);
+
+    // We have
+    //
+    //     NonNull(T extends bool) = T
+    //
+    // resulting in
+    //
+    //     (T)? = T?
+    //
+    checkUpperBound(
+        type1: "T",
+        type2: "Null",
+        upperBound: "T?",
+        typeParameters: "T extends bool",
+        nonNull1: true);
   }
 
   void test_upper_bound_unknown() {
@@ -1521,16 +1570,29 @@
   }
 
   void checkUpperBound(
-      {String type1, String type2, String upperBound, String typeParameters}) {
+      {String type1,
+      String type2,
+      String upperBound,
+      String typeParameters,
+      bool nonNull1: false,
+      bool nonNull2: false}) {
     assert(type1 != null);
     assert(type2 != null);
     assert(upperBound != null);
 
     typeParserEnvironment.withTypeParameters(typeParameters,
         (List<TypeParameter> typeParameterNodes) {
+      DartType dartType1 = parseType(type1);
+      DartType dartType2 = parseType(type2);
+      if (nonNull1) {
+        dartType1 = dartType1.toNonNull();
+      }
+      if (nonNull2) {
+        dartType2 = dartType2.toNonNull();
+      }
       expect(
           typeSchemaEnvironment.getStandardUpperBound(
-              parseType(type1), parseType(type2), testLibrary),
+              dartType1, dartType2, testLibrary),
           parseType(upperBound));
     });
   }
diff --git a/pkg/front_end/testcases/general/constants/js_semantics/folder.options b/pkg/front_end/testcases/general/constants/js_semantics/folder.options
index 674c362..7a017fa 100644
--- a/pkg/front_end/testcases/general/constants/js_semantics/folder.options
+++ b/pkg/front_end/testcases/general/constants/js_semantics/folder.options
@@ -1,2 +1,2 @@
 --enable-experiment=triple-shift
---target=noneWithJs
\ No newline at end of file
+--target=dart2js
\ No newline at end of file
diff --git a/pkg/front_end/testcases/general/constants/js_semantics/issue45376.dart b/pkg/front_end/testcases/general/constants/js_semantics/issue45376.dart
new file mode 100644
index 0000000..81c2ce2
--- /dev/null
+++ b/pkg/front_end/testcases/general/constants/js_semantics/issue45376.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2021, 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.
+
+class MyClass {
+  final int a;
+  final int b;
+  const MyClass(i1, i2) : a = (i1 >>> i2), b = (i1 >>> i2);
+}
+
+test() {
+  const MyClass c1 = MyClass(1.0, 1);
+}
+
+main() {}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/general/constants/js_semantics/issue45376.dart.textual_outline.expect b/pkg/front_end/testcases/general/constants/js_semantics/issue45376.dart.textual_outline.expect
new file mode 100644
index 0000000..c73f11f
--- /dev/null
+++ b/pkg/front_end/testcases/general/constants/js_semantics/issue45376.dart.textual_outline.expect
@@ -0,0 +1,7 @@
+class MyClass {
+  final int a;
+  final int b;
+  const MyClass(i1, i2) : a = (i1 >>> i2), b = (i1 >>> i2);
+}
+test() {}
+main() {}
diff --git a/pkg/front_end/testcases/general/constants/js_semantics/issue45376.dart.weak.expect b/pkg/front_end/testcases/general/constants/js_semantics/issue45376.dart.weak.expect
new file mode 100644
index 0000000..bdbea12
--- /dev/null
+++ b/pkg/front_end/testcases/general/constants/js_semantics/issue45376.dart.weak.expect
@@ -0,0 +1,20 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class MyClass extends core::Object /*hasConstConstructor*/  {
+  final field core::int a;
+  final field core::int b;
+  const constructor •(dynamic i1, dynamic i2) → self::MyClass
+    : self::MyClass::a = i1{dynamic}.>>>(i2) as{TypeError,ForDynamic,ForNonNullableByDefault} core::int, self::MyClass::b = i1{dynamic}.>>>(i2) as{TypeError,ForDynamic,ForNonNullableByDefault} core::int, super core::Object::•()
+    ;
+}
+static method test() → dynamic {}
+static method main() → dynamic {}
+
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///issue45376.dart:
+- MyClass. (from org-dartlang-testcase:///issue45376.dart:8:9)
+- Object. (from org-dartlang-sdk:///lib/core/object.dart:25:9)
diff --git a/pkg/front_end/testcases/general/constants/js_semantics/issue45376.dart.weak.outline.expect b/pkg/front_end/testcases/general/constants/js_semantics/issue45376.dart.weak.outline.expect
new file mode 100644
index 0000000..dcdb486
--- /dev/null
+++ b/pkg/front_end/testcases/general/constants/js_semantics/issue45376.dart.weak.outline.expect
@@ -0,0 +1,15 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class MyClass extends core::Object /*hasConstConstructor*/  {
+  final field core::int a;
+  final field core::int b;
+  const constructor •(dynamic i1, dynamic i2) → self::MyClass
+    : self::MyClass::a = i1{dynamic}.>>>(i2) as{TypeError,ForDynamic,ForNonNullableByDefault} core::int, self::MyClass::b = i1{dynamic}.>>>(i2) as{TypeError,ForDynamic,ForNonNullableByDefault} core::int, super core::Object::•()
+    ;
+}
+static method test() → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/general/constants/js_semantics/issue45376.dart.weak.transformed.expect b/pkg/front_end/testcases/general/constants/js_semantics/issue45376.dart.weak.transformed.expect
new file mode 100644
index 0000000..bdbea12
--- /dev/null
+++ b/pkg/front_end/testcases/general/constants/js_semantics/issue45376.dart.weak.transformed.expect
@@ -0,0 +1,20 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class MyClass extends core::Object /*hasConstConstructor*/  {
+  final field core::int a;
+  final field core::int b;
+  const constructor •(dynamic i1, dynamic i2) → self::MyClass
+    : self::MyClass::a = i1{dynamic}.>>>(i2) as{TypeError,ForDynamic,ForNonNullableByDefault} core::int, self::MyClass::b = i1{dynamic}.>>>(i2) as{TypeError,ForDynamic,ForNonNullableByDefault} core::int, super core::Object::•()
+    ;
+}
+static method test() → dynamic {}
+static method main() → dynamic {}
+
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///issue45376.dart:
+- MyClass. (from org-dartlang-testcase:///issue45376.dart:8:9)
+- Object. (from org-dartlang-sdk:///lib/core/object.dart:25:9)
diff --git a/pkg/front_end/testcases/general/constants/js_semantics/on_double.dart b/pkg/front_end/testcases/general/constants/js_semantics/on_double.dart
new file mode 100644
index 0000000..d4598da
--- /dev/null
+++ b/pkg/front_end/testcases/general/constants/js_semantics/on_double.dart
@@ -0,0 +1,40 @@
+// Copyright (c) 2021, 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.
+
+const dynamic a = 1.0;
+const dynamic b = 1.5;
+
+const dynamic c0 = a >> 1;
+const dynamic c1 = b >> 1;
+const dynamic c2 = a >>> 1;
+const dynamic c3 = b >>> 1;
+
+const dynamic d0 = 1 >> a;
+const dynamic d1 = 1 >> b;
+const dynamic d2 = 1 >>> a;
+const dynamic d3 = 1 >>> b;
+
+class Class {
+  final int a;
+
+  const Class.doubleShift(i1, i2) : a = (i1 >> i2);
+  const Class.tripleShift(i1, i2) : a = (i1 >>> i2);
+}
+
+main() {
+  const Class c1 = Class.doubleShift(a, 1);
+  const Class c2 = Class.doubleShift(b, 1);
+  const Class c3 = Class.tripleShift(a, 1);
+  const Class c4 = Class.tripleShift(b, 1);
+
+  const Class d1 = Class.doubleShift(1, a);
+  const Class d2 = Class.doubleShift(1, b);
+  const Class d3 = Class.tripleShift(1, a);
+  const Class d4 = Class.tripleShift(1, b);
+
+  const Class e1 = Class.doubleShift(1.0, 1);
+  const Class e2 = Class.doubleShift(1.5, 1);
+  const Class e3 = Class.tripleShift(1.0, 1);
+  const Class e4 = Class.tripleShift(1.5, 1);
+}
diff --git a/pkg/front_end/testcases/general/constants/js_semantics/on_double.dart.textual_outline.expect b/pkg/front_end/testcases/general/constants/js_semantics/on_double.dart.textual_outline.expect
new file mode 100644
index 0000000..006bef5
--- /dev/null
+++ b/pkg/front_end/testcases/general/constants/js_semantics/on_double.dart.textual_outline.expect
@@ -0,0 +1,16 @@
+const dynamic a = 1.0;
+const dynamic b = 1.5;
+const dynamic c0 = a >> 1;
+const dynamic c1 = b >> 1;
+const dynamic c2 = a >>> 1;
+const dynamic c3 = b >>> 1;
+const dynamic d0 = 1 >> a;
+const dynamic d1 = 1 >> b;
+const dynamic d2 = 1 >>> a;
+const dynamic d3 = 1 >>> b;
+class Class {
+  final int a;
+  const Class.doubleShift(i1, i2) : a = (i1 >> i2);
+  const Class.tripleShift(i1, i2) : a = (i1 >>> i2);
+}
+main() {}
diff --git a/pkg/front_end/testcases/general/constants/js_semantics/on_double.dart.weak.expect b/pkg/front_end/testcases/general/constants/js_semantics/on_double.dart.weak.expect
new file mode 100644
index 0000000..2573a35
--- /dev/null
+++ b/pkg/front_end/testcases/general/constants/js_semantics/on_double.dart.weak.expect
@@ -0,0 +1,147 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:27:26: Error: Constant evaluation error:
+//   const Class c2 = Class.doubleShift(b, 1);
+//                          ^
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:21:45: Context: Binary operator '>>' on '1.5' requires operand of type 'int', but was of type 'double'.
+//   const Class.doubleShift(i1, i2) : a = (i1 >> i2);
+//                                             ^
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:27:15: Context: While analyzing:
+//   const Class c2 = Class.doubleShift(b, 1);
+//               ^
+//
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:29:26: Error: Constant evaluation error:
+//   const Class c4 = Class.tripleShift(b, 1);
+//                          ^
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:22:45: Context: Binary operator '>>>' on '1.5' requires operand of type 'int', but was of type 'double'.
+//   const Class.tripleShift(i1, i2) : a = (i1 >>> i2);
+//                                             ^
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:29:15: Context: While analyzing:
+//   const Class c4 = Class.tripleShift(b, 1);
+//               ^
+//
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:32:26: Error: Constant evaluation error:
+//   const Class d2 = Class.doubleShift(1, b);
+//                          ^
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:21:45: Context: Binary operator '>>' on '1.5' requires operand of type 'int', but was of type 'double'.
+//   const Class.doubleShift(i1, i2) : a = (i1 >> i2);
+//                                             ^
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:32:15: Context: While analyzing:
+//   const Class d2 = Class.doubleShift(1, b);
+//               ^
+//
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:34:26: Error: Constant evaluation error:
+//   const Class d4 = Class.tripleShift(1, b);
+//                          ^
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:22:45: Context: Binary operator '>>>' on '1.5' requires operand of type 'int', but was of type 'double'.
+//   const Class.tripleShift(i1, i2) : a = (i1 >>> i2);
+//                                             ^
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:34:15: Context: While analyzing:
+//   const Class d4 = Class.tripleShift(1, b);
+//               ^
+//
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:37:26: Error: Constant evaluation error:
+//   const Class e2 = Class.doubleShift(1.5, 1);
+//                          ^
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:21:45: Context: Binary operator '>>' on '1.5' requires operand of type 'int', but was of type 'double'.
+//   const Class.doubleShift(i1, i2) : a = (i1 >> i2);
+//                                             ^
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:37:15: Context: While analyzing:
+//   const Class e2 = Class.doubleShift(1.5, 1);
+//               ^
+//
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:39:26: Error: Constant evaluation error:
+//   const Class e4 = Class.tripleShift(1.5, 1);
+//                          ^
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:22:45: Context: Binary operator '>>>' on '1.5' requires operand of type 'int', but was of type 'double'.
+//   const Class.tripleShift(i1, i2) : a = (i1 >>> i2);
+//                                             ^
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:39:15: Context: While analyzing:
+//   const Class e4 = Class.tripleShift(1.5, 1);
+//               ^
+//
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:9:22: Error: Constant evaluation error:
+// const dynamic c1 = b >> 1;
+//                      ^
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:9:22: Context: Binary operator '>>' on '1.5' requires operand of type 'int', but was of type 'double'.
+// const dynamic c1 = b >> 1;
+//                      ^
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:9:15: Context: While analyzing:
+// const dynamic c1 = b >> 1;
+//               ^
+//
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:11:22: Error: Constant evaluation error:
+// const dynamic c3 = b >>> 1;
+//                      ^
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:11:22: Context: Binary operator '>>>' on '1.5' requires operand of type 'int', but was of type 'double'.
+// const dynamic c3 = b >>> 1;
+//                      ^
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:11:15: Context: While analyzing:
+// const dynamic c3 = b >>> 1;
+//               ^
+//
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:14:22: Error: Constant evaluation error:
+// const dynamic d1 = 1 >> b;
+//                      ^
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:14:25: Context: Expected constant '1.5' to be of type 'int', but was of type 'double'.
+// const dynamic d1 = 1 >> b;
+//                         ^
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:14:15: Context: While analyzing:
+// const dynamic d1 = 1 >> b;
+//               ^
+//
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:16:22: Error: Constant evaluation error:
+// const dynamic d3 = 1 >>> b;
+//                      ^
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:16:26: Context: Expected constant '1.5' to be of type 'int', but was of type 'double'.
+// const dynamic d3 = 1 >>> b;
+//                          ^
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:16:15: Context: While analyzing:
+// const dynamic d3 = 1 >>> b;
+//               ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object /*hasConstConstructor*/  {
+  final field core::int a;
+  const constructor doubleShift(dynamic i1, dynamic i2) → self::Class
+    : self::Class::a = i1{dynamic}.>>(i2) as{TypeError,ForDynamic,ForNonNullableByDefault} core::int, super core::Object::•()
+    ;
+  const constructor tripleShift(dynamic i1, dynamic i2) → self::Class
+    : self::Class::a = i1{dynamic}.>>>(i2) as{TypeError,ForDynamic,ForNonNullableByDefault} core::int, super core::Object::•()
+    ;
+}
+static const field dynamic a = #C1;
+static const field dynamic b = #C2;
+static const field dynamic c0 = #C3;
+static const field dynamic c1 = invalid-expression "Binary operator '>>' on '1.5' requires operand of type 'int', but was of type 'double'.";
+static const field dynamic c2 = #C3;
+static const field dynamic c3 = invalid-expression "Binary operator '>>>' on '1.5' requires operand of type 'int', but was of type 'double'.";
+static const field dynamic d0 = #C3;
+static const field dynamic d1 = invalid-expression "Expected constant '1.5' to be of type 'int', but was of type 'double'.";
+static const field dynamic d2 = #C3;
+static const field dynamic d3 = invalid-expression "Expected constant '1.5' to be of type 'int', but was of type 'double'.";
+static method main() → dynamic {
+  const self::Class c2 = invalid-expression "Binary operator '>>' on '1.5' requires operand of type 'int', but was of type 'double'.";
+  const self::Class c4 = invalid-expression "Binary operator '>>>' on '1.5' requires operand of type 'int', but was of type 'double'.";
+  const self::Class d2 = invalid-expression "Binary operator '>>' on '1.5' requires operand of type 'int', but was of type 'double'.";
+  const self::Class d4 = invalid-expression "Binary operator '>>>' on '1.5' requires operand of type 'int', but was of type 'double'.";
+  const self::Class e2 = invalid-expression "Binary operator '>>' on '1.5' requires operand of type 'int', but was of type 'double'.";
+  const self::Class e4 = invalid-expression "Binary operator '>>>' on '1.5' requires operand of type 'int', but was of type 'double'.";
+}
+
+constants  {
+  #C1 = 1.0
+  #C2 = 1.5
+  #C3 = 0.0
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///on_double.dart:
+- Class.doubleShift (from org-dartlang-testcase:///on_double.dart:21:9)
+- Object. (from org-dartlang-sdk:///lib/core/object.dart:25:9)
+- Class.tripleShift (from org-dartlang-testcase:///on_double.dart:22:9)
diff --git a/pkg/front_end/testcases/general/constants/js_semantics/on_double.dart.weak.outline.expect b/pkg/front_end/testcases/general/constants/js_semantics/on_double.dart.weak.outline.expect
new file mode 100644
index 0000000..c94c041
--- /dev/null
+++ b/pkg/front_end/testcases/general/constants/js_semantics/on_double.dart.weak.outline.expect
@@ -0,0 +1,37 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object /*hasConstConstructor*/  {
+  final field core::int a;
+  const constructor doubleShift(dynamic i1, dynamic i2) → self::Class
+    : self::Class::a = i1{dynamic}.>>(i2) as{TypeError,ForDynamic,ForNonNullableByDefault} core::int, super core::Object::•()
+    ;
+  const constructor tripleShift(dynamic i1, dynamic i2) → self::Class
+    : self::Class::a = i1{dynamic}.>>>(i2) as{TypeError,ForDynamic,ForNonNullableByDefault} core::int, super core::Object::•()
+    ;
+}
+static const field dynamic a = 1.0;
+static const field dynamic b = 1.5;
+static const field dynamic c0 = self::a{dynamic}.>>(1);
+static const field dynamic c1 = self::b{dynamic}.>>(1);
+static const field dynamic c2 = self::a{dynamic}.>>>(1);
+static const field dynamic c3 = self::b{dynamic}.>>>(1);
+static const field dynamic d0 = 1.{core::int::>>}(self::a as{TypeError,ForDynamic,ForNonNullableByDefault} core::int){(core::int) → core::int};
+static const field dynamic d1 = 1.{core::int::>>}(self::b as{TypeError,ForDynamic,ForNonNullableByDefault} core::int){(core::int) → core::int};
+static const field dynamic d2 = 1.{core::int::>>>}(self::a as{TypeError,ForDynamic,ForNonNullableByDefault} core::int){(core::int) → core::int};
+static const field dynamic d3 = 1.{core::int::>>>}(self::b as{TypeError,ForDynamic,ForNonNullableByDefault} core::int){(core::int) → core::int};
+static method main() → dynamic
+  ;
+
+
+Extra constant evaluation status:
+Evaluated: DynamicInvocation @ org-dartlang-testcase:///on_double.dart:8:22 -> DoubleConstant(0.0)
+Evaluated: StaticGet @ org-dartlang-testcase:///on_double.dart:9:20 -> DoubleConstant(1.5)
+Evaluated: DynamicInvocation @ org-dartlang-testcase:///on_double.dart:10:22 -> DoubleConstant(0.0)
+Evaluated: StaticGet @ org-dartlang-testcase:///on_double.dart:11:20 -> DoubleConstant(1.5)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///on_double.dart:13:22 -> DoubleConstant(0.0)
+Evaluated: StaticGet @ org-dartlang-testcase:///on_double.dart:14:25 -> DoubleConstant(1.5)
+Evaluated: InstanceInvocation @ org-dartlang-testcase:///on_double.dart:15:22 -> DoubleConstant(0.0)
+Evaluated: StaticGet @ org-dartlang-testcase:///on_double.dart:16:26 -> DoubleConstant(1.5)
+Extra constant evaluation: evaluated: 22, effectively constant: 8
diff --git a/pkg/front_end/testcases/general/constants/js_semantics/on_double.dart.weak.transformed.expect b/pkg/front_end/testcases/general/constants/js_semantics/on_double.dart.weak.transformed.expect
new file mode 100644
index 0000000..2573a35
--- /dev/null
+++ b/pkg/front_end/testcases/general/constants/js_semantics/on_double.dart.weak.transformed.expect
@@ -0,0 +1,147 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:27:26: Error: Constant evaluation error:
+//   const Class c2 = Class.doubleShift(b, 1);
+//                          ^
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:21:45: Context: Binary operator '>>' on '1.5' requires operand of type 'int', but was of type 'double'.
+//   const Class.doubleShift(i1, i2) : a = (i1 >> i2);
+//                                             ^
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:27:15: Context: While analyzing:
+//   const Class c2 = Class.doubleShift(b, 1);
+//               ^
+//
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:29:26: Error: Constant evaluation error:
+//   const Class c4 = Class.tripleShift(b, 1);
+//                          ^
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:22:45: Context: Binary operator '>>>' on '1.5' requires operand of type 'int', but was of type 'double'.
+//   const Class.tripleShift(i1, i2) : a = (i1 >>> i2);
+//                                             ^
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:29:15: Context: While analyzing:
+//   const Class c4 = Class.tripleShift(b, 1);
+//               ^
+//
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:32:26: Error: Constant evaluation error:
+//   const Class d2 = Class.doubleShift(1, b);
+//                          ^
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:21:45: Context: Binary operator '>>' on '1.5' requires operand of type 'int', but was of type 'double'.
+//   const Class.doubleShift(i1, i2) : a = (i1 >> i2);
+//                                             ^
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:32:15: Context: While analyzing:
+//   const Class d2 = Class.doubleShift(1, b);
+//               ^
+//
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:34:26: Error: Constant evaluation error:
+//   const Class d4 = Class.tripleShift(1, b);
+//                          ^
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:22:45: Context: Binary operator '>>>' on '1.5' requires operand of type 'int', but was of type 'double'.
+//   const Class.tripleShift(i1, i2) : a = (i1 >>> i2);
+//                                             ^
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:34:15: Context: While analyzing:
+//   const Class d4 = Class.tripleShift(1, b);
+//               ^
+//
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:37:26: Error: Constant evaluation error:
+//   const Class e2 = Class.doubleShift(1.5, 1);
+//                          ^
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:21:45: Context: Binary operator '>>' on '1.5' requires operand of type 'int', but was of type 'double'.
+//   const Class.doubleShift(i1, i2) : a = (i1 >> i2);
+//                                             ^
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:37:15: Context: While analyzing:
+//   const Class e2 = Class.doubleShift(1.5, 1);
+//               ^
+//
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:39:26: Error: Constant evaluation error:
+//   const Class e4 = Class.tripleShift(1.5, 1);
+//                          ^
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:22:45: Context: Binary operator '>>>' on '1.5' requires operand of type 'int', but was of type 'double'.
+//   const Class.tripleShift(i1, i2) : a = (i1 >>> i2);
+//                                             ^
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:39:15: Context: While analyzing:
+//   const Class e4 = Class.tripleShift(1.5, 1);
+//               ^
+//
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:9:22: Error: Constant evaluation error:
+// const dynamic c1 = b >> 1;
+//                      ^
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:9:22: Context: Binary operator '>>' on '1.5' requires operand of type 'int', but was of type 'double'.
+// const dynamic c1 = b >> 1;
+//                      ^
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:9:15: Context: While analyzing:
+// const dynamic c1 = b >> 1;
+//               ^
+//
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:11:22: Error: Constant evaluation error:
+// const dynamic c3 = b >>> 1;
+//                      ^
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:11:22: Context: Binary operator '>>>' on '1.5' requires operand of type 'int', but was of type 'double'.
+// const dynamic c3 = b >>> 1;
+//                      ^
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:11:15: Context: While analyzing:
+// const dynamic c3 = b >>> 1;
+//               ^
+//
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:14:22: Error: Constant evaluation error:
+// const dynamic d1 = 1 >> b;
+//                      ^
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:14:25: Context: Expected constant '1.5' to be of type 'int', but was of type 'double'.
+// const dynamic d1 = 1 >> b;
+//                         ^
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:14:15: Context: While analyzing:
+// const dynamic d1 = 1 >> b;
+//               ^
+//
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:16:22: Error: Constant evaluation error:
+// const dynamic d3 = 1 >>> b;
+//                      ^
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:16:26: Context: Expected constant '1.5' to be of type 'int', but was of type 'double'.
+// const dynamic d3 = 1 >>> b;
+//                          ^
+// pkg/front_end/testcases/general/constants/js_semantics/on_double.dart:16:15: Context: While analyzing:
+// const dynamic d3 = 1 >>> b;
+//               ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object /*hasConstConstructor*/  {
+  final field core::int a;
+  const constructor doubleShift(dynamic i1, dynamic i2) → self::Class
+    : self::Class::a = i1{dynamic}.>>(i2) as{TypeError,ForDynamic,ForNonNullableByDefault} core::int, super core::Object::•()
+    ;
+  const constructor tripleShift(dynamic i1, dynamic i2) → self::Class
+    : self::Class::a = i1{dynamic}.>>>(i2) as{TypeError,ForDynamic,ForNonNullableByDefault} core::int, super core::Object::•()
+    ;
+}
+static const field dynamic a = #C1;
+static const field dynamic b = #C2;
+static const field dynamic c0 = #C3;
+static const field dynamic c1 = invalid-expression "Binary operator '>>' on '1.5' requires operand of type 'int', but was of type 'double'.";
+static const field dynamic c2 = #C3;
+static const field dynamic c3 = invalid-expression "Binary operator '>>>' on '1.5' requires operand of type 'int', but was of type 'double'.";
+static const field dynamic d0 = #C3;
+static const field dynamic d1 = invalid-expression "Expected constant '1.5' to be of type 'int', but was of type 'double'.";
+static const field dynamic d2 = #C3;
+static const field dynamic d3 = invalid-expression "Expected constant '1.5' to be of type 'int', but was of type 'double'.";
+static method main() → dynamic {
+  const self::Class c2 = invalid-expression "Binary operator '>>' on '1.5' requires operand of type 'int', but was of type 'double'.";
+  const self::Class c4 = invalid-expression "Binary operator '>>>' on '1.5' requires operand of type 'int', but was of type 'double'.";
+  const self::Class d2 = invalid-expression "Binary operator '>>' on '1.5' requires operand of type 'int', but was of type 'double'.";
+  const self::Class d4 = invalid-expression "Binary operator '>>>' on '1.5' requires operand of type 'int', but was of type 'double'.";
+  const self::Class e2 = invalid-expression "Binary operator '>>' on '1.5' requires operand of type 'int', but was of type 'double'.";
+  const self::Class e4 = invalid-expression "Binary operator '>>>' on '1.5' requires operand of type 'int', but was of type 'double'.";
+}
+
+constants  {
+  #C1 = 1.0
+  #C2 = 1.5
+  #C3 = 0.0
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///on_double.dart:
+- Class.doubleShift (from org-dartlang-testcase:///on_double.dart:21:9)
+- Object. (from org-dartlang-sdk:///lib/core/object.dart:25:9)
+- Class.tripleShift (from org-dartlang-testcase:///on_double.dart:22:9)
diff --git a/pkg/front_end/testcases/general/null_check_type_variable_type.dart b/pkg/front_end/testcases/general/null_check_type_variable_type.dart
new file mode 100644
index 0000000..30f0312
--- /dev/null
+++ b/pkg/front_end/testcases/general/null_check_type_variable_type.dart
@@ -0,0 +1,26 @@
+// Copyright (c) 2021, 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.
+
+class Element {}
+
+class Class<E extends Element?> {
+  E? element;
+
+  Class(this.element);
+
+  void setElement(E? element) {
+    if (this.element != element) {
+      this.element = element;
+      Set<Element> elements = new Set<Element>();
+      if (element != null) {
+        elements.add(element);
+      }
+      if (this.element != null) {
+        elements.add(this.element!);
+      }
+    }
+  }
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/general/null_check_type_variable_type.dart.textual_outline.expect b/pkg/front_end/testcases/general/null_check_type_variable_type.dart.textual_outline.expect
new file mode 100644
index 0000000..e380d41
--- /dev/null
+++ b/pkg/front_end/testcases/general/null_check_type_variable_type.dart.textual_outline.expect
@@ -0,0 +1,9 @@
+class Element {}
+
+class Class<E extends Element?> {
+  E? element;
+  Class(this.element);
+  void setElement(E? element) {}
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/general/null_check_type_variable_type.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/null_check_type_variable_type.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..c1b9d90
--- /dev/null
+++ b/pkg/front_end/testcases/general/null_check_type_variable_type.dart.textual_outline_modelled.expect
@@ -0,0 +1,9 @@
+class Class<E extends Element?> {
+  Class(this.element);
+  E? element;
+  void setElement(E? element) {}
+}
+
+class Element {}
+
+main() {}
diff --git a/pkg/front_end/testcases/general/null_check_type_variable_type.dart.weak.expect b/pkg/front_end/testcases/general/null_check_type_variable_type.dart.weak.expect
new file mode 100644
index 0000000..6972fb1
--- /dev/null
+++ b/pkg/front_end/testcases/general/null_check_type_variable_type.dart.weak.expect
@@ -0,0 +1,29 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:collection" as col;
+
+class Element extends core::Object {
+  synthetic constructor •() → self::Element
+    : super core::Object::•()
+    ;
+}
+class Class<E extends self::Element? = self::Element?> extends core::Object {
+  generic-covariant-impl field self::Class::E? element;
+  constructor •(self::Class::E? element) → self::Class<self::Class::E%>
+    : self::Class::element = element, super core::Object::•()
+    ;
+  method setElement(generic-covariant-impl self::Class::E? element) → void {
+    if(!this.{self::Class::element}.{core::Object::==}(element)) {
+      this.{self::Class::element} = element;
+      core::Set<self::Element> elements = col::LinkedHashSet::•<self::Element>();
+      if(!element.{core::Object::==}(null)) {
+        elements.{core::Set::add}(element{self::Class::E% & self::Element /* '%' & '!' = '!' */});
+      }
+      if(!this.{self::Class::element}.{core::Object::==}(null)) {
+        elements.{core::Set::add}(this.{self::Class::element}!);
+      }
+    }
+  }
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/general/null_check_type_variable_type.dart.weak.outline.expect b/pkg/front_end/testcases/general/null_check_type_variable_type.dart.weak.outline.expect
new file mode 100644
index 0000000..199055c
--- /dev/null
+++ b/pkg/front_end/testcases/general/null_check_type_variable_type.dart.weak.outline.expect
@@ -0,0 +1,17 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class Element extends core::Object {
+  synthetic constructor •() → self::Element
+    ;
+}
+class Class<E extends self::Element? = self::Element?> extends core::Object {
+  generic-covariant-impl field self::Class::E? element;
+  constructor •(self::Class::E? element) → self::Class<self::Class::E%>
+    ;
+  method setElement(generic-covariant-impl self::Class::E? element) → void
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/general/null_check_type_variable_type.dart.weak.transformed.expect b/pkg/front_end/testcases/general/null_check_type_variable_type.dart.weak.transformed.expect
new file mode 100644
index 0000000..6405a73
--- /dev/null
+++ b/pkg/front_end/testcases/general/null_check_type_variable_type.dart.weak.transformed.expect
@@ -0,0 +1,29 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:collection" as col;
+
+class Element extends core::Object {
+  synthetic constructor •() → self::Element
+    : super core::Object::•()
+    ;
+}
+class Class<E extends self::Element? = self::Element?> extends core::Object {
+  generic-covariant-impl field self::Class::E? element;
+  constructor •(self::Class::E? element) → self::Class<self::Class::E%>
+    : self::Class::element = element, super core::Object::•()
+    ;
+  method setElement(generic-covariant-impl self::Class::E? element) → void {
+    if(!this.{self::Class::element}.{core::Object::==}(element)) {
+      this.{self::Class::element} = element;
+      core::Set<self::Element> elements = new col::_CompactLinkedHashSet::•<self::Element>();
+      if(!element.{core::Object::==}(null)) {
+        elements.{core::Set::add}(element{self::Class::E% & self::Element /* '%' & '!' = '!' */});
+      }
+      if(!this.{self::Class::element}.{core::Object::==}(null)) {
+        elements.{core::Set::add}(this.{self::Class::element}!);
+      }
+    }
+  }
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue43278.dart.strong.expect b/pkg/front_end/testcases/nnbd/issue43278.dart.strong.expect
index d15a9c9..3bfcc52 100644
--- a/pkg/front_end/testcases/nnbd/issue43278.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/issue43278.dart.strong.expect
@@ -19,15 +19,8 @@
 //   b.fooExtension ??= x; // Error.
 //     ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/issue43278.dart:29:5: Error: The getter 'fooExtension' isn't defined for the class 'B?'.
-//  - 'B' is from 'pkg/front_end/testcases/nnbd/issue43278.dart'.
-// Try correcting the name to the name of an existing getter, or defining a getter or field named 'fooExtension'.
-//   t.fooExtension ??= x; // Error.
-//     ^^^^^^^^^^^^
-//
-// pkg/front_end/testcases/nnbd/issue43278.dart:29:5: Error: The setter 'fooExtension' isn't defined for the class 'B?'.
-//  - 'B' is from 'pkg/front_end/testcases/nnbd/issue43278.dart'.
-// Try correcting the name to the name of an existing setter, or defining a setter or field named 'fooExtension'.
+// pkg/front_end/testcases/nnbd/issue43278.dart:29:5: Error: Property 'fooExtension' cannot be accessed on 'T' because it is potentially null.
+// Try accessing using ?. instead.
 //   t.fooExtension ??= x; // Error.
 //     ^^^^^^^^^^^^
 //
@@ -86,15 +79,13 @@
 Try accessing using ?. instead.
   b.fooExtension ??= x; // Error.
     ^^^^^^^^^^^^" in self::Extension|set#fooExtension(#t10, x) : null;
-  let final self::testExtension::T% #t13 = t in invalid-expression "pkg/front_end/testcases/nnbd/issue43278.dart:29:5: Error: The getter 'fooExtension' isn't defined for the class 'B?'.
- - 'B' is from 'pkg/front_end/testcases/nnbd/issue43278.dart'.
-Try correcting the name to the name of an existing getter, or defining a getter or field named 'fooExtension'.
+  let final self::testExtension::T% #t13 = t in (let final Never #t14 = invalid-expression "pkg/front_end/testcases/nnbd/issue43278.dart:29:5: Error: Property 'fooExtension' cannot be accessed on 'T' because it is potentially null.
+Try accessing using ?. instead.
   t.fooExtension ??= x; // Error.
-    ^^^^^^^^^^^^".{core::Object::==}(null) ?{dynamic} invalid-expression "pkg/front_end/testcases/nnbd/issue43278.dart:29:5: Error: The setter 'fooExtension' isn't defined for the class 'B?'.
- - 'B' is from 'pkg/front_end/testcases/nnbd/issue43278.dart'.
-Try correcting the name to the name of an existing setter, or defining a setter or field named 'fooExtension'.
+    ^^^^^^^^^^^^" in self::Extension|get#fooExtension(#t13)).{core::num::==}(null) ?{core::int} let final Never #t15 = invalid-expression "pkg/front_end/testcases/nnbd/issue43278.dart:29:5: Error: Property 'fooExtension' cannot be accessed on 'T' because it is potentially null.
+Try accessing using ?. instead.
   t.fooExtension ??= x; // Error.
-    ^^^^^^^^^^^^" : null;
-  let final self::B? #t14 = b in #t14.{core::Object::==}(null) ?{core::int?} null : let final self::B #t15 = self::Extension|get#barExtension(#t14{self::B}) in self::Extension|get#fooExtension(#t15).{core::num::==}(null) ?{core::int} self::Extension|set#fooExtension(#t15, x) : null;
+    ^^^^^^^^^^^^" in self::Extension|set#fooExtension(#t13, x) : null;
+  let final self::B? #t16 = b in #t16.{core::Object::==}(null) ?{core::int?} null : let final self::B #t17 = self::Extension|get#barExtension(#t16{self::B}) in self::Extension|get#fooExtension(#t17).{core::num::==}(null) ?{core::int} self::Extension|set#fooExtension(#t17, x) : null;
 }
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue43278.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/issue43278.dart.strong.transformed.expect
index d15a9c9..3bfcc52 100644
--- a/pkg/front_end/testcases/nnbd/issue43278.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/issue43278.dart.strong.transformed.expect
@@ -19,15 +19,8 @@
 //   b.fooExtension ??= x; // Error.
 //     ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/issue43278.dart:29:5: Error: The getter 'fooExtension' isn't defined for the class 'B?'.
-//  - 'B' is from 'pkg/front_end/testcases/nnbd/issue43278.dart'.
-// Try correcting the name to the name of an existing getter, or defining a getter or field named 'fooExtension'.
-//   t.fooExtension ??= x; // Error.
-//     ^^^^^^^^^^^^
-//
-// pkg/front_end/testcases/nnbd/issue43278.dart:29:5: Error: The setter 'fooExtension' isn't defined for the class 'B?'.
-//  - 'B' is from 'pkg/front_end/testcases/nnbd/issue43278.dart'.
-// Try correcting the name to the name of an existing setter, or defining a setter or field named 'fooExtension'.
+// pkg/front_end/testcases/nnbd/issue43278.dart:29:5: Error: Property 'fooExtension' cannot be accessed on 'T' because it is potentially null.
+// Try accessing using ?. instead.
 //   t.fooExtension ??= x; // Error.
 //     ^^^^^^^^^^^^
 //
@@ -86,15 +79,13 @@
 Try accessing using ?. instead.
   b.fooExtension ??= x; // Error.
     ^^^^^^^^^^^^" in self::Extension|set#fooExtension(#t10, x) : null;
-  let final self::testExtension::T% #t13 = t in invalid-expression "pkg/front_end/testcases/nnbd/issue43278.dart:29:5: Error: The getter 'fooExtension' isn't defined for the class 'B?'.
- - 'B' is from 'pkg/front_end/testcases/nnbd/issue43278.dart'.
-Try correcting the name to the name of an existing getter, or defining a getter or field named 'fooExtension'.
+  let final self::testExtension::T% #t13 = t in (let final Never #t14 = invalid-expression "pkg/front_end/testcases/nnbd/issue43278.dart:29:5: Error: Property 'fooExtension' cannot be accessed on 'T' because it is potentially null.
+Try accessing using ?. instead.
   t.fooExtension ??= x; // Error.
-    ^^^^^^^^^^^^".{core::Object::==}(null) ?{dynamic} invalid-expression "pkg/front_end/testcases/nnbd/issue43278.dart:29:5: Error: The setter 'fooExtension' isn't defined for the class 'B?'.
- - 'B' is from 'pkg/front_end/testcases/nnbd/issue43278.dart'.
-Try correcting the name to the name of an existing setter, or defining a setter or field named 'fooExtension'.
+    ^^^^^^^^^^^^" in self::Extension|get#fooExtension(#t13)).{core::num::==}(null) ?{core::int} let final Never #t15 = invalid-expression "pkg/front_end/testcases/nnbd/issue43278.dart:29:5: Error: Property 'fooExtension' cannot be accessed on 'T' because it is potentially null.
+Try accessing using ?. instead.
   t.fooExtension ??= x; // Error.
-    ^^^^^^^^^^^^" : null;
-  let final self::B? #t14 = b in #t14.{core::Object::==}(null) ?{core::int?} null : let final self::B #t15 = self::Extension|get#barExtension(#t14{self::B}) in self::Extension|get#fooExtension(#t15).{core::num::==}(null) ?{core::int} self::Extension|set#fooExtension(#t15, x) : null;
+    ^^^^^^^^^^^^" in self::Extension|set#fooExtension(#t13, x) : null;
+  let final self::B? #t16 = b in #t16.{core::Object::==}(null) ?{core::int?} null : let final self::B #t17 = self::Extension|get#barExtension(#t16{self::B}) in self::Extension|get#fooExtension(#t17).{core::num::==}(null) ?{core::int} self::Extension|set#fooExtension(#t17, x) : null;
 }
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue43278.dart.weak.expect b/pkg/front_end/testcases/nnbd/issue43278.dart.weak.expect
index d15a9c9..3bfcc52 100644
--- a/pkg/front_end/testcases/nnbd/issue43278.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/issue43278.dart.weak.expect
@@ -19,15 +19,8 @@
 //   b.fooExtension ??= x; // Error.
 //     ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/issue43278.dart:29:5: Error: The getter 'fooExtension' isn't defined for the class 'B?'.
-//  - 'B' is from 'pkg/front_end/testcases/nnbd/issue43278.dart'.
-// Try correcting the name to the name of an existing getter, or defining a getter or field named 'fooExtension'.
-//   t.fooExtension ??= x; // Error.
-//     ^^^^^^^^^^^^
-//
-// pkg/front_end/testcases/nnbd/issue43278.dart:29:5: Error: The setter 'fooExtension' isn't defined for the class 'B?'.
-//  - 'B' is from 'pkg/front_end/testcases/nnbd/issue43278.dart'.
-// Try correcting the name to the name of an existing setter, or defining a setter or field named 'fooExtension'.
+// pkg/front_end/testcases/nnbd/issue43278.dart:29:5: Error: Property 'fooExtension' cannot be accessed on 'T' because it is potentially null.
+// Try accessing using ?. instead.
 //   t.fooExtension ??= x; // Error.
 //     ^^^^^^^^^^^^
 //
@@ -86,15 +79,13 @@
 Try accessing using ?. instead.
   b.fooExtension ??= x; // Error.
     ^^^^^^^^^^^^" in self::Extension|set#fooExtension(#t10, x) : null;
-  let final self::testExtension::T% #t13 = t in invalid-expression "pkg/front_end/testcases/nnbd/issue43278.dart:29:5: Error: The getter 'fooExtension' isn't defined for the class 'B?'.
- - 'B' is from 'pkg/front_end/testcases/nnbd/issue43278.dart'.
-Try correcting the name to the name of an existing getter, or defining a getter or field named 'fooExtension'.
+  let final self::testExtension::T% #t13 = t in (let final Never #t14 = invalid-expression "pkg/front_end/testcases/nnbd/issue43278.dart:29:5: Error: Property 'fooExtension' cannot be accessed on 'T' because it is potentially null.
+Try accessing using ?. instead.
   t.fooExtension ??= x; // Error.
-    ^^^^^^^^^^^^".{core::Object::==}(null) ?{dynamic} invalid-expression "pkg/front_end/testcases/nnbd/issue43278.dart:29:5: Error: The setter 'fooExtension' isn't defined for the class 'B?'.
- - 'B' is from 'pkg/front_end/testcases/nnbd/issue43278.dart'.
-Try correcting the name to the name of an existing setter, or defining a setter or field named 'fooExtension'.
+    ^^^^^^^^^^^^" in self::Extension|get#fooExtension(#t13)).{core::num::==}(null) ?{core::int} let final Never #t15 = invalid-expression "pkg/front_end/testcases/nnbd/issue43278.dart:29:5: Error: Property 'fooExtension' cannot be accessed on 'T' because it is potentially null.
+Try accessing using ?. instead.
   t.fooExtension ??= x; // Error.
-    ^^^^^^^^^^^^" : null;
-  let final self::B? #t14 = b in #t14.{core::Object::==}(null) ?{core::int?} null : let final self::B #t15 = self::Extension|get#barExtension(#t14{self::B}) in self::Extension|get#fooExtension(#t15).{core::num::==}(null) ?{core::int} self::Extension|set#fooExtension(#t15, x) : null;
+    ^^^^^^^^^^^^" in self::Extension|set#fooExtension(#t13, x) : null;
+  let final self::B? #t16 = b in #t16.{core::Object::==}(null) ?{core::int?} null : let final self::B #t17 = self::Extension|get#barExtension(#t16{self::B}) in self::Extension|get#fooExtension(#t17).{core::num::==}(null) ?{core::int} self::Extension|set#fooExtension(#t17, x) : null;
 }
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue43278.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/issue43278.dart.weak.transformed.expect
index d15a9c9..3bfcc52 100644
--- a/pkg/front_end/testcases/nnbd/issue43278.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/issue43278.dart.weak.transformed.expect
@@ -19,15 +19,8 @@
 //   b.fooExtension ??= x; // Error.
 //     ^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/issue43278.dart:29:5: Error: The getter 'fooExtension' isn't defined for the class 'B?'.
-//  - 'B' is from 'pkg/front_end/testcases/nnbd/issue43278.dart'.
-// Try correcting the name to the name of an existing getter, or defining a getter or field named 'fooExtension'.
-//   t.fooExtension ??= x; // Error.
-//     ^^^^^^^^^^^^
-//
-// pkg/front_end/testcases/nnbd/issue43278.dart:29:5: Error: The setter 'fooExtension' isn't defined for the class 'B?'.
-//  - 'B' is from 'pkg/front_end/testcases/nnbd/issue43278.dart'.
-// Try correcting the name to the name of an existing setter, or defining a setter or field named 'fooExtension'.
+// pkg/front_end/testcases/nnbd/issue43278.dart:29:5: Error: Property 'fooExtension' cannot be accessed on 'T' because it is potentially null.
+// Try accessing using ?. instead.
 //   t.fooExtension ??= x; // Error.
 //     ^^^^^^^^^^^^
 //
@@ -86,15 +79,13 @@
 Try accessing using ?. instead.
   b.fooExtension ??= x; // Error.
     ^^^^^^^^^^^^" in self::Extension|set#fooExtension(#t10, x) : null;
-  let final self::testExtension::T% #t13 = t in invalid-expression "pkg/front_end/testcases/nnbd/issue43278.dart:29:5: Error: The getter 'fooExtension' isn't defined for the class 'B?'.
- - 'B' is from 'pkg/front_end/testcases/nnbd/issue43278.dart'.
-Try correcting the name to the name of an existing getter, or defining a getter or field named 'fooExtension'.
+  let final self::testExtension::T% #t13 = t in (let final Never #t14 = invalid-expression "pkg/front_end/testcases/nnbd/issue43278.dart:29:5: Error: Property 'fooExtension' cannot be accessed on 'T' because it is potentially null.
+Try accessing using ?. instead.
   t.fooExtension ??= x; // Error.
-    ^^^^^^^^^^^^".{core::Object::==}(null) ?{dynamic} invalid-expression "pkg/front_end/testcases/nnbd/issue43278.dart:29:5: Error: The setter 'fooExtension' isn't defined for the class 'B?'.
- - 'B' is from 'pkg/front_end/testcases/nnbd/issue43278.dart'.
-Try correcting the name to the name of an existing setter, or defining a setter or field named 'fooExtension'.
+    ^^^^^^^^^^^^" in self::Extension|get#fooExtension(#t13)).{core::num::==}(null) ?{core::int} let final Never #t15 = invalid-expression "pkg/front_end/testcases/nnbd/issue43278.dart:29:5: Error: Property 'fooExtension' cannot be accessed on 'T' because it is potentially null.
+Try accessing using ?. instead.
   t.fooExtension ??= x; // Error.
-    ^^^^^^^^^^^^" : null;
-  let final self::B? #t14 = b in #t14.{core::Object::==}(null) ?{core::int?} null : let final self::B #t15 = self::Extension|get#barExtension(#t14{self::B}) in self::Extension|get#fooExtension(#t15).{core::num::==}(null) ?{core::int} self::Extension|set#fooExtension(#t15, x) : null;
+    ^^^^^^^^^^^^" in self::Extension|set#fooExtension(#t13, x) : null;
+  let final self::B? #t16 = b in #t16.{core::Object::==}(null) ?{core::int?} null : let final self::B #t17 = self::Extension|get#barExtension(#t16{self::B}) in self::Extension|get#fooExtension(#t17).{core::num::==}(null) ?{core::int} self::Extension|set#fooExtension(#t17, x) : null;
 }
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/textual_outline.status b/pkg/front_end/testcases/textual_outline.status
index a8397df..66bc9f8 100644
--- a/pkg/front_end/testcases/textual_outline.status
+++ b/pkg/front_end/testcases/textual_outline.status
@@ -30,7 +30,9 @@
 general/bad_setter_abstract: FormatterCrash
 general/bug31124: FormatterCrash
 general/clone_function_type: FormatterCrash
+general/constants/js_semantics/issue45376: FormatterCrash
 general/constants/js_semantics/number_folds: FormatterCrash
+general/constants/js_semantics/on_double: FormatterCrash
 general/constants/number_folds: FormatterCrash
 general/constants/various: FormatterCrash
 general/constructor_initializer_invalid: FormatterCrash
diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart
index 3298c90..fde2440 100644
--- a/pkg/kernel/lib/ast.dart
+++ b/pkg/kernel/lib/ast.dart
@@ -84,6 +84,7 @@
 import 'type_algebra.dart';
 import 'type_environment.dart';
 import 'src/assumptions.dart';
+import 'src/non_null.dart';
 import 'src/printer.dart';
 import 'src/text_util.dart';
 
@@ -10394,6 +10395,14 @@
   /// `void`, or `bottom`.
   DartType withDeclaredNullability(Nullability declaredNullability);
 
+  /// Creates the type corresponding to this type without null, if possible.
+  ///
+  /// Note that not all types, for instance `dynamic`, have a corresponding
+  /// non-nullable type. For these, the type itself is returned.
+  ///
+  /// This corresponds to the `NonNull` function of the nnbd specification.
+  DartType toNonNull() => computeNonNull(this);
+
   /// Checks if the type is potentially nullable.
   ///
   /// A type is potentially nullable if it's nullable or if its nullability is
@@ -11577,9 +11586,6 @@
     if (declaredNullability == this.declaredNullability) {
       return this;
     }
-    // TODO(dmitryas): Consider removing the assert.
-    assert(promotedBound == null,
-        "Can't change the nullability attribute of an intersection type.");
     return new TypeParameterType(parameter, declaredNullability, promotedBound);
   }
 
diff --git a/pkg/kernel/lib/src/non_null.dart b/pkg/kernel/lib/src/non_null.dart
index d8b3c73..b0e7cd2 100644
--- a/pkg/kernel/lib/src/non_null.dart
+++ b/pkg/kernel/lib/src/non_null.dart
@@ -4,7 +4,7 @@
 
 import '../ast.dart';
 
-/// Returns the type defines as `NonNull(type)` in the nnbd specification.
+/// Returns the type defined as `NonNull(type)` in the nnbd specification.
 DartType computeNonNull(DartType type) {
   return type.accept(const _NonNullVisitor()) ?? type;
 }
@@ -23,10 +23,18 @@
   }
 
   @override
-  DartType? visitDynamicType(DynamicType node) => null;
+  DartType? visitDynamicType(DynamicType node) {
+    // NonNull(dynamic) = dynamic
+    return null;
+  }
 
   @override
   DartType? visitFunctionType(FunctionType node) {
+    // NonNull(T0 Function(...)) = T0 Function(...)
+    //
+    // NonNull(T?) = NonNull(T)
+    //
+    // NonNull(T*) = NonNull(T)
     if (node.declaredNullability == Nullability.nonNullable) {
       return null;
     }
@@ -35,17 +43,51 @@
 
   @override
   DartType? visitFutureOrType(FutureOrType node) {
-    DartType? typeArgument = node.typeArgument.accept(this);
-    if (node.declaredNullability == Nullability.nonNullable &&
-        typeArgument == null) {
+    // NonNull(FutureOr<T>) = FutureOr<T>
+    //
+    // NonNull(T?) = NonNull(T)
+    //
+    // NonNull(T*) = NonNull(T)
+
+    // Note that we should _not_ compute NonNull of the type argument. Consider
+    //
+    //     NonNull(FutureOr<int?>?)
+    //
+    // We have that
+    //
+    //     FutureOr<int?>? = Future<int?>? | int?
+    //
+    // and therefore that
+    //
+    //     NonNull(FutureOr<int?>?) = NonNull(FutureOr<int?>?) | NonNull(int?)
+    //                              = FutureOr<int?> | int
+    //
+    // but that means that while `null` is not a possible value from `int` it
+    // is still a possible value from awaiting the future. Taking NonNull on
+    // the type argument as well as on the `FutureOr`:
+    //
+    //     NonNull(FutureOr<int?>?) = NonNull(FutureOr<NonNull(int?)>?)
+    //                              = FutureOr<int>
+    //
+    // would be wrong since it would compute that the awaited result could not
+    // be `null`.
+
+    if (node.declaredNullability == Nullability.nonNullable) {
       return null;
     }
-    return new FutureOrType(
-        typeArgument ?? node.typeArgument, Nullability.nonNullable);
+    return new FutureOrType(node.typeArgument, Nullability.nonNullable);
   }
 
   @override
   DartType? visitInterfaceType(InterfaceType node) {
+    // NonNull(C<T1, ... , Tn>) = C<T1, ... , Tn> for class C other
+    // than Null (including Object).
+    //
+    // NonNull(Function) = Function
+    //
+    // NonNull(T?) = NonNull(T)
+    //
+    // NonNull(T*) = NonNull(T)
     if (node.declaredNullability == Nullability.nonNullable) {
       return null;
     }
@@ -54,6 +96,12 @@
 
   @override
   DartType? visitExtensionType(ExtensionType node) {
+    // NonNull(C<T1, ... , Tn>) = C<T1, ... , Tn> for class C other
+    // than Null (including Object).
+    //
+    // NonNull(T?) = NonNull(T)
+    //
+    // NonNull(T*) = NonNull(T)
     if (node.declaredNullability == Nullability.nonNullable) {
       return null;
     }
@@ -65,6 +113,11 @@
 
   @override
   DartType? visitNeverType(NeverType node) {
+    // NonNull(Never) = Never
+    //
+    // NonNull(T?) = NonNull(T)
+    //
+    // NonNull(T*) = NonNull(T)
     if (node.declaredNullability == Nullability.nonNullable) {
       return null;
     }
@@ -73,15 +126,25 @@
 
   @override
   DartType? visitNullType(NullType node) {
+    // NonNull(Null) = Never
     return const NeverType.nonNullable();
   }
 
   @override
   DartType? visitTypeParameterType(TypeParameterType node) {
+    // NonNull(X) = X & NonNull(B), where B is the bound of X.
+    //
+    // NonNull(X & T) = X & NonNull(T)
+    //
+    // NonNull(T?) = NonNull(T)
+    //
+    // NonNull(T*) = NonNull(T)
     if (node.nullability == Nullability.nonNullable) {
       return null;
     }
     if (node.promotedBound != null) {
+      // NonNull(X & T) = X & NonNull(T)
+
       if (node.promotedBound!.nullability == Nullability.nonNullable) {
         // The promoted bound is already non-nullable so we set the declared
         // nullability to non-nullable.
@@ -108,6 +171,7 @@
             node.parameter, Nullability.undetermined, promotedBound);
       }
     } else {
+      // NonNull(X) = X & NonNull(B), where B is the bound of X.
       if (node.bound.nullability == Nullability.nonNullable) {
         // The bound is already non-nullable so we set the declared nullability
         // to non-nullable.
@@ -134,6 +198,12 @@
 
   @override
   DartType? visitTypedefType(TypedefType node) {
+    // NonNull(C<T1, ... , Tn>) = C<T1, ... , Tn> for class C other
+    // than Null (including Object).
+    //
+    // NonNull(T?) = NonNull(T)
+    //
+    // NonNull(T*) = NonNull(T)
     if (node.declaredNullability == Nullability.nonNullable) {
       return null;
     }
@@ -141,5 +211,8 @@
   }
 
   @override
-  DartType? visitVoidType(VoidType node) => null;
+  DartType? visitVoidType(VoidType node) {
+    // NonNull(void) = void
+    return null;
+  }
 }
diff --git a/pkg/kernel/test/non_null_test.dart b/pkg/kernel/test/non_null_test.dart
index ef3b433..5a3dca1 100644
--- a/pkg/kernel/test/non_null_test.dart
+++ b/pkg/kernel/test/non_null_test.dart
@@ -29,18 +29,18 @@
   'List<Object*>': 'List<Object*>',
   'List<Object*>?': 'List<Object*>',
   'List<Object*>*': 'List<Object*>',
-  'FutureOr<Null>': 'FutureOr<Never>',
+  'FutureOr<Null>': 'FutureOr<Null>',
   'FutureOr<dynamic>': 'FutureOr<dynamic>',
   'FutureOr<Object>': 'FutureOr<Object>',
   'FutureOr<Object>?': 'FutureOr<Object>',
   'FutureOr<Object>*': 'FutureOr<Object>',
-  'FutureOr<Object?>': 'FutureOr<Object>',
-  'FutureOr<Object?>?': 'FutureOr<Object>',
-  'FutureOr<Object?>*': 'FutureOr<Object>',
-  'FutureOr<Object*>': 'FutureOr<Object>',
-  'FutureOr<Object*>?': 'FutureOr<Object>',
-  'FutureOr<Object*>*': 'FutureOr<Object>',
-  'FutureOr<FutureOr<Object?>>': 'FutureOr<FutureOr<Object>>',
+  'FutureOr<Object?>': 'FutureOr<Object?>',
+  'FutureOr<Object?>?': 'FutureOr<Object?>',
+  'FutureOr<Object?>*': 'FutureOr<Object?>',
+  'FutureOr<Object*>': 'FutureOr<Object*>',
+  'FutureOr<Object*>?': 'FutureOr<Object*>',
+  'FutureOr<Object*>*': 'FutureOr<Object*>',
+  'FutureOr<FutureOr<Object?>>': 'FutureOr<FutureOr<Object?>>',
   '(List<Object>, {required List<Object> a, List<Object> b}) -> List<Object>':
       '(List<Object>, {required List<Object> a, List<Object> b})'
           ' -> List<Object>',
diff --git a/runtime/vm/compiler/recognized_methods_list.h b/runtime/vm/compiler/recognized_methods_list.h
index 6c22c21..fa9e3e8 100644
--- a/runtime/vm/compiler/recognized_methods_list.h
+++ b/runtime/vm/compiler/recognized_methods_list.h
@@ -199,7 +199,7 @@
   V(::, reachabilityFence, ReachabilityFence, 0x619235c1)                      \
   V(_Utf8Decoder, _scan, Utf8DecoderScan, 0x4983e111)                          \
   V(_Future, timeout, FutureTimeout, 0xc83eaf79)                               \
-  V(Future, wait, FutureWait, 0x99cfb096)                                      \
+  V(Future, wait, FutureWait, 0xc71e731d)                                      \
   V(_RootZone, runUnary, RootZoneRunUnary, 0x966a802c)                         \
   V(_FutureListener, handleValue, FutureListenerHandleValue, 0x165b47c4)       \
 
diff --git a/sdk/lib/_internal/vm/lib/ffi_dynamic_library_patch.dart b/sdk/lib/_internal/vm/lib/ffi_dynamic_library_patch.dart
index 303c5a4..655006c 100644
--- a/sdk/lib/_internal/vm/lib/ffi_dynamic_library_patch.dart
+++ b/sdk/lib/_internal/vm/lib/ffi_dynamic_library_patch.dart
@@ -8,7 +8,7 @@
 import 'dart:typed_data';
 import 'dart:isolate';
 
-DynamicLibrary _open(String name) native "Ffi_dl_open";
+DynamicLibrary _open(String path) native "Ffi_dl_open";
 DynamicLibrary _processLibrary() native "Ffi_dl_processLibrary";
 DynamicLibrary _executableLibrary() native "Ffi_dl_executableLibrary";
 
@@ -16,8 +16,8 @@
 @pragma("vm:entry-point")
 class DynamicLibrary {
   @patch
-  factory DynamicLibrary.open(String name) {
-    return _open(name);
+  factory DynamicLibrary.open(String path) {
+    return _open(path);
   }
 
   @patch
diff --git a/sdk/lib/ffi/dynamic_library.dart b/sdk/lib/ffi/dynamic_library.dart
index bcfa586..16e1b0f 100644
--- a/sdk/lib/ffi/dynamic_library.dart
+++ b/sdk/lib/ffi/dynamic_library.dart
@@ -4,47 +4,77 @@
 
 part of dart.ffi;
 
-/// Represents a dynamically loaded C library.
+/// A dynamically loaded native library.
+///
+/// A dynamically loaded library is a mapping from symbols to memory addresses.
+/// These memory addresses can be accessed through [lookup].
 class DynamicLibrary {
   /// Creates a dynamic library holding all global symbols.
   ///
-  /// Any symbol in a library currently loaded with global visibility (including
-  /// the executable itself) may be resolved in this library.
+  /// Any symbol in a library currently loaded with global visibility
+  /// (including the executable itself) may be resolved through this library.
   ///
-  /// This feature is not available on Windows, instead an exception is thrown.
+  /// This feature is not available on Windows.
   external factory DynamicLibrary.process();
 
-  /// Creates a dynamic library representing the running executable.
+  /// Creates a dynamic library containing all the symbols of the running
+  /// executable.
   external factory DynamicLibrary.executable();
 
-  /// Loads a dynamic library file with local visibility.
+  /// Loads a library file and provides access to its symbols.
   ///
-  /// Throws an [ArgumentError] if loading the dynamic library fails.
+  /// The [path] must refer to a native library file which can be successfully
+  /// loaded.
   ///
-  /// Calling this function multiple times, even in different isolates, returns
-  /// objects which are equal but not identical. The underlying library is only
-  /// loaded once into the DartVM by the OS.
-  external factory DynamicLibrary.open(String name);
+  /// Calling this function multiple times with the same [path], even across
+  /// different isolates, only loads the library into the DartVM process once.
+  /// Multiple loads of the same library file produces [DynamicLibrary] objects
+  /// which are equal (`==`), but not [identical].
+  external factory DynamicLibrary.open(String path);
 
   /// Looks up a symbol in the [DynamicLibrary] and returns its address in
-  /// memory. Equivalent of dlsym.
+  /// memory.
   ///
-  /// Throws an [ArgumentError] if it fails to lookup the symbol.
+  /// Similar to the functionality of the
+  /// [dlsym(3)](https://man7.org/linux/man-pages/man3/dlsym.3.html) system
+  /// call.
+  ///
+  /// The symbol must be provided by the dynamic library.
   external Pointer<T> lookup<T extends NativeType>(String symbolName);
 
   /// Dynamic libraries are equal if they load the same library.
   external bool operator ==(Object other);
 
-  /// The hash code for a DynamicLibrary only depends on the loaded library
+  /// The hash code for a [DynamicLibrary] only depends on the loaded library.
   external int get hashCode;
 
-  /// The handle to the dynamic library.
+  /// The opaque handle to the dynamic library.
+  ///
+  /// Similar to the return value of
+  /// [dlopen(3)](https://man7.org/linux/man-pages/man3/dlopen.3.html).
+  /// Can be used as arguments to other functions in the `dlopen` API
+  /// through FFI calls.
   external Pointer<Void> get handle;
 }
 
-/// Methods which cannot be invoked dynamically.
+/// Method which must not be invoked dynamically.
 extension DynamicLibraryExtension on DynamicLibrary {
-  /// Helper that combines lookup and cast to a Dart function.
+  /// Looks up a native function and returns it as a Dart function.
+  ///
+  /// [T] is the C function signature, and [F] is the Dart function signature.
+  /// For example:
+  ///
+  /// ```c
+  /// int32_t add(int32_t a, int32_t b) {
+  ///   return a + b;
+  /// }
+  /// ```
+  ///
+  /// ```dart
+  /// DynamicLibrary dylib;
+  /// final add = dylib.lookupFunction<Int32 Function(Int32, Int32),
+  ///                                  int Function(int, int)>('add');
+  /// ```
   external F lookupFunction<T extends Function, F extends Function>(
       String symbolName);
 }
diff --git a/tools/VERSION b/tools/VERSION
index 52a4a09..73e776b 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 13
 PATCH 0
-PRERELEASE 178
+PRERELEASE 179
 PRERELEASE_PATCH 0
\ No newline at end of file