Version 2.10.0-29.0.dev

Merge commit 'a904d72a02c10d9c52ac0868a8ec5c79993ef9dd' into 'dev'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4aa79ce..2ac349f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -38,6 +38,14 @@
 * Updated `unnecessary_statements` to skip `as` expressions.
 * Fixed `prefer_relative_imports` to work with path dependencies.
 
+#### Pub
+
+* `pub run` and `pub global run` accepts a `--(no-)-sound-null-safety` flag,
+  that is passed to the VM.
+* Fix: Avoid multiple recompilation of binaries in global packages.
+* Fix: Avoid exponential behaviour of error reporting from the solver.
+* Fix: Refresh binstubs after recompile in global run.
+
 ## 2.9.1 - 2020-08-12
 
 This is a patch release that fixes unhandled exceptions in some Flutter
@@ -163,8 +171,6 @@
 ### Pub
 * `pub run` and `pub global run` accepts a `--enable-experiment` flag enabling
   experiments in the Dart VM (and language).
-* `pub run` and `pub global run` accepts a `--(no-)-sound-null-safety flag, that
-  is passed to the VM.
 * Warn when publishing the first null-safe version of a package.
 * `pub outdated`:
   * If the current version of a dependency is a prerelease
@@ -184,9 +190,6 @@
 * Fix git folder names in cache, allowing for ssh-style git
   dependencies.
 * Fix: Avoid precompilation of dependencies of global packages.
-* Fix: Avoid multiple recompilation of binaries in global packages.
-* Fix: Avoid exponential behaviour of error reporting from the solver.
-* Fix: Refresh binstubs after recompile in global run.
 
 ## 2.8.4 - 2020-06-04
 
diff --git a/DEPS b/DEPS
index 984e608..6edb3b0 100644
--- a/DEPS
+++ b/DEPS
@@ -44,11 +44,11 @@
   # co19 is a cipd package. Use update.sh in tests/co19[_2] to update these
   # hashes. It requires access to the dart-build-access group, which EngProd
   # has.
-  "co19_rev": "74eec903ea06fa09dc8799b0552d55b581a82996",
+  "co19_rev": "12eb7bb3dd199c817babce7eb65266b90eb8deca",
   "co19_2_rev": "e48b3090826cf40b8037648f19d211e8eab1b4b6",
 
   # The internal benchmarks to use. See go/dart-benchmarks-internal
-  "benchmarks_internal_rev": "760986cf29594acf424ee6e8af23a4322825935a",
+  "benchmarks_internal_rev": "01b76c69ca61d3184d4896d230c5bfd439b84d27",
   "checkout_benchmarks_internal": False,
 
   # As Flutter does, we use Fuchsia's GN and Clang toolchain. These revision
diff --git a/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart b/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
index 82c40dc..8c4699a 100644
--- a/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
@@ -363,11 +363,12 @@
 
   /// Call this method just after visiting a binary `==` or `!=` expression.
   void equalityOp_end(Expression wholeExpression, Expression rightOperand,
+      Type rightOperandType,
       {bool notEqual = false});
 
   /// Call this method just after visiting the left hand side of a binary `==`
   /// or `!=` expression.
-  void equalityOp_rightBegin(Expression leftOperand);
+  void equalityOp_rightBegin(Expression leftOperand, Type leftOperandType);
 
   /// This method should be called at the conclusion of flow analysis for a top
   /// level function or method.  Performs assertion checks.
@@ -811,17 +812,20 @@
 
   @override
   void equalityOp_end(Expression wholeExpression, Expression rightOperand,
+      Type rightOperandType,
       {bool notEqual = false}) {
     _wrap(
-        'equalityOp_end($wholeExpression, $rightOperand, notEqual: $notEqual)',
-        () => _wrapped.equalityOp_end(wholeExpression, rightOperand,
+        'equalityOp_end($wholeExpression, $rightOperand, $rightOperandType, '
+        'notEqual: $notEqual)',
+        () => _wrapped.equalityOp_end(
+            wholeExpression, rightOperand, rightOperandType,
             notEqual: notEqual));
   }
 
   @override
-  void equalityOp_rightBegin(Expression leftOperand) {
-    _wrap('equalityOp_rightBegin($leftOperand)',
-        () => _wrapped.equalityOp_rightBegin(leftOperand));
+  void equalityOp_rightBegin(Expression leftOperand, Type leftOperandType) {
+    _wrap('equalityOp_rightBegin($leftOperand, $leftOperandType)',
+        () => _wrapped.equalityOp_rightBegin(leftOperand, leftOperandType));
   }
 
   @override
@@ -1651,8 +1655,26 @@
   }
 }
 
+/// Enum representing the different classifications of types that can be
+/// returned by [TypeOperations.classifyType].
+enum TypeClassification {
+  /// The type is `Null` or an equivalent type (e.g. `Never?`)
+  nullOrEquivalent,
+
+  /// The type is a potentially nullable type, but not equivalent to `Null`
+  /// (e.g. `int?`, or a type variable whose bound is potentially nullable)
+  potentiallyNullable,
+
+  /// The type is a non-nullable type.
+  nonNullable,
+}
+
 /// Operations on types, abstracted from concrete type interfaces.
 abstract class TypeOperations<Variable, Type> {
+  /// Classifies the given type into one of the three categories defined by
+  /// the [TypeClassification] enum.
+  TypeClassification classifyType(Type type);
+
   /// Returns the "remainder" of [from] when [what] has been removed from
   /// consideration by an instance check.
   Type factor(Type from, Type what);
@@ -2277,6 +2299,21 @@
       'thenInfo: $_thenInfo)';
 }
 
+/// [_FlowContext] representing an equality comparison using `==` or `!=`.
+class _EqualityOpContext<Variable, Type> extends _BranchContext {
+  /// The type of the expression on the LHS of `==` or `!=`.
+  final Type _leftOperandType;
+
+  _EqualityOpContext(
+      ExpressionInfo<Variable, Type> conditionInfo, this._leftOperandType)
+      : super(conditionInfo);
+
+  @override
+  String toString() =>
+      '_EqualityOpContext(conditionInfo: $_conditionInfo, lhsType: '
+      '$_leftOperandType)';
+}
+
 class _FlowAnalysisImpl<Node, Statement extends Node, Expression, Variable,
     Type> implements FlowAnalysis<Node, Statement, Expression, Variable, Type> {
   /// The [TypeOperations], used to access types, and check subtyping.
@@ -2420,31 +2457,49 @@
 
   @override
   void equalityOp_end(Expression wholeExpression, Expression rightOperand,
+      Type rightOperandType,
       {bool notEqual = false}) {
-    _BranchContext<Variable, Type> context =
-        _stack.removeLast() as _BranchContext<Variable, Type>;
+    _EqualityOpContext<Variable, Type> context =
+        _stack.removeLast() as _EqualityOpContext<Variable, Type>;
     ExpressionInfo<Variable, Type> lhsInfo = context._conditionInfo;
+    Type leftOperandType = context._leftOperandType;
     ExpressionInfo<Variable, Type> rhsInfo = _getExpressionInfo(rightOperand);
-    Variable variable;
-    if (lhsInfo is _NullInfo<Variable, Type> &&
+    ExpressionInfo<Variable, Type> equalityInfo;
+    TypeClassification leftOperandTypeClassification =
+        typeOperations.classifyType(leftOperandType);
+    TypeClassification rightOperandTypeClassification =
+        typeOperations.classifyType(rightOperandType);
+    if (leftOperandTypeClassification == TypeClassification.nullOrEquivalent &&
+        rightOperandTypeClassification == TypeClassification.nullOrEquivalent) {
+      return booleanLiteral(wholeExpression, !notEqual);
+    } else if ((leftOperandTypeClassification ==
+                TypeClassification.nullOrEquivalent &&
+            rightOperandTypeClassification == TypeClassification.nonNullable) ||
+        (rightOperandTypeClassification ==
+                TypeClassification.nullOrEquivalent &&
+            leftOperandTypeClassification == TypeClassification.nonNullable)) {
+      return booleanLiteral(wholeExpression, notEqual);
+    } else if (lhsInfo is _NullInfo<Variable, Type> &&
         rhsInfo is _VariableReadInfo<Variable, Type>) {
-      variable = rhsInfo._variable;
+      assert(
+          leftOperandTypeClassification == TypeClassification.nullOrEquivalent);
+      equalityInfo =
+          _current.tryMarkNonNullable(typeOperations, rhsInfo._variable);
     } else if (rhsInfo is _NullInfo<Variable, Type> &&
         lhsInfo is _VariableReadInfo<Variable, Type>) {
-      variable = lhsInfo._variable;
+      equalityInfo =
+          _current.tryMarkNonNullable(typeOperations, lhsInfo._variable);
     } else {
       return;
     }
-    ExpressionInfo<Variable, Type> expressionInfo =
-        _current.tryMarkNonNullable(typeOperations, variable);
     _storeExpressionInfo(wholeExpression,
-        notEqual ? expressionInfo : ExpressionInfo.invert(expressionInfo));
+        notEqual ? equalityInfo : ExpressionInfo.invert(equalityInfo));
   }
 
   @override
-  void equalityOp_rightBegin(Expression leftOperand) {
-    _stack.add(
-        new _BranchContext<Variable, Type>(_getExpressionInfo(leftOperand)));
+  void equalityOp_rightBegin(Expression leftOperand, Type leftOperandType) {
+    _stack.add(new _EqualityOpContext<Variable, Type>(
+        _getExpressionInfo(leftOperand), leftOperandType));
   }
 
   @override
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/definite_unassignment/data/binary_expression.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/definite_unassignment/data/binary_expression.dart
index f666e45..ec3bf0e 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/definite_unassignment/data/binary_expression.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/definite_unassignment/data/binary_expression.dart
@@ -8,7 +8,7 @@
   v;
 }
 
-ifNull_right(int a) {
+ifNull_right(int? a) {
   late int v;
   a ?? (v = 0);
   v;
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
index a3c666f..09e6023 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart
@@ -33,7 +33,7 @@
       var x = h.addVar('x', 'int?');
       h.run((flow) {
         flow.assert_begin();
-        var expr = h.eqNull(x)();
+        var expr = h.eqNull(x, _Type('int?'))();
         flow.assert_afterCondition(expr);
         expect(flow.promotedType(x).type, 'int');
         flow.assert_end();
@@ -55,7 +55,8 @@
         flow.assert_begin();
         flow.write(x, _Type('int?'));
         flow.write(z, _Type('int?'));
-        var expr = h.and(h.notNull(x), h.notNull(y))();
+        var expr =
+            h.and(h.notNull(x, _Type('int?')), h.notNull(y, _Type('int?')))();
         flow.assert_afterCondition(expr);
         flow.assert_end();
         // x should be promoted because it was promoted before the assert, and
@@ -75,7 +76,7 @@
       var x = h.addVar('x', 'int?');
       h.run((flow) {
         h.declare(x, initialized: true);
-        flow.conditional_thenBegin(h.notNull(x)());
+        flow.conditional_thenBegin(h.notNull(x, _Type('int?'))());
         expect(flow.promotedType(x).type, 'int');
         flow.conditional_elseBegin(_Expression());
         expect(flow.promotedType(x), isNull);
@@ -89,7 +90,7 @@
       var x = h.addVar('x', 'int?');
       h.run((flow) {
         h.declare(x, initialized: true);
-        flow.conditional_thenBegin(h.eqNull(x)());
+        flow.conditional_thenBegin(h.eqNull(x, _Type('int?'))());
         expect(flow.promotedType(x), isNull);
         flow.conditional_elseBegin(_Expression());
         expect(flow.promotedType(x).type, 'int');
@@ -134,8 +135,12 @@
         h.declare(y, initialized: true);
         h.declare(z, initialized: true);
         h.if_(
-            h.conditional(h.expr, h.and(h.notNull(x), h.notNull(y)),
-                h.and(h.notNull(x), h.notNull(z))), () {
+            h.conditional(
+                h.expr,
+                h.and(h.notNull(x, _Type('int?')), h.notNull(y, _Type('int?'))),
+                h.and(
+                    h.notNull(x, _Type('int?')), h.notNull(z, _Type('int?')))),
+            () {
           expect(flow.promotedType(x).type, 'int');
           expect(flow.promotedType(y), isNull);
           expect(flow.promotedType(z), isNull);
@@ -157,8 +162,10 @@
         h.declare(y, initialized: true);
         h.declare(z, initialized: true);
         h.ifElse(
-            h.conditional(h.expr, h.or(h.eqNull(x), h.eqNull(y)),
-                h.or(h.eqNull(x), h.eqNull(z))),
+            h.conditional(
+                h.expr,
+                h.or(h.eqNull(x, _Type('int?')), h.eqNull(y, _Type('int?'))),
+                h.or(h.eqNull(x, _Type('int?')), h.eqNull(z, _Type('int?')))),
             () {}, () {
           expect(flow.promotedType(x).type, 'int');
           expect(flow.promotedType(y), isNull);
@@ -174,11 +181,11 @@
         h.declare(x, initialized: true);
         var varExpr = _Expression();
         flow.variableRead(varExpr, x);
-        flow.equalityOp_rightBegin(varExpr);
+        flow.equalityOp_rightBegin(varExpr, _Type('int?'));
         var nullExpr = _Expression();
         flow.nullLiteral(nullExpr);
         var expr = _Expression();
-        flow.equalityOp_end(expr, nullExpr, notEqual: true);
+        flow.equalityOp_end(expr, nullExpr, _Type('Null'), notEqual: true);
         flow.ifStatement_thenBegin(expr);
         expect(flow.promotedType(x).type, 'int');
         flow.ifStatement_elseBegin();
@@ -187,6 +194,25 @@
       });
     });
 
+    test('equalityOp(x != <null expr>) does not promote', () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        var varExpr = _Expression();
+        flow.variableRead(varExpr, x);
+        flow.equalityOp_rightBegin(varExpr, _Type('int?'));
+        var nullExpr = _Expression();
+        var expr = _Expression();
+        flow.equalityOp_end(expr, nullExpr, _Type('Null'), notEqual: true);
+        flow.ifStatement_thenBegin(expr);
+        expect(flow.promotedType(x), isNull);
+        flow.ifStatement_elseBegin();
+        expect(flow.promotedType(x), isNull);
+        flow.ifStatement_end(true);
+      });
+    });
+
     test('equalityOp(x == null) promotes false branch', () {
       var h = _Harness();
       var x = h.addVar('x', 'int?');
@@ -194,11 +220,11 @@
         h.declare(x, initialized: true);
         var varExpr = _Expression();
         flow.variableRead(varExpr, x);
-        flow.equalityOp_rightBegin(varExpr);
+        flow.equalityOp_rightBegin(varExpr, _Type('int?'));
         var nullExpr = _Expression();
         flow.nullLiteral(nullExpr);
         var expr = _Expression();
-        flow.equalityOp_end(expr, nullExpr, notEqual: false);
+        flow.equalityOp_end(expr, nullExpr, _Type('Null'), notEqual: false);
         flow.ifStatement_thenBegin(expr);
         expect(flow.promotedType(x), isNull);
         flow.ifStatement_elseBegin();
@@ -214,11 +240,11 @@
         h.declare(x, initialized: true);
         var nullExpr = _Expression();
         flow.nullLiteral(nullExpr);
-        flow.equalityOp_rightBegin(nullExpr);
+        flow.equalityOp_rightBegin(nullExpr, _Type('Null'));
         var varExpr = _Expression();
         flow.variableRead(varExpr, x);
         var expr = _Expression();
-        flow.equalityOp_end(expr, varExpr, notEqual: true);
+        flow.equalityOp_end(expr, varExpr, _Type('int?'), notEqual: true);
         flow.ifStatement_thenBegin(expr);
         expect(flow.promotedType(x).type, 'int');
         flow.ifStatement_elseBegin();
@@ -227,6 +253,25 @@
       });
     });
 
+    test('equalityOp(<null expr> != x) does not promote', () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        var nullExpr = _Expression();
+        flow.equalityOp_rightBegin(nullExpr, _Type('Null'));
+        var varExpr = _Expression();
+        flow.variableRead(varExpr, x);
+        var expr = _Expression();
+        flow.equalityOp_end(expr, varExpr, _Type('int?'), notEqual: true);
+        flow.ifStatement_thenBegin(expr);
+        expect(flow.promotedType(x), isNull);
+        flow.ifStatement_elseBegin();
+        expect(flow.promotedType(x), isNull);
+        flow.ifStatement_end(true);
+      });
+    });
+
     test('equalityOp(null == x) promotes false branch', () {
       var h = _Harness();
       var x = h.addVar('x', 'int?');
@@ -234,11 +279,11 @@
         h.declare(x, initialized: true);
         var nullExpr = _Expression();
         flow.nullLiteral(nullExpr);
-        flow.equalityOp_rightBegin(nullExpr);
+        flow.equalityOp_rightBegin(nullExpr, _Type('Null'));
         var varExpr = _Expression();
         flow.variableRead(varExpr, x);
         var expr = _Expression();
-        flow.equalityOp_end(expr, varExpr, notEqual: false);
+        flow.equalityOp_end(expr, varExpr, _Type('int?'), notEqual: false);
         flow.ifStatement_thenBegin(expr);
         expect(flow.promotedType(x), isNull);
         flow.ifStatement_elseBegin();
@@ -247,6 +292,102 @@
       });
     });
 
+    test('equalityOp(null == null) equivalent to true', () {
+      var h = _Harness();
+      h.run((flow) {
+        var null1 = _Expression();
+        flow.equalityOp_rightBegin(null1, _Type('Null'));
+        var null2 = _Expression();
+        var expr = _Expression();
+        flow.equalityOp_end(expr, null2, _Type('Null'));
+        flow.ifStatement_thenBegin(expr);
+        expect(flow.isReachable, true);
+        flow.ifStatement_elseBegin();
+        expect(flow.isReachable, false);
+        flow.ifStatement_end(true);
+      });
+    });
+
+    test('equalityOp(null != null) equivalent to false', () {
+      var h = _Harness();
+      h.run((flow) {
+        var null1 = _Expression();
+        flow.equalityOp_rightBegin(null1, _Type('Null'));
+        var null2 = _Expression();
+        var expr = _Expression();
+        flow.equalityOp_end(expr, null2, _Type('Null'), notEqual: true);
+        flow.ifStatement_thenBegin(expr);
+        expect(flow.isReachable, false);
+        flow.ifStatement_elseBegin();
+        expect(flow.isReachable, true);
+        flow.ifStatement_end(true);
+      });
+    });
+
+    test('equalityOp(null == non-null) equivalent to false', () {
+      var h = _Harness();
+      h.run((flow) {
+        var null1 = _Expression();
+        flow.equalityOp_rightBegin(null1, _Type('Null'));
+        var null2 = _Expression();
+        var expr = _Expression();
+        flow.equalityOp_end(expr, null2, _Type('int'));
+        flow.ifStatement_thenBegin(expr);
+        expect(flow.isReachable, false);
+        flow.ifStatement_elseBegin();
+        expect(flow.isReachable, true);
+        flow.ifStatement_end(true);
+      });
+    });
+
+    test('equalityOp(null != non-null) equivalent to true', () {
+      var h = _Harness();
+      h.run((flow) {
+        var null1 = _Expression();
+        flow.equalityOp_rightBegin(null1, _Type('Null'));
+        var null2 = _Expression();
+        var expr = _Expression();
+        flow.equalityOp_end(expr, null2, _Type('int'), notEqual: true);
+        flow.ifStatement_thenBegin(expr);
+        expect(flow.isReachable, true);
+        flow.ifStatement_elseBegin();
+        expect(flow.isReachable, false);
+        flow.ifStatement_end(true);
+      });
+    });
+
+    test('equalityOp(non-null == null) equivalent to false', () {
+      var h = _Harness();
+      h.run((flow) {
+        var null1 = _Expression();
+        flow.equalityOp_rightBegin(null1, _Type('int'));
+        var null2 = _Expression();
+        var expr = _Expression();
+        flow.equalityOp_end(expr, null2, _Type('Null'));
+        flow.ifStatement_thenBegin(expr);
+        expect(flow.isReachable, false);
+        flow.ifStatement_elseBegin();
+        expect(flow.isReachable, true);
+        flow.ifStatement_end(true);
+      });
+    });
+
+    test('equalityOp(non-null != null) equivalent to true', () {
+      var h = _Harness();
+      h.run((flow) {
+        var null1 = _Expression();
+        flow.equalityOp_rightBegin(null1, _Type('int'));
+        var null2 = _Expression();
+        var expr = _Expression();
+        flow.equalityOp_end(expr, null2, _Type('Null'), notEqual: true);
+        flow.ifStatement_thenBegin(expr);
+        expect(flow.isReachable, true);
+        flow.ifStatement_elseBegin();
+        expect(flow.isReachable, false);
+        flow.ifStatement_end(true);
+      });
+    });
+
     test('conditionEqNull() does not promote write-captured vars', () {
       var h = _Harness();
       var x = h.addVar('x', 'int?');
@@ -255,13 +396,13 @@
           (vars) => vars.function(functionNode, () => vars.write(x)));
       h.run((flow) {
         h.declare(x, initialized: true);
-        h.if_(h.notNull(x), () {
+        h.if_(h.notNull(x, _Type('int?')), () {
           expect(flow.promotedType(x).type, 'int');
         });
         h.function(functionNode, () {
           flow.write(x, _Type('int?'));
         });
-        h.if_(h.notNull(x), () {
+        h.if_(h.notNull(x, _Type('int?')), () {
           expect(flow.promotedType(x), isNull);
         });
       });
@@ -314,7 +455,7 @@
       h.run((flow) {
         h.declare(x, initialized: true);
         flow.doStatement_bodyBegin(stmt);
-        h.if_(h.notNull(x), () {
+        h.if_(h.notNull(x, _Type('int?')), () {
           flow.handleContinue(stmt);
         });
         flow.handleExit();
@@ -337,7 +478,7 @@
         flow.doStatement_bodyBegin(stmt);
         flow.doStatement_conditionBegin();
         expect(flow.promotedType(x), isNull);
-        flow.doStatement_end(h.eqNull(x)());
+        flow.doStatement_end(h.eqNull(x, _Type('int?'))());
         expect(flow.promotedType(x).type, 'int');
       });
     });
@@ -432,7 +573,7 @@
       h.run((flow) {
         h.declare(x, initialized: true);
         flow.for_conditionBegin(stmt);
-        flow.for_bodyBegin(stmt, h.notNull(x)());
+        flow.for_bodyBegin(stmt, h.notNull(x, _Type('int?'))());
         expect(flow.promotedType(x).type, 'int');
         flow.for_updaterBegin();
         flow.for_end();
@@ -448,7 +589,7 @@
       h.run((flow) {
         h.declare(x, initialized: true);
         flow.for_conditionBegin(node);
-        flow.for_bodyBegin(null, h.notNull(x)());
+        flow.for_bodyBegin(null, h.notNull(x, _Type('int?'))());
         flow.for_updaterBegin();
         flow.for_end();
       });
@@ -500,7 +641,8 @@
         h.declare(y, initialized: true);
         h.declare(z, initialized: true);
         flow.for_conditionBegin(stmt);
-        flow.for_bodyBegin(stmt, h.or(h.eqNull(x), h.eqNull(z))());
+        flow.for_bodyBegin(stmt,
+            h.or(h.eqNull(x, _Type('int?')), h.eqNull(z, _Type('int?')))());
         h.if_(h.expr, () {
           h.promote(x, 'int');
           h.promote(y, 'int');
@@ -782,7 +924,7 @@
       var x = h.addVar('x', 'int?');
       h.run((flow) {
         h.declare(x, initialized: true);
-        flow.ifStatement_thenBegin(h.eqNull(x)());
+        flow.ifStatement_thenBegin(h.eqNull(x, _Type('int?'))());
         flow.handleExit();
         flow.ifStatement_end(false);
         expect(flow.promotedType(x).type, 'int');
@@ -904,7 +1046,8 @@
       var x = h.addVar('x', 'int?');
       h.run((flow) {
         h.declare(x, initialized: true);
-        flow.logicalBinaryOp_rightBegin(h.notNull(x)(), isAnd: true);
+        flow.logicalBinaryOp_rightBegin(h.notNull(x, _Type('int?'))(),
+            isAnd: true);
         expect(flow.promotedType(x).type, 'int');
         flow.logicalBinaryOp_end(_Expression(), _Expression(), isAnd: true);
       });
@@ -917,7 +1060,8 @@
         h.declare(x, initialized: true);
         flow.logicalBinaryOp_rightBegin(_Expression(), isAnd: true);
         var wholeExpr = _Expression();
-        flow.logicalBinaryOp_end(wholeExpr, h.notNull(x)(), isAnd: true);
+        flow.logicalBinaryOp_end(wholeExpr, h.notNull(x, _Type('int?'))(),
+            isAnd: true);
         flow.ifStatement_thenBegin(wholeExpr);
         expect(flow.promotedType(x).type, 'int');
         flow.ifStatement_end(false);
@@ -932,7 +1076,8 @@
         h.declare(x, initialized: true);
         flow.logicalBinaryOp_rightBegin(_Expression(), isAnd: false);
         var wholeExpr = _Expression();
-        flow.logicalBinaryOp_end(wholeExpr, h.eqNull(x)(), isAnd: false);
+        flow.logicalBinaryOp_end(wholeExpr, h.eqNull(x, _Type('int?'))(),
+            isAnd: false);
         flow.ifStatement_thenBegin(wholeExpr);
         flow.ifStatement_elseBegin();
         expect(flow.promotedType(x).type, 'int');
@@ -945,7 +1090,8 @@
       var x = h.addVar('x', 'int?');
       h.run((flow) {
         h.declare(x, initialized: true);
-        flow.logicalBinaryOp_rightBegin(h.eqNull(x)(), isAnd: false);
+        flow.logicalBinaryOp_rightBegin(h.eqNull(x, _Type('int?'))(),
+            isAnd: false);
         expect(flow.promotedType(x).type, 'int');
         flow.logicalBinaryOp_end(_Expression(), _Expression(), isAnd: false);
       });
@@ -961,7 +1107,8 @@
       h.run((flow) {
         h.declare(x, initialized: true);
         h.declare(y, initialized: true);
-        h.if_(h.and(h.notNull(x), h.notNull(y)), () {
+        h.if_(h.and(h.notNull(x, _Type('int?')), h.notNull(y, _Type('int?'))),
+            () {
           expect(flow.promotedType(x).type, 'int');
           expect(flow.promotedType(y).type, 'int');
         });
@@ -978,7 +1125,9 @@
       h.run((flow) {
         h.declare(x, initialized: true);
         h.declare(y, initialized: true);
-        h.ifElse(h.or(h.eqNull(x), h.eqNull(y)), () {}, () {
+        h.ifElse(
+            h.or(h.eqNull(x, _Type('int?')), h.eqNull(y, _Type('int?'))), () {},
+            () {
           expect(flow.promotedType(x).type, 'int');
           expect(flow.promotedType(y).type, 'int');
         });
@@ -1046,8 +1195,11 @@
       var x = h.addVar('x', 'int?');
       h.run((flow) {
         h.if_(
-            h.parenthesized(h.notEqual(h.parenthesized(h.variableRead(x)),
-                h.parenthesized(h.nullLiteral))), () {
+            h.parenthesized(h.notEqual(
+                h.parenthesized(h.variableRead(x)),
+                _Type('int?'),
+                h.parenthesized(h.nullLiteral),
+                _Type('Null'))), () {
           expect(flow.promotedType(x).type, 'int');
         });
       });
@@ -1625,7 +1777,7 @@
       h.run((flow) {
         h.declare(x, initialized: true);
         flow.whileStatement_conditionBegin(stmt);
-        flow.whileStatement_bodyBegin(stmt, h.notNull(x)());
+        flow.whileStatement_bodyBegin(stmt, h.notNull(x, _Type('int?'))());
         expect(flow.promotedType(x).type, 'int');
         flow.whileStatement_end();
       });
@@ -1646,7 +1798,8 @@
         h.declare(y, initialized: true);
         h.declare(z, initialized: true);
         flow.whileStatement_conditionBegin(stmt);
-        flow.whileStatement_bodyBegin(stmt, h.or(h.eqNull(x), h.eqNull(z))());
+        flow.whileStatement_bodyBegin(stmt,
+            h.or(h.eqNull(x, _Type('int?')), h.eqNull(z, _Type('int?')))());
         h.if_(h.expr, () {
           h.promote(x, 'int');
           h.promote(y, 'int');
@@ -3133,6 +3286,7 @@
     'int <: int?': true,
     'int <: Iterable': false,
     'int <: List': false,
+    'int <: Null': false,
     'int <: num': true,
     'int <: num?': true,
     'int <: num*': true,
@@ -3141,10 +3295,13 @@
     'int <: Object?': true,
     'int <: String': false,
     'int? <: int': false,
+    'int? <: Null': false,
     'int? <: num': false,
     'int? <: num?': true,
     'int? <: Object': false,
     'int? <: Object?': true,
+    'Null <: int': false,
+    'Null <: Object': false,
     'num <: int': false,
     'num <: Iterable': false,
     'num <: List': false,
@@ -3175,6 +3332,7 @@
     'Never? <: int?': true,
     'Never? <: num?': true,
     'Never? <: Object?': true,
+    'Null <: int?': true,
     'Object <: int': false,
     'Object <: int?': false,
     'Object <: List': false,
@@ -3204,6 +3362,7 @@
     'int? - int': _Type('Never?'),
     'int? - int?': _Type('Never'),
     'int? - String': _Type('int?'),
+    'Null - int': _Type('Null'),
     'num - int': _Type('num'),
     'num? - num': _Type('Never?'),
     'num? - int': _Type('num?'),
@@ -3270,6 +3429,17 @@
     callback(_AssignedVariablesHarness(_assignedVariables));
   }
 
+  @override
+  TypeClassification classifyType(_Type type) {
+    if (isSubtypeOf(type, _Type('Object'))) {
+      return TypeClassification.nonNullable;
+    } else if (isSubtypeOf(type, _Type('Null'))) {
+      return TypeClassification.nullOrEquivalent;
+    } else {
+      return TypeClassification.potentiallyNullable;
+    }
+  }
+
   /// Given three [LazyExpression]s, produces a new [LazyExpression]
   /// representing the result of combining them with `?` and `:`.
   LazyExpression conditional(
@@ -3293,15 +3463,15 @@
 
   /// Creates a [LazyExpression] representing an `== null` check performed on
   /// [variable].
-  LazyExpression eqNull(_Var variable) {
+  LazyExpression eqNull(_Var variable, _Type type) {
     return () {
       var varExpr = _Expression();
       _flow.variableRead(varExpr, variable);
-      _flow.equalityOp_rightBegin(varExpr);
+      _flow.equalityOp_rightBegin(varExpr, type);
       var nullExpr = _Expression();
       _flow.nullLiteral(nullExpr);
       var expr = _Expression();
-      _flow.equalityOp_end(expr, nullExpr, notEqual: false);
+      _flow.equalityOp_end(expr, nullExpr, _Type('Null'), notEqual: false);
       return expr;
     };
   }
@@ -3391,26 +3561,27 @@
 
   /// Creates a [LazyExpression] representing an equality check between two
   /// other expressions.
-  LazyExpression notEqual(LazyExpression lhs, LazyExpression rhs) {
+  LazyExpression notEqual(
+      LazyExpression lhs, _Type lhsType, LazyExpression rhs, _Type rhsType) {
     return () {
       var expr = _Expression();
-      _flow.equalityOp_rightBegin(lhs());
-      _flow.equalityOp_end(expr, rhs(), notEqual: true);
+      _flow.equalityOp_rightBegin(lhs(), lhsType);
+      _flow.equalityOp_end(expr, rhs(), rhsType, notEqual: true);
       return expr;
     };
   }
 
   /// Creates a [LazyExpression] representing a `!= null` check performed on
   /// [variable].
-  LazyExpression notNull(_Var variable) {
+  LazyExpression notNull(_Var variable, _Type type) {
     return () {
       var varExpr = _Expression();
       _flow.variableRead(varExpr, variable);
-      _flow.equalityOp_rightBegin(varExpr);
+      _flow.equalityOp_rightBegin(varExpr, type);
       var nullExpr = _Expression();
       _flow.nullLiteral(nullExpr);
       var expr = _Expression();
-      _flow.equalityOp_end(expr, nullExpr, notEqual: true);
+      _flow.equalityOp_end(expr, nullExpr, _Type('Null'), notEqual: true);
       return expr;
     };
   }
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/nullability/data/equality_operator.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/nullability/data/equality_operator.dart
new file mode 100644
index 0000000..e020657
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/nullability/data/equality_operator.dart
@@ -0,0 +1,69 @@
+// 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.
+
+Null nullExpr = null;
+
+void var_eq_null(int? x) {
+  if (x == null) {
+    x;
+  } else {
+    /*nonNullable*/ x;
+  }
+}
+
+void var_notEq_null(int? x) {
+  if (x != null) {
+    /*nonNullable*/ x;
+  } else {
+    x;
+  }
+}
+
+void null_eq_var(int? x) {
+  if (null == x) {
+    x;
+  } else {
+    /*nonNullable*/ x;
+  }
+}
+
+void null_notEq_var(int? x) {
+  if (null != x) {
+    /*nonNullable*/ x;
+  } else {
+    x;
+  }
+}
+
+void var_eq_nullExpr(int? x) {
+  if (x == nullExpr) {
+    x;
+  } else {
+    x;
+  }
+}
+
+void var_notEq_nullExpr(int? x) {
+  if (x != nullExpr) {
+    x;
+  } else {
+    x;
+  }
+}
+
+void nullExpr_eq_var(int? x) {
+  if (nullExpr == x) {
+    x;
+  } else {
+    x;
+  }
+}
+
+void nullExpr_notEq_var(int? x) {
+  if (nullExpr != x) {
+    x;
+  } else {
+    x;
+  }
+}
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/reachability/data/equality_operator.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/reachability/data/equality_operator.dart
new file mode 100644
index 0000000..195e679
--- /dev/null
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/reachability/data/equality_operator.dart
@@ -0,0 +1,83 @@
+// 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.
+
+void nullValue(Null x) {
+  if (x == null) {
+    1;
+  } else /*unreachable*/ {
+    /*stmt: unreachable*/ 2;
+  }
+}
+
+void neverQuestionValue(Never? x) {
+  if (x == null) {
+    1;
+  } else /*unreachable*/ {
+    /*stmt: unreachable*/ 2;
+  }
+}
+
+void dynamicValue(dynamic x) {
+  if (x == null) {
+    1;
+  } else {
+    2;
+  }
+}
+
+void nullableValue(int? x) {
+  if (x == null) {
+    1;
+  } else {
+    2;
+  }
+}
+
+void nonNullableValue(int x) {
+  if (x == null) /*unreachable*/ {
+    /*stmt: unreachable*/ 1;
+  } else {
+    2;
+  }
+}
+
+void potentiallyNullableTypeVar_noBound<T>(T x) {
+  if (x == null) {
+    1;
+  } else {
+    2;
+  }
+}
+
+void potentiallyNullableTypeVar_dynamicBound<T extends dynamic>(T x) {
+  if (x == null) {
+    1;
+  } else {
+    2;
+  }
+}
+
+void potentiallyNullableTypeVar_nullableBound<T extends Object?>(T x) {
+  if (x == null) {
+    1;
+  } else {
+    2;
+  }
+}
+
+void nonNullableTypeVar<T extends Object>(T x) {
+  if (x == null) /*unreachable*/ {
+    /*stmt: unreachable*/ 1;
+  } else {
+    2;
+  }
+}
+
+void nullTypeVar<T extends Null>(T x) {
+  if (x == null) {
+    1;
+  } else /*unreachable*/ {
+    /*stmt: unreachable*/ 2;
+  }
+}
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/data/binary.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/data/binary.dart
index addc66a..b43c121 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/data/binary.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/data/binary.dart
@@ -7,7 +7,7 @@
   /*num*/ x;
 }
 
-void ifNull_rightUnPromote(Object x, Object y, Object z) {
+void ifNull_rightUnPromote(Object x, Object? y, Object z) {
   if (x is int) {
     /*int*/ x;
     y ?? (x = z);
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/data/null_check.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/data/null_check.dart
index 9dcfa11..8879f21 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/data/null_check.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/data/null_check.dart
@@ -18,9 +18,9 @@
   }
 }
 
-promotesNullType(Null x) {
+doesNotPromoteNullType(Null x) {
   if (x != null) {
-    /*Never*/ x;
+    x;
   } else {
     x;
   }
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/add_type_parameter_change.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/add_type_parameter_change.dart
index edc2312..c195e50 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/add_type_parameter_change.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/add_type_parameter_change.dart
@@ -41,8 +41,10 @@
   void apply(DartFileEditBuilder builder, DataDrivenFix fix, _Data data) {
     if (data is _TypeArgumentData) {
       _applyToTypeArguments(builder, data);
+    } else if (data is _TypeParameterData) {
+      _applyToTypeParameters(builder, data);
     } else {
-      _applyToTypeParameters(builder, data as _TypeParameterData);
+      throw StateError('Unsupported class of data: ${data.runtimeType}');
     }
   }
 
@@ -165,7 +167,7 @@
 
 /// The data returned when updating a type parameter list.
 class _TypeParameterData extends _Data {
-  /// The list of type parameters to which a new type paramete is being added,
+  /// The list of type parameters to which a new type parameter is being added,
   /// or `null` if the first type parameter is being added.
   final TypeParameterList typeParameters;
 
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/value_extractor.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/value_extractor.dart
index 704eae8..ad5243b 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/value_extractor.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/value_extractor.dart
@@ -6,14 +6,16 @@
 import 'package:analysis_server/src/services/correction/util.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 
-/// A value extractor used to extract a specified argument of an invocation.
+/// A value extractor used to extract a specified argument from an invocation.
 class ArgumentExtractor extends ValueExtractor {
-  /// The parameter that defines the argument to be extracted.
+  /// The parameter corresponding to the argument from the original invocation,
+  /// or `null` if the value of the argument can't be taken from the original
+  /// invocation.
   final ParameterReference parameter;
 
   /// Initialize a newly created extractor to extract the argument that
   /// corresponds to the given [parameter].
-  ArgumentExtractor(this.parameter);
+  ArgumentExtractor(this.parameter) : assert(parameter != null);
 
   @override
   String from(AstNode node, CorrectionUtils utils) {
@@ -32,7 +34,7 @@
   /// The code to be returned.
   final String code;
 
-  /// Initialize a newly created  extractor to return the given [code].
+  /// Initialize a newly created extractor to return the given [code].
   LiteralExtractor(this.code);
 
   @override
diff --git a/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
index 8486729..db0d9c9 100644
--- a/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
@@ -136,13 +136,13 @@
     left = node.leftOperand;
 
     var flow = _flowAnalysis?.flow;
-    flow?.equalityOp_rightBegin(left);
+    flow?.equalityOp_rightBegin(left, left.staticType);
 
     var right = node.rightOperand;
     right.accept(_resolver);
     right = node.rightOperand;
 
-    flow?.equalityOp_end(node, right, notEqual: notEqual);
+    flow?.equalityOp_end(node, right, right.staticType, notEqual: notEqual);
 
     _resolveUserDefinableElement(
       node,
diff --git a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
index 9d22406..f6fe441 100644
--- a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
@@ -351,6 +351,17 @@
   TypeSystemTypeOperations(this.typeSystem);
 
   @override
+  TypeClassification classifyType(DartType type) {
+    if (isSubtypeOf(type, typeSystem.typeProvider.objectType)) {
+      return TypeClassification.nonNullable;
+    } else if (isSubtypeOf(type, typeSystem.typeProvider.nullType)) {
+      return TypeClassification.nullOrEquivalent;
+    } else {
+      return TypeClassification.potentiallyNullable;
+    }
+  }
+
+  @override
   DartType factor(DartType from, DartType what) {
     return typeSystem.factor(from, what);
   }
diff --git a/pkg/analyzer/lib/src/error/dead_code_verifier.dart b/pkg/analyzer/lib/src/error/dead_code_verifier.dart
index ad7fa1f..24eefd2 100644
--- a/pkg/analyzer/lib/src/error/dead_code_verifier.dart
+++ b/pkg/analyzer/lib/src/error/dead_code_verifier.dart
@@ -505,33 +505,40 @@
         return;
       }
 
-      // We know that [node] is the first dead node, or contains it.
-      // So, technically the code code interval ends at the end of [node].
-      // But we trim it to the last statement for presentation purposes.
-      if (node != _firstDeadNode) {
-        if (node is FunctionDeclaration) {
-          node = (node as FunctionDeclaration).functionExpression.body;
+      var parent = _firstDeadNode.parent;
+      if (parent is Assertion && identical(_firstDeadNode, parent.message)) {
+        // Don't report "dead code" for the message part of an assert statement,
+        // because this causes nuisance warnings for redundant `!= null`
+        // asserts.
+      } else {
+        // We know that [node] is the first dead node, or contains it.
+        // So, technically the code code interval ends at the end of [node].
+        // But we trim it to the last statement for presentation purposes.
+        if (node != _firstDeadNode) {
+          if (node is FunctionDeclaration) {
+            node = (node as FunctionDeclaration).functionExpression.body;
+          }
+          if (node is FunctionExpression) {
+            node = (node as FunctionExpression).body;
+          }
+          if (node is MethodDeclaration) {
+            node = (node as MethodDeclaration).body;
+          }
+          if (node is BlockFunctionBody) {
+            node = (node as BlockFunctionBody).block;
+          }
+          if (node is Block && node.statements.isNotEmpty) {
+            node = (node as Block).statements.last;
+          }
+          if (node is SwitchMember && node.statements.isNotEmpty) {
+            node = (node as SwitchMember).statements.last;
+          }
         }
-        if (node is FunctionExpression) {
-          node = (node as FunctionExpression).body;
-        }
-        if (node is MethodDeclaration) {
-          node = (node as MethodDeclaration).body;
-        }
-        if (node is BlockFunctionBody) {
-          node = (node as BlockFunctionBody).block;
-        }
-        if (node is Block && node.statements.isNotEmpty) {
-          node = (node as Block).statements.last;
-        }
-        if (node is SwitchMember && node.statements.isNotEmpty) {
-          node = (node as SwitchMember).statements.last;
-        }
-      }
 
-      var offset = _firstDeadNode.offset;
-      var length = node.end - offset;
-      _errorReporter.reportErrorForOffset(HintCode.DEAD_CODE, offset, length);
+        var offset = _firstDeadNode.offset;
+        var length = node.end - offset;
+        _errorReporter.reportErrorForOffset(HintCode.DEAD_CODE, offset, length);
+      }
 
       _firstDeadNode = null;
     }
diff --git a/pkg/analyzer/test/src/diagnostics/dead_code_test.dart b/pkg/analyzer/test/src/diagnostics/dead_code_test.dart
index 2529fea..b261479 100644
--- a/pkg/analyzer/test/src/diagnostics/dead_code_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/dead_code_test.dart
@@ -846,6 +846,20 @@
 
 @reflectiveTest
 class DeadCodeWithNullSafetyTest extends DeadCodeTest with WithNullSafetyMixin {
+  test_assert_dead_message() async {
+    // We don't warn if an assert statement is live but its message is dead,
+    // because this results in nuisance warnings for desirable assertions (e.g.
+    // a `!= null` assertion that is redundant with strong checking but still
+    // useful with weak checking).
+    await assertErrorsInCode('''
+void f(Object waldo) {
+  assert(waldo != null, "Where's Waldo?");
+}
+''', [
+      error(HintCode.UNNECESSARY_NULL_COMPARISON_TRUE, 38, 7),
+    ]);
+  }
+
   test_flowEnd_tryStatement_body() async {
     await assertErrorsInCode(r'''
 Never foo() => throw 0;
diff --git a/pkg/front_end/lib/src/fasta/kernel/forwarding_node.dart b/pkg/front_end/lib/src/fasta/kernel/forwarding_node.dart
index ab6775c..5fa02e2 100644
--- a/pkg/front_end/lib/src/fasta/kernel/forwarding_node.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/forwarding_node.dart
@@ -418,6 +418,34 @@
             (stub as Procedure).isMemberSignature &&
             stub.memberSignatureOrigin == null),
         "No member signature origin for member signature $stub.");
+    if (stub != interfaceMember && stub is Procedure) {
+      Procedure procedure = stub;
+      if (procedure.isForwardingStub || procedure.isForwardingSemiStub) {
+        procedure.isMemberSignature = false;
+        procedure.memberSignatureOrigin = null;
+      } else {
+        procedure.forwardingStubInterfaceTarget = null;
+        procedure.forwardingStubSuperTarget = null;
+      }
+      assert(
+          !(procedure.isMemberSignature && procedure.isForwardingStub),
+          "Procedure is both member signature and forwarding stub: "
+          "$procedure.");
+      assert(
+          !(procedure.isMemberSignature && procedure.isForwardingSemiStub),
+          "Procedure is both member signature and forwarding semi stub: "
+          "$procedure.");
+      assert(
+          !(procedure.forwardingStubInterfaceTarget is Procedure &&
+              (procedure.forwardingStubInterfaceTarget as Procedure)
+                  .isMemberSignature),
+          "Forwarding stub interface target is member signature: $procedure.");
+      assert(
+          !(procedure.forwardingStubSuperTarget is Procedure &&
+              (procedure.forwardingStubSuperTarget as Procedure)
+                  .isMemberSignature),
+          "Forwarding stub super target is member signature: $procedure.");
+    }
     return stub;
   }
 
@@ -438,6 +466,8 @@
     if (superTarget is Procedure && superTarget.isForwardingStub) {
       Procedure superProcedure = superTarget;
       superTarget = superProcedure.forwardingStubSuperTarget;
+    } else {
+      superTarget = superTarget.memberSignatureOrigin ?? superTarget;
     }
     procedure.isAbstract = false;
     if (!procedure.isForwardingStub) {
@@ -528,7 +558,7 @@
     if (target is Procedure && target.isForwardingStub) {
       finalTarget = target.forwardingStubInterfaceTarget;
     } else {
-      finalTarget = target;
+      finalTarget = target.memberSignatureOrigin ?? target;
     }
     Procedure referenceFrom;
     if (classBuilder.referencesFromIndexed != null) {
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 bf4ca5e..aec4c80 100644
--- a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
@@ -3520,7 +3520,7 @@
       int fileOffset, Expression left, DartType leftType, Expression right,
       {bool isNot}) {
     assert(isNot != null);
-    inferrer.flowAnalysis.equalityOp_rightBegin(left);
+    inferrer.flowAnalysis.equalityOp_rightBegin(left, leftType);
     ObjectAccessTarget equalsTarget = inferrer.findInterfaceMember(
         leftType, equalsName, fileOffset,
         includeExtensionMethods: true);
@@ -3557,7 +3557,9 @@
     if (isNot) {
       equals = new Not(equals)..fileOffset = fileOffset;
     }
-    inferrer.flowAnalysis.equalityOp_end(equals, right, notEqual: isNot);
+    inferrer.flowAnalysis.equalityOp_end(
+        equals, right, rightResult.inferredType,
+        notEqual: isNot);
     return new ExpressionInferenceResult(
         equalsTarget.isNever
             ? const NeverType(Nullability.nonNullable)
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 78e2f3e..a75173f 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
@@ -264,6 +264,21 @@
   TypeOperationsCfe(this.typeEnvironment);
 
   @override
+  TypeClassification classifyType(DartType type) {
+    if (type == null) {
+      // Note: this can happen during top-level inference.
+      return TypeClassification.potentiallyNullable;
+    } else if (isSubtypeOf(
+        type, typeEnvironment.coreTypes.objectNonNullableRawType)) {
+      return TypeClassification.nonNullable;
+    } else if (isSubtypeOf(type, typeEnvironment.coreTypes.nullType)) {
+      return TypeClassification.nullOrEquivalent;
+    } else {
+      return TypeClassification.potentiallyNullable;
+    }
+  }
+
+  @override
   DartType factor(DartType from, DartType what) {
     return factorType(typeEnvironment, from, what);
   }
diff --git a/pkg/front_end/test/spell_checking_list_common.txt b/pkg/front_end/test/spell_checking_list_common.txt
index 0850a28..81e9982 100644
--- a/pkg/front_end/test/spell_checking_list_common.txt
+++ b/pkg/front_end/test/spell_checking_list_common.txt
@@ -446,6 +446,10 @@
 class
 classes
 classic
+classification
+classifications
+classifies
+classify
 clause
 clauses
 clean
diff --git a/pkg/front_end/test/unit_test_suites.dart b/pkg/front_end/test/unit_test_suites.dart
index 72bc4fa..768fa14 100644
--- a/pkg/front_end/test/unit_test_suites.dart
+++ b/pkg/front_end/test/unit_test_suites.dart
@@ -8,7 +8,6 @@
 import 'dart:isolate' show Isolate, ReceivePort, SendPort;
 
 import 'package:args/args.dart' show ArgParser;
-
 import 'package:testing/src/chain.dart' show CreateContext, Result, Step;
 import 'package:testing/src/expectation.dart' show Expectation;
 import 'package:testing/src/log.dart' show Logger;
@@ -17,13 +16,14 @@
 import 'package:testing/src/test_description.dart' show TestDescription;
 
 import 'fasta/expression_suite.dart' as expression show createContext;
-import 'fasta/outline_suite.dart' as outline show createContext;
 import 'fasta/fast_strong_suite.dart' as fast_strong show createContext;
 import 'fasta/incremental_suite.dart' as incremental show createContext;
 import 'fasta/messages_suite.dart' as messages show createContext;
+import 'fasta/outline_suite.dart' as outline show createContext;
 import 'fasta/strong_tester.dart' as strong show createContext;
 import 'fasta/text_serialization_tester.dart' as text_serialization
     show createContext;
+import 'fasta/textual_outline_suite.dart' as textual_outline show createContext;
 import 'fasta/weak_suite.dart' as weak show createContext;
 import 'incremental_bulk_compiler_smoke_suite.dart' as incremental_bulk_compiler
     show createContext;
@@ -271,6 +271,8 @@
   const Suite(
       "spelling_test_src", spelling_src.createContext, "../testing.json"),
   const Suite("fasta/weak", weak.createContext, "../../testing.json"),
+  const Suite("fasta/textual_outline", textual_outline.createContext,
+      "../../testing.json"),
 ];
 
 const Duration timeoutDuration = Duration(minutes: 25);
diff --git a/pkg/front_end/testcases/general/callable_type_variable.dart.textual_outline.expect b/pkg/front_end/testcases/general/callable_type_variable.dart.textual_outline.expect
new file mode 100644
index 0000000..d54964e
--- /dev/null
+++ b/pkg/front_end/testcases/general/callable_type_variable.dart.textual_outline.expect
@@ -0,0 +1,13 @@
+class Class1<T extends Function> {
+  T field;
+  Class1(this.field);
+  method() {}
+}
+
+class Class2<T extends String Function(int)> {
+  T field;
+  Class2(this.field);
+  method() {}
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/general/callable_type_variable.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/callable_type_variable.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..8eb5879
--- /dev/null
+++ b/pkg/front_end/testcases/general/callable_type_variable.dart.textual_outline_modelled.expect
@@ -0,0 +1,13 @@
+class Class1<T extends Function> {
+  Class1(this.field);
+  T field;
+  method() {}
+}
+
+class Class2<T extends String Function(int)> {
+  Class2(this.field);
+  T field;
+  method() {}
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/general/issue34714.dart.textual_outline.expect b/pkg/front_end/testcases/general/issue34714.dart.textual_outline.expect
new file mode 100644
index 0000000..82ac1d1
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue34714.dart.textual_outline.expect
@@ -0,0 +1,9 @@
+class A<T> {
+  factory A() = B;
+}
+
+class B<T> implements A<T> {
+  B();
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/general/issue34714.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/issue34714.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..82ac1d1
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue34714.dart.textual_outline_modelled.expect
@@ -0,0 +1,9 @@
+class A<T> {
+  factory A() = B;
+}
+
+class B<T> implements A<T> {
+  B();
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/general/issue42615.dart.textual_outline.expect b/pkg/front_end/testcases/general/issue42615.dart.textual_outline.expect
new file mode 100644
index 0000000..d430822
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue42615.dart.textual_outline.expect
@@ -0,0 +1,8 @@
+import 'dart:async';
+
+class Class<T> {
+  Class({FutureOr<List<T>> Function() a});
+}
+
+dynamic method() => null;
+main() {}
diff --git a/pkg/front_end/testcases/general/issue42615.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/issue42615.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..d430822
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue42615.dart.textual_outline_modelled.expect
@@ -0,0 +1,8 @@
+import 'dart:async';
+
+class Class<T> {
+  Class({FutureOr<List<T>> Function() a});
+}
+
+dynamic method() => null;
+main() {}
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/future_or_null_test.dart.textual_outline.expect b/pkg/front_end/testcases/general_nnbd_opt_out/future_or_null_test.dart.textual_outline.expect
new file mode 100644
index 0000000..c579627
--- /dev/null
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/future_or_null_test.dart.textual_outline.expect
@@ -0,0 +1,5 @@
+// @dart = 2.6
+import 'dart:async';
+
+FutureOr<Null> get foo => null;
+main() {}
diff --git a/pkg/front_end/testcases/general_nnbd_opt_out/future_or_null_test.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general_nnbd_opt_out/future_or_null_test.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..c579627
--- /dev/null
+++ b/pkg/front_end/testcases/general_nnbd_opt_out/future_or_null_test.dart.textual_outline_modelled.expect
@@ -0,0 +1,5 @@
+// @dart = 2.6
+import 'dart:async';
+
+FutureOr<Null> get foo => null;
+main() {}
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/flutter_widget_transform_const.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/flutter_widget_transform_const.yaml
new file mode 100644
index 0000000..07a3cda
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/flutter_widget_transform_const.yaml
@@ -0,0 +1,122 @@
+# 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.md file.
+
+type: newworld
+target: DDC
+trackWidgetCreation: true
+worlds:
+  - entry: main.dart
+    experiments: non-nullable
+    sources:
+      main.dart: |
+        import 'foo.dart';
+        Foo newFoo = new Foo();
+        Bar newBar = new Bar();
+        Bar constBar = const Bar();
+        Baz newBaz = new Baz();
+        Boz newBoz = new Boz(createNew: true);
+        Boz constBoz = new Boz(createNew: false);
+      foo.dart:
+        import 'package:flutter/src/widgets/framework.dart';
+        import 'package:flutter/src/widgets/widget_inspector.dart';
+
+        class Foo extends Widget {
+          factory Foo() => const Foo._();
+
+          const Foo._();
+        }
+
+        class Bar extends Widget {
+          const factory Bar() = Bar._;
+
+          const Bar._();
+        }
+
+        class Baz extends Widget {
+          factory Baz() => const Baz._();
+
+          const factory Baz._() = Baz.__;
+
+          const Baz.__();
+        }
+
+        class Boz extends Widget {
+          factory Boz({bool createNew}) {
+            if (createNew) {
+              return new Boz._();
+            } else {
+              return const Boz._();
+            }
+          }
+
+          const Boz._();
+        }
+      flutter/lib/src/widgets/framework.dart: |
+        abstract class Bar {
+          const Bar();
+        }
+        abstract class Widget extends Bar {
+          const Widget();
+        }
+      flutter/lib/src/widgets/widget_inspector.dart: |
+        abstract class _HasCreationLocation {
+          _Location get _location;
+        }
+        /// A tuple with file, line, and column number, for displaying human-readable
+        /// file locations.
+        class _Location {
+          const _Location({
+            required this.file,
+            required this.line,
+            required this.column,
+            required this.name,
+            required this.parameterLocations,
+          });
+          /// File path of the location.
+          final String file;
+          /// 1-based line number.
+          final int line;
+          /// 1-based column number.
+          final int column;
+          /// Optional name of the parameter or function at this location.
+          final String name;
+          /// Optional locations of the parameters of the member at this location.
+          final List<_Location> parameterLocations;
+        }
+      .dart_tool/package_config.json: |
+        {
+          "configVersion": 2,
+          "packages": [
+            {
+              "name": "flutter",
+              "rootUri": "../flutter",
+              "packageUri": "lib/"
+            }
+          ]
+        }
+    expectedLibraryCount: 4
+  - entry: main.dart
+    worldType: updated
+    invalidate:
+      - main.dart
+    expectInitializeFromDill: false
+    sources:
+      main.dart: |
+        import 'foo.dart';
+    expectedLibraryCount: 4
+  - entry: main.dart
+    worldType: updated
+    invalidate:
+      - main.dart
+    expectInitializeFromDill: false
+    sources:
+      main.dart: |
+        import 'foo.dart';
+        Foo newFoo = new Foo();
+        Bar newBar = new Bar();
+        Bar constBar = const Bar();
+        Baz newBaz = new Baz();
+        Boz newBoz = new Boz(createNew: true);
+        Boz constBoz = new Boz(createNew: false);
+    expectedLibraryCount: 4
\ No newline at end of file
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/flutter_widget_transform_const.yaml.world.1.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/flutter_widget_transform_const.yaml.world.1.expect
new file mode 100644
index 0000000..3847ff7
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/flutter_widget_transform_const.yaml.world.1.expect
@@ -0,0 +1,126 @@
+main = <No Member>;
+library from "package:flutter/src/widgets/framework.dart" as fra {
+
+  abstract class Bar extends dart.core::Object /*hasConstConstructor*/  {
+    const constructor •() → fra::Bar
+      : super dart.core::Object::•()
+      ;
+  }
+  abstract class Widget extends fra::Bar implements wid::_HasCreationLocation /*hasConstConstructor*/  {
+    final field wid::_Location? _location /*isNullableByDefault, from null */;
+    const constructor •({wid::_Location? $creationLocationd_0dea112b090073317d4}) → fra::Widget
+      : super fra::Bar::•(), fra::Widget::_location = $creationLocationd_0dea112b090073317d4!
+      ;
+  }
+}
+library from "package:flutter/src/widgets/widget_inspector.dart" as wid {
+
+  abstract class _HasCreationLocation extends dart.core::Object {
+    synthetic constructor •() → wid::_HasCreationLocation
+      : super dart.core::Object::•()
+      ;
+    abstract get _location() → wid::_Location;
+  }
+  class _Location extends dart.core::Object /*hasConstConstructor*/  {
+    final field dart.core::String file;
+    final field dart.core::int line;
+    final field dart.core::int column;
+    final field dart.core::String name;
+    final field dart.core::List<wid::_Location> parameterLocations;
+    const constructor •({required dart.core::String file = #C1, required dart.core::int line = #C1, required dart.core::int column = #C1, required dart.core::String name = #C1, required dart.core::List<wid::_Location> parameterLocations = #C1}) → wid::_Location
+      : wid::_Location::file = file, wid::_Location::line = line, wid::_Location::column = column, wid::_Location::name = name, wid::_Location::parameterLocations = parameterLocations, super dart.core::Object::•()
+      ;
+  }
+}
+library from "org-dartlang-test:///foo.dart" as foo {
+
+  import "package:flutter/src/widgets/framework.dart";
+  import "package:flutter/src/widgets/widget_inspector.dart";
+
+  class Foo extends fra::Widget /*hasConstConstructor*/  {
+    const constructor _({wid::_Location? $creationLocationd_0dea112b090073317d4}) → foo::Foo
+      : super fra::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
+      ;
+    static factory •({wid::_Location? $creationLocationd_0dea112b090073317d4}) → foo::Foo
+      return #C7;
+  }
+  class Bar extends fra::Widget /*hasConstConstructor*/  {
+    static field dynamic _redirecting# = <dynamic>[foo::Bar::•]/*isNullableByDefault*/;
+    const constructor _({wid::_Location? $creationLocationd_0dea112b090073317d4}) → foo::Bar
+      : super fra::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
+      ;
+    static factory •({wid::_Location? $creationLocationd_0dea112b090073317d4}) → foo::Bar
+      let dynamic #redirecting_factory = foo::Bar::_ in invalid-expression;
+  }
+  class Baz extends fra::Widget /*hasConstConstructor*/  {
+    static field dynamic _redirecting# = <dynamic>[foo::Baz::_]/*isNullableByDefault*/;
+    const constructor __({wid::_Location? $creationLocationd_0dea112b090073317d4}) → foo::Baz
+      : super fra::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
+      ;
+    static factory •({wid::_Location? $creationLocationd_0dea112b090073317d4}) → foo::Baz
+      return #C10;
+    static factory _({wid::_Location? $creationLocationd_0dea112b090073317d4}) → foo::Baz
+      let dynamic #redirecting_factory = foo::Baz::__ in invalid-expression;
+  }
+  class Boz extends fra::Widget /*hasConstConstructor*/  {
+    const constructor _({wid::_Location? $creationLocationd_0dea112b090073317d4}) → foo::Boz
+      : super fra::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
+      ;
+    static factory •({dart.core::bool createNew = #C1, wid::_Location? $creationLocationd_0dea112b090073317d4}) → foo::Boz {
+      if(createNew) {
+        return new foo::Boz::_($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4);
+      }
+      else {
+        return #C14;
+      }
+    }
+  }
+}
+library from "org-dartlang-test:///main.dart" as main {
+
+  import "org-dartlang-test:///foo.dart";
+
+  static field foo::Foo newFoo = foo::Foo::•($creationLocationd_0dea112b090073317d4: #C17);
+  static field foo::Bar newBar = new foo::Bar::_($creationLocationd_0dea112b090073317d4: #C19);
+  static field foo::Bar constBar = #C23;
+  static field foo::Baz newBaz = foo::Baz::•($creationLocationd_0dea112b090073317d4: #C25);
+  static field foo::Boz newBoz = foo::Boz::•(createNew: true, $creationLocationd_0dea112b090073317d4: #C29);
+  static field foo::Boz constBoz = foo::Boz::•(createNew: false, $creationLocationd_0dea112b090073317d4: #C35);
+}
+constants  {
+  #C1 = null
+  #C2 = "org-dartlang-test:///foo.dart"
+  #C3 = 2.0
+  #C4 = 51.0
+  #C5 = <wid::_Location*>[]
+  #C6 = wid::_Location {file:#C2, line:#C3, column:#C4, name:#C1, parameterLocations:#C5}
+  #C7 = foo::Foo {_location:#C6}
+  #C8 = 6.0
+  #C9 = wid::_Location {file:#C2, line:#C8, column:#C4, name:#C1, parameterLocations:#C5}
+  #C10 = foo::Baz {_location:#C9}
+  #C11 = 9.0
+  #C12 = 119.0
+  #C13 = wid::_Location {file:#C2, line:#C11, column:#C12, name:#C1, parameterLocations:#C5}
+  #C14 = foo::Boz {_location:#C13}
+  #C15 = "org-dartlang-test:///main.dart"
+  #C16 = 18.0
+  #C17 = wid::_Location {file:#C15, line:#C3, column:#C16, name:#C1, parameterLocations:#C5}
+  #C18 = 3.0
+  #C19 = wid::_Location {file:#C15, line:#C18, column:#C16, name:#C1, parameterLocations:#C5}
+  #C20 = 4.0
+  #C21 = 22.0
+  #C22 = wid::_Location {file:#C15, line:#C20, column:#C21, name:#C1, parameterLocations:#C5}
+  #C23 = foo::Bar {_location:#C22}
+  #C24 = 5.0
+  #C25 = wid::_Location {file:#C15, line:#C24, column:#C16, name:#C1, parameterLocations:#C5}
+  #C26 = "createNew"
+  #C27 = wid::_Location {file:#C1, line:#C8, column:#C21, name:#C26, parameterLocations:#C1}
+  #C28 = <wid::_Location*>[#C27]
+  #C29 = wid::_Location {file:#C15, line:#C8, column:#C16, name:#C1, parameterLocations:#C28}
+  #C30 = 7.0
+  #C31 = 20.0
+  #C32 = 24.0
+  #C33 = wid::_Location {file:#C1, line:#C30, column:#C32, name:#C26, parameterLocations:#C1}
+  #C34 = <wid::_Location*>[#C33]
+  #C35 = wid::_Location {file:#C15, line:#C30, column:#C31, name:#C1, parameterLocations:#C34}
+}
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/flutter_widget_transform_const.yaml.world.2.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/flutter_widget_transform_const.yaml.world.2.expect
new file mode 100644
index 0000000..e48708e
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/flutter_widget_transform_const.yaml.world.2.expect
@@ -0,0 +1,99 @@
+main = <No Member>;
+library from "package:flutter/src/widgets/framework.dart" as fra {
+
+  abstract class Bar extends dart.core::Object /*hasConstConstructor*/  {
+    const constructor •() → fra::Bar
+      : super dart.core::Object::•()
+      ;
+  }
+  abstract class Widget extends fra::Bar implements wid::_HasCreationLocation /*hasConstConstructor*/  {
+    final field wid::_Location? _location /*isNullableByDefault, from null */;
+    const constructor •({wid::_Location? $creationLocationd_0dea112b090073317d4}) → fra::Widget
+      : super fra::Bar::•(), fra::Widget::_location = $creationLocationd_0dea112b090073317d4!
+      ;
+  }
+}
+library from "package:flutter/src/widgets/widget_inspector.dart" as wid {
+
+  abstract class _HasCreationLocation extends dart.core::Object {
+    synthetic constructor •() → wid::_HasCreationLocation
+      : super dart.core::Object::•()
+      ;
+    abstract get _location() → wid::_Location;
+  }
+  class _Location extends dart.core::Object /*hasConstConstructor*/  {
+    final field dart.core::String file;
+    final field dart.core::int line;
+    final field dart.core::int column;
+    final field dart.core::String name;
+    final field dart.core::List<wid::_Location> parameterLocations;
+    const constructor •({required dart.core::String file = #C1, required dart.core::int line = #C1, required dart.core::int column = #C1, required dart.core::String name = #C1, required dart.core::List<wid::_Location> parameterLocations = #C1}) → wid::_Location
+      : wid::_Location::file = file, wid::_Location::line = line, wid::_Location::column = column, wid::_Location::name = name, wid::_Location::parameterLocations = parameterLocations, super dart.core::Object::•()
+      ;
+  }
+}
+library from "org-dartlang-test:///foo.dart" as foo {
+
+  import "package:flutter/src/widgets/framework.dart";
+  import "package:flutter/src/widgets/widget_inspector.dart";
+
+  class Foo extends fra::Widget /*hasConstConstructor*/  {
+    const constructor _({wid::_Location? $creationLocationd_0dea112b090073317d4}) → foo::Foo
+      : super fra::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
+      ;
+    static factory •({wid::_Location? $creationLocationd_0dea112b090073317d4}) → foo::Foo
+      return #C7;
+  }
+  class Bar extends fra::Widget /*hasConstConstructor*/  {
+    static field dynamic _redirecting# = <dynamic>[foo::Bar::•]/*isNullableByDefault*/;
+    const constructor _({wid::_Location? $creationLocationd_0dea112b090073317d4}) → foo::Bar
+      : super fra::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
+      ;
+    static factory •({wid::_Location? $creationLocationd_0dea112b090073317d4}) → foo::Bar
+      let dynamic #redirecting_factory = foo::Bar::_ in invalid-expression;
+  }
+  class Baz extends fra::Widget /*hasConstConstructor*/  {
+    static field dynamic _redirecting# = <dynamic>[foo::Baz::_]/*isNullableByDefault*/;
+    const constructor __({wid::_Location? $creationLocationd_0dea112b090073317d4}) → foo::Baz
+      : super fra::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
+      ;
+    static factory •({wid::_Location? $creationLocationd_0dea112b090073317d4}) → foo::Baz
+      return #C10;
+    static factory _({wid::_Location? $creationLocationd_0dea112b090073317d4}) → foo::Baz
+      let dynamic #redirecting_factory = foo::Baz::__ in invalid-expression;
+  }
+  class Boz extends fra::Widget /*hasConstConstructor*/  {
+    const constructor _({wid::_Location? $creationLocationd_0dea112b090073317d4}) → foo::Boz
+      : super fra::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
+      ;
+    static factory •({dart.core::bool createNew = #C1, wid::_Location? $creationLocationd_0dea112b090073317d4}) → foo::Boz {
+      if(createNew) {
+        return new foo::Boz::_($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4);
+      }
+      else {
+        return #C14;
+      }
+    }
+  }
+}
+library from "org-dartlang-test:///main.dart" as main {
+
+  import "org-dartlang-test:///foo.dart";
+
+}
+constants  {
+  #C1 = null
+  #C2 = "org-dartlang-test:///foo.dart"
+  #C3 = 2.0
+  #C4 = 51.0
+  #C5 = <wid::_Location*>[]
+  #C6 = wid::_Location {file:#C2, line:#C3, column:#C4, name:#C1, parameterLocations:#C5}
+  #C7 = foo::Foo {_location:#C6}
+  #C8 = 6.0
+  #C9 = wid::_Location {file:#C2, line:#C8, column:#C4, name:#C1, parameterLocations:#C5}
+  #C10 = foo::Baz {_location:#C9}
+  #C11 = 9.0
+  #C12 = 119.0
+  #C13 = wid::_Location {file:#C2, line:#C11, column:#C12, name:#C1, parameterLocations:#C5}
+  #C14 = foo::Boz {_location:#C13}
+}
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/flutter_widget_transform_const.yaml.world.3.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/flutter_widget_transform_const.yaml.world.3.expect
new file mode 100644
index 0000000..3847ff7
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/flutter_widget_transform_const.yaml.world.3.expect
@@ -0,0 +1,126 @@
+main = <No Member>;
+library from "package:flutter/src/widgets/framework.dart" as fra {
+
+  abstract class Bar extends dart.core::Object /*hasConstConstructor*/  {
+    const constructor •() → fra::Bar
+      : super dart.core::Object::•()
+      ;
+  }
+  abstract class Widget extends fra::Bar implements wid::_HasCreationLocation /*hasConstConstructor*/  {
+    final field wid::_Location? _location /*isNullableByDefault, from null */;
+    const constructor •({wid::_Location? $creationLocationd_0dea112b090073317d4}) → fra::Widget
+      : super fra::Bar::•(), fra::Widget::_location = $creationLocationd_0dea112b090073317d4!
+      ;
+  }
+}
+library from "package:flutter/src/widgets/widget_inspector.dart" as wid {
+
+  abstract class _HasCreationLocation extends dart.core::Object {
+    synthetic constructor •() → wid::_HasCreationLocation
+      : super dart.core::Object::•()
+      ;
+    abstract get _location() → wid::_Location;
+  }
+  class _Location extends dart.core::Object /*hasConstConstructor*/  {
+    final field dart.core::String file;
+    final field dart.core::int line;
+    final field dart.core::int column;
+    final field dart.core::String name;
+    final field dart.core::List<wid::_Location> parameterLocations;
+    const constructor •({required dart.core::String file = #C1, required dart.core::int line = #C1, required dart.core::int column = #C1, required dart.core::String name = #C1, required dart.core::List<wid::_Location> parameterLocations = #C1}) → wid::_Location
+      : wid::_Location::file = file, wid::_Location::line = line, wid::_Location::column = column, wid::_Location::name = name, wid::_Location::parameterLocations = parameterLocations, super dart.core::Object::•()
+      ;
+  }
+}
+library from "org-dartlang-test:///foo.dart" as foo {
+
+  import "package:flutter/src/widgets/framework.dart";
+  import "package:flutter/src/widgets/widget_inspector.dart";
+
+  class Foo extends fra::Widget /*hasConstConstructor*/  {
+    const constructor _({wid::_Location? $creationLocationd_0dea112b090073317d4}) → foo::Foo
+      : super fra::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
+      ;
+    static factory •({wid::_Location? $creationLocationd_0dea112b090073317d4}) → foo::Foo
+      return #C7;
+  }
+  class Bar extends fra::Widget /*hasConstConstructor*/  {
+    static field dynamic _redirecting# = <dynamic>[foo::Bar::•]/*isNullableByDefault*/;
+    const constructor _({wid::_Location? $creationLocationd_0dea112b090073317d4}) → foo::Bar
+      : super fra::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
+      ;
+    static factory •({wid::_Location? $creationLocationd_0dea112b090073317d4}) → foo::Bar
+      let dynamic #redirecting_factory = foo::Bar::_ in invalid-expression;
+  }
+  class Baz extends fra::Widget /*hasConstConstructor*/  {
+    static field dynamic _redirecting# = <dynamic>[foo::Baz::_]/*isNullableByDefault*/;
+    const constructor __({wid::_Location? $creationLocationd_0dea112b090073317d4}) → foo::Baz
+      : super fra::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
+      ;
+    static factory •({wid::_Location? $creationLocationd_0dea112b090073317d4}) → foo::Baz
+      return #C10;
+    static factory _({wid::_Location? $creationLocationd_0dea112b090073317d4}) → foo::Baz
+      let dynamic #redirecting_factory = foo::Baz::__ in invalid-expression;
+  }
+  class Boz extends fra::Widget /*hasConstConstructor*/  {
+    const constructor _({wid::_Location? $creationLocationd_0dea112b090073317d4}) → foo::Boz
+      : super fra::Widget::•($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4)
+      ;
+    static factory •({dart.core::bool createNew = #C1, wid::_Location? $creationLocationd_0dea112b090073317d4}) → foo::Boz {
+      if(createNew) {
+        return new foo::Boz::_($creationLocationd_0dea112b090073317d4: $creationLocationd_0dea112b090073317d4);
+      }
+      else {
+        return #C14;
+      }
+    }
+  }
+}
+library from "org-dartlang-test:///main.dart" as main {
+
+  import "org-dartlang-test:///foo.dart";
+
+  static field foo::Foo newFoo = foo::Foo::•($creationLocationd_0dea112b090073317d4: #C17);
+  static field foo::Bar newBar = new foo::Bar::_($creationLocationd_0dea112b090073317d4: #C19);
+  static field foo::Bar constBar = #C23;
+  static field foo::Baz newBaz = foo::Baz::•($creationLocationd_0dea112b090073317d4: #C25);
+  static field foo::Boz newBoz = foo::Boz::•(createNew: true, $creationLocationd_0dea112b090073317d4: #C29);
+  static field foo::Boz constBoz = foo::Boz::•(createNew: false, $creationLocationd_0dea112b090073317d4: #C35);
+}
+constants  {
+  #C1 = null
+  #C2 = "org-dartlang-test:///foo.dart"
+  #C3 = 2.0
+  #C4 = 51.0
+  #C5 = <wid::_Location*>[]
+  #C6 = wid::_Location {file:#C2, line:#C3, column:#C4, name:#C1, parameterLocations:#C5}
+  #C7 = foo::Foo {_location:#C6}
+  #C8 = 6.0
+  #C9 = wid::_Location {file:#C2, line:#C8, column:#C4, name:#C1, parameterLocations:#C5}
+  #C10 = foo::Baz {_location:#C9}
+  #C11 = 9.0
+  #C12 = 119.0
+  #C13 = wid::_Location {file:#C2, line:#C11, column:#C12, name:#C1, parameterLocations:#C5}
+  #C14 = foo::Boz {_location:#C13}
+  #C15 = "org-dartlang-test:///main.dart"
+  #C16 = 18.0
+  #C17 = wid::_Location {file:#C15, line:#C3, column:#C16, name:#C1, parameterLocations:#C5}
+  #C18 = 3.0
+  #C19 = wid::_Location {file:#C15, line:#C18, column:#C16, name:#C1, parameterLocations:#C5}
+  #C20 = 4.0
+  #C21 = 22.0
+  #C22 = wid::_Location {file:#C15, line:#C20, column:#C21, name:#C1, parameterLocations:#C5}
+  #C23 = foo::Bar {_location:#C22}
+  #C24 = 5.0
+  #C25 = wid::_Location {file:#C15, line:#C24, column:#C16, name:#C1, parameterLocations:#C5}
+  #C26 = "createNew"
+  #C27 = wid::_Location {file:#C1, line:#C8, column:#C21, name:#C26, parameterLocations:#C1}
+  #C28 = <wid::_Location*>[#C27]
+  #C29 = wid::_Location {file:#C15, line:#C8, column:#C16, name:#C1, parameterLocations:#C28}
+  #C30 = 7.0
+  #C31 = 20.0
+  #C32 = 24.0
+  #C33 = wid::_Location {file:#C1, line:#C30, column:#C32, name:#C26, parameterLocations:#C1}
+  #C34 = <wid::_Location*>[#C33]
+  #C35 = wid::_Location {file:#C15, line:#C30, column:#C31, name:#C1, parameterLocations:#C34}
+}
diff --git a/pkg/front_end/testcases/nnbd/infer_method_types.dart.outline.expect b/pkg/front_end/testcases/nnbd/infer_method_types.dart.outline.expect
index f0f39bc4..fa99f33 100644
--- a/pkg/front_end/testcases/nnbd/infer_method_types.dart.outline.expect
+++ b/pkg/front_end/testcases/nnbd/infer_method_types.dart.outline.expect
@@ -40,7 +40,7 @@
 abstract class H extends core::Object implements self::D, self::E, self::F, self::C {
   synthetic constructor •() → self::H
     ;
-  abstract forwarding-stub member-signature method m(covariant core::num a) → core::Object?;
+  abstract forwarding-stub method m(covariant core::num a) → core::Object?;
 }
 abstract class I extends core::Object implements self::D {
   synthetic constructor •() → self::I
@@ -55,7 +55,7 @@
 abstract class K extends core::Object implements self::I, self::E, self::G {
   synthetic constructor •() → self::K
     ;
-  abstract forwarding-stub member-signature method m(covariant core::num a) → core::Object?;
+  abstract forwarding-stub method m(covariant core::num a) → core::Object?;
 }
 abstract class L extends core::Object implements self::K {
   synthetic constructor •() → self::L
diff --git a/pkg/front_end/testcases/nnbd/infer_method_types.dart.strong.expect b/pkg/front_end/testcases/nnbd/infer_method_types.dart.strong.expect
index 85e72a0..5bd5e36 100644
--- a/pkg/front_end/testcases/nnbd/infer_method_types.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/infer_method_types.dart.strong.expect
@@ -48,7 +48,7 @@
   synthetic constructor •() → self::H
     : super core::Object::•()
     ;
-  abstract forwarding-stub member-signature method m(covariant core::num a) → core::Object?;
+  abstract forwarding-stub method m(covariant core::num a) → core::Object?;
 }
 abstract class I extends core::Object implements self::D {
   synthetic constructor •() → self::I
@@ -66,7 +66,7 @@
   synthetic constructor •() → self::K
     : super core::Object::•()
     ;
-  abstract forwarding-stub member-signature method m(covariant core::num a) → core::Object?;
+  abstract forwarding-stub method m(covariant core::num a) → core::Object?;
 }
 abstract class L extends core::Object implements self::K {
   synthetic constructor •() → self::L
diff --git a/pkg/front_end/testcases/nnbd/infer_method_types.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/infer_method_types.dart.strong.transformed.expect
index 85e72a0..5bd5e36 100644
--- a/pkg/front_end/testcases/nnbd/infer_method_types.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/infer_method_types.dart.strong.transformed.expect
@@ -48,7 +48,7 @@
   synthetic constructor •() → self::H
     : super core::Object::•()
     ;
-  abstract forwarding-stub member-signature method m(covariant core::num a) → core::Object?;
+  abstract forwarding-stub method m(covariant core::num a) → core::Object?;
 }
 abstract class I extends core::Object implements self::D {
   synthetic constructor •() → self::I
@@ -66,7 +66,7 @@
   synthetic constructor •() → self::K
     : super core::Object::•()
     ;
-  abstract forwarding-stub member-signature method m(covariant core::num a) → core::Object?;
+  abstract forwarding-stub method m(covariant core::num a) → core::Object?;
 }
 abstract class L extends core::Object implements self::K {
   synthetic constructor •() → self::L
diff --git a/pkg/front_end/testcases/nnbd/infer_method_types.dart.weak.expect b/pkg/front_end/testcases/nnbd/infer_method_types.dart.weak.expect
index 85e72a0..5bd5e36 100644
--- a/pkg/front_end/testcases/nnbd/infer_method_types.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/infer_method_types.dart.weak.expect
@@ -48,7 +48,7 @@
   synthetic constructor •() → self::H
     : super core::Object::•()
     ;
-  abstract forwarding-stub member-signature method m(covariant core::num a) → core::Object?;
+  abstract forwarding-stub method m(covariant core::num a) → core::Object?;
 }
 abstract class I extends core::Object implements self::D {
   synthetic constructor •() → self::I
@@ -66,7 +66,7 @@
   synthetic constructor •() → self::K
     : super core::Object::•()
     ;
-  abstract forwarding-stub member-signature method m(covariant core::num a) → core::Object?;
+  abstract forwarding-stub method m(covariant core::num a) → core::Object?;
 }
 abstract class L extends core::Object implements self::K {
   synthetic constructor •() → self::L
diff --git a/pkg/front_end/testcases/nnbd/infer_method_types.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/infer_method_types.dart.weak.transformed.expect
index 85e72a0..5bd5e36 100644
--- a/pkg/front_end/testcases/nnbd/infer_method_types.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/infer_method_types.dart.weak.transformed.expect
@@ -48,7 +48,7 @@
   synthetic constructor •() → self::H
     : super core::Object::•()
     ;
-  abstract forwarding-stub member-signature method m(covariant core::num a) → core::Object?;
+  abstract forwarding-stub method m(covariant core::num a) → core::Object?;
 }
 abstract class I extends core::Object implements self::D {
   synthetic constructor •() → self::I
@@ -66,7 +66,7 @@
   synthetic constructor •() → self::K
     : super core::Object::•()
     ;
-  abstract forwarding-stub member-signature method m(covariant core::num a) → core::Object?;
+  abstract forwarding-stub method m(covariant core::num a) → core::Object?;
 }
 abstract class L extends core::Object implements self::K {
   synthetic constructor •() → self::L
diff --git a/pkg/front_end/testcases/nnbd/issue42579.dart.textual_outline.expect b/pkg/front_end/testcases/nnbd/issue42579.dart.textual_outline.expect
new file mode 100644
index 0000000..8c9bcff
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42579.dart.textual_outline.expect
@@ -0,0 +1,6 @@
+class A<T> {}
+
+S foo<S>() => throw "foo";
+bar<R>(A<R> a) {}
+baz() => bar(foo());
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue42579.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd/issue42579.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..3e6dfbe
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42579.dart.textual_outline_modelled.expect
@@ -0,0 +1,7 @@
+S foo<S>() => throw "foo";
+bar<R>(A<R> a) {}
+baz() => bar(foo());
+
+class A<T> {}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue42579_2.dart.textual_outline.expect b/pkg/front_end/testcases/nnbd/issue42579_2.dart.textual_outline.expect
new file mode 100644
index 0000000..60af131
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42579_2.dart.textual_outline.expect
@@ -0,0 +1,9 @@
+class A<T> {
+  T get property => throw "A.property";
+}
+
+S foo<S>() => throw "foo";
+wrap<R>(R Function() f) {}
+wrap2<R>(A<R> Function() f) {}
+bar() {}
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue42579_2.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd/issue42579_2.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..5cdcfec
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42579_2.dart.textual_outline_modelled.expect
@@ -0,0 +1,10 @@
+S foo<S>() => throw "foo";
+bar() {}
+
+class A<T> {
+  T get property => throw "A.property";
+}
+
+main() {}
+wrap2<R>(A<R> Function() f) {}
+wrap<R>(R Function() f) {}
diff --git a/pkg/front_end/testcases/nnbd/issue42579_3.dart.textual_outline.expect b/pkg/front_end/testcases/nnbd/issue42579_3.dart.textual_outline.expect
new file mode 100644
index 0000000..743ca12
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42579_3.dart.textual_outline.expect
@@ -0,0 +1,11 @@
+class A<X> {}
+
+class B<Y1, Y2 extends List<Y3>, Y3> extends A<Y1> {
+  Y1 get y1 => throw "B.y1";
+  Y2 get y2 => throw "B.y2";
+  Y3 get y3 => throw "B.y3";
+}
+
+foo<Z>(A<List<Z>> Function() f) {}
+bar() {}
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue42579_3.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd/issue42579_3.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..0a7a426
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42579_3.dart.textual_outline_modelled.expect
@@ -0,0 +1,12 @@
+bar() {}
+
+class A<X> {}
+
+class B<Y1, Y2 extends List<Y3>, Y3> extends A<Y1> {
+  Y1 get y1 => throw "B.y1";
+  Y2 get y2 => throw "B.y2";
+  Y3 get y3 => throw "B.y3";
+}
+
+foo<Z>(A<List<Z>> Function() f) {}
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/upper_bound_on_promoted_type.dart.textual_outline.expect b/pkg/front_end/testcases/nnbd/upper_bound_on_promoted_type.dart.textual_outline.expect
new file mode 100644
index 0000000..39f0511
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/upper_bound_on_promoted_type.dart.textual_outline.expect
@@ -0,0 +1,7 @@
+class Foo<T> {
+  dynamic bar;
+  dynamic baz;
+  dynamic qux() {}
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/upper_bound_on_promoted_type.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd/upper_bound_on_promoted_type.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..39f0511
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/upper_bound_on_promoted_type.dart.textual_outline_modelled.expect
@@ -0,0 +1,7 @@
+class Foo<T> {
+  dynamic bar;
+  dynamic baz;
+  dynamic qux() {}
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/regress/issue_41265.crash_dart.textual_outline.expect b/pkg/front_end/testcases/regress/issue_41265.crash_dart.textual_outline.expect
index 0ebe3c9..49f2d7d 100644
--- a/pkg/front_end/testcases/regress/issue_41265.crash_dart.textual_outline.expect
+++ b/pkg/front_end/testcases/regress/issue_41265.crash_dart.textual_outline.expect
@@ -1 +1,13 @@
-class A<T> {} mixin M<T> {} class DND1 extends Object with M<dynamic> Function()> { } class DND2 extends Object with M<dynamic> Function() { } class DND3 extends M<dynamic> Function() { } class DND4 implements M<dynamic> Function() { } main() { }
+class A<T> {
+}
+mixin M<T> {
+}
+class DND1 extends Object with M<dynamic> Function()> {
+}
+class DND2 extends Object with M<dynamic> Function() {
+}
+class DND3 extends M<dynamic> Function() {
+}
+class DND4 implements M<dynamic> Function() {
+}
+main() { }
diff --git a/pkg/front_end/testcases/textual_outline.status b/pkg/front_end/testcases/textual_outline.status
index 6603dc9..138700b 100644
--- a/pkg/front_end/testcases/textual_outline.status
+++ b/pkg/front_end/testcases/textual_outline.status
@@ -20,9 +20,6 @@
 regress/issue_39091_2: EmptyOutput
 regress/utf_16_le_content.crash: EmptyOutput
 
-rasta/issue_000032: FormatterCrash
-regress/ambiguous_builder_01: FormatterCrash
-regress/issue_34614: FormatterCrash
 extensions/ambiguous: FormatterCrash
 extensions/annotations: FormatterCrash
 extensions/builtin_identifiers: FormatterCrash
@@ -99,7 +96,6 @@
 general/bug31124: FormatterCrash
 general/clone_function_type: FormatterCrash
 general/constructor_initializer_invalid: FormatterCrash
-general/covariant_field: FormatterCrash
 general/duplicated_declarations: FormatterCrash
 general/error_recovery/constructor_recovery_bad_name_general.crash: FormatterCrash
 general/error_recovery/constructor_recovery_bad_name_get.crash: FormatterCrash
@@ -120,7 +116,9 @@
 general/invalid_operator: FormatterCrash
 general/invalid_operator2: FormatterCrash
 general/issue40242: FormatterCrash
+general/issue42997: FormatterCrash
 general/many_errors: FormatterCrash
+general/null_safety_invalid_experiment_and_language_version: FormatterCrash
 general/type_parameter_usage_in_static_method_in_extension: FormatterCrash
 general/type_parameters_on_void: FormatterCrash
 general/var_as_type_name: FormatterCrash
@@ -157,8 +155,21 @@
 late_lowering/override_getter_setter: FormatterCrash
 late_lowering/override: FormatterCrash
 late_lowering/uninitialized_non_nullable_late_fields: FormatterCrash
+nnbd_mixed/inheritance_from_opt_in: FormatterCrash
+nnbd_mixed/issue41597: FormatterCrash
+nnbd_mixed/no_null_shorting_explicit_extension: FormatterCrash
+nnbd_mixed/no_null_shorting_extension: FormatterCrash
+nnbd_mixed/null_safety_invalid_language_version: FormatterCrash
+nnbd_mixed/nullable_extension_on_opt_out: FormatterCrash
+nnbd_mixed/opt_out: FormatterCrash
+nnbd/abstract_field_errors: FormatterCrash
+nnbd/abstract_fields_spec: FormatterCrash
+nnbd/abstract_fields: FormatterCrash
 nnbd/covariant_late_field: FormatterCrash
 nnbd/extension_never: FormatterCrash
+nnbd/external_field_errors: FormatterCrash
+nnbd/external_fields_spec: FormatterCrash
+nnbd/external_fields: FormatterCrash
 nnbd/forbidden_supers: FormatterCrash
 nnbd/infer_if_null: FormatterCrash
 nnbd/inheritance_from_opt_in: FormatterCrash
@@ -174,6 +185,8 @@
 nnbd/null_shorting_explicit_extension: FormatterCrash
 nnbd/null_shorting_extension: FormatterCrash
 nnbd/null_shorting_index: FormatterCrash
+nnbd/nullable_extension: FormatterCrash
+nnbd/nullable_setter: FormatterCrash
 nnbd/opt_out: FormatterCrash
 nnbd/potentially_non_nullable_field: FormatterCrash
 nnbd/potentially_nullable_access: FormatterCrash
@@ -181,6 +194,7 @@
 nnbd/uninitialized_non_nullable_late_fields: FormatterCrash
 nonfunction_type_aliases/issue41501: FormatterCrash
 rasta/bad_redirection: FormatterCrash
+rasta/issue_000032: FormatterCrash
 rasta/issue_000034: FormatterCrash
 rasta/issue_000036: FormatterCrash
 rasta/issue_000044: FormatterCrash
@@ -188,6 +202,7 @@
 rasta/issue_000047: FormatterCrash
 rasta/malformed_const_constructor: FormatterCrash
 rasta/mandatory_parameter_initializer: FormatterCrash
+regress/ambiguous_builder_01: FormatterCrash
 regress/issue_29942: FormatterCrash
 regress/issue_29944: FormatterCrash
 regress/issue_29983: FormatterCrash
@@ -204,12 +219,14 @@
 regress/issue_34225: FormatterCrash
 regress/issue_34563: FormatterCrash
 regress/issue_34610: FormatterCrash
+regress/issue_34614: FormatterCrash
 regress/issue_34850: FormatterCrash
 regress/issue_35151: FormatterCrash
 regress/issue_36400: FormatterCrash
 regress/issue_37285: FormatterCrash
 regress/issue_39091_1: FormatterCrash
 regress/issue_41265.crash: Crash
+regress/issue_41265.crash: FormatterCrash
 triple_shift/invalid_operator: FormatterCrash
 variance/class_type_parameter_modifier: FormatterCrash
 variance/generic_covariance_sound_variance: FormatterCrash
diff --git a/pkg/front_end/testcases/value_class/empty.dart.textual_outline.expect b/pkg/front_end/testcases/value_class/empty.dart.textual_outline.expect
new file mode 100644
index 0000000..5716b5d
--- /dev/null
+++ b/pkg/front_end/testcases/value_class/empty.dart.textual_outline.expect
@@ -0,0 +1,6 @@
+const String valueClass = "valueClass";
+
+@valueClass
+class EmptyClass {}
+
+main() {}
diff --git a/pkg/front_end/testcases/value_class/empty.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/value_class/empty.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..3137333
--- /dev/null
+++ b/pkg/front_end/testcases/value_class/empty.dart.textual_outline_modelled.expect
@@ -0,0 +1,5 @@
+@valueClass
+class EmptyClass {}
+
+const String valueClass = "valueClass";
+main() {}
diff --git a/pkg/front_end/testcases/value_class/explicit_mixin.dart.textual_outline.expect b/pkg/front_end/testcases/value_class/explicit_mixin.dart.textual_outline.expect
new file mode 100644
index 0000000..2b99804
--- /dev/null
+++ b/pkg/front_end/testcases/value_class/explicit_mixin.dart.textual_outline.expect
@@ -0,0 +1,14 @@
+const String valueClass = "valueClass";
+
+@valueClass
+class A {}
+
+class B {}
+
+class C {}
+
+class D = A with B;
+class E = B with A;
+@valueClass
+class F = B with C;
+main() {}
diff --git a/pkg/front_end/testcases/value_class/explicit_mixin.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/value_class/explicit_mixin.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..afefd47
--- /dev/null
+++ b/pkg/front_end/testcases/value_class/explicit_mixin.dart.textual_outline_modelled.expect
@@ -0,0 +1,13 @@
+@valueClass
+class A {}
+
+class B {}
+
+class C {}
+
+const String valueClass = "valueClass";
+class D = A with B;
+class E = B with A;
+@valueClass
+class F = B with C;
+main() {}
diff --git a/pkg/front_end/testcases/value_class/non_final_field_error.dart.textual_outline.expect b/pkg/front_end/testcases/value_class/non_final_field_error.dart.textual_outline.expect
new file mode 100644
index 0000000..2130873
--- /dev/null
+++ b/pkg/front_end/testcases/value_class/non_final_field_error.dart.textual_outline.expect
@@ -0,0 +1,8 @@
+const String valueClass = "valueClass";
+
+@valueClass
+class Animal {
+  int numLegs;
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/value_class/non_final_field_error.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/value_class/non_final_field_error.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..e9bb0a6
--- /dev/null
+++ b/pkg/front_end/testcases/value_class/non_final_field_error.dart.textual_outline_modelled.expect
@@ -0,0 +1,7 @@
+@valueClass
+class Animal {
+  int numLegs;
+}
+
+const String valueClass = "valueClass";
+main() {}
diff --git a/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.textual_outline.expect b/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.textual_outline.expect
new file mode 100644
index 0000000..91337d4
--- /dev/null
+++ b/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.textual_outline.expect
@@ -0,0 +1,10 @@
+const String valueClass = "valueClass";
+
+@valueClass
+class Animal {
+  final int numLegs;
+}
+
+class Cat extends Animal {}
+
+main() {}
diff --git a/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..693a088
--- /dev/null
+++ b/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.textual_outline_modelled.expect
@@ -0,0 +1,9 @@
+@valueClass
+class Animal {
+  final int numLegs;
+}
+
+class Cat extends Animal {}
+
+const String valueClass = "valueClass";
+main() {}
diff --git a/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.textual_outline.expect b/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.textual_outline.expect
new file mode 100644
index 0000000..a28b098
--- /dev/null
+++ b/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.textual_outline.expect
@@ -0,0 +1,12 @@
+const String valueClass = "valueClass";
+
+@valueClass
+class Animal {
+  final int numLegs;
+}
+
+class Cat implements Animal {
+  final int numLegs;
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..021adc2
--- /dev/null
+++ b/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.textual_outline_modelled.expect
@@ -0,0 +1,11 @@
+@valueClass
+class Animal {
+  final int numLegs;
+}
+
+class Cat implements Animal {
+  final int numLegs;
+}
+
+const String valueClass = "valueClass";
+main() {}
diff --git a/pkg/front_end/testcases/value_class/simple.dart.textual_outline.expect b/pkg/front_end/testcases/value_class/simple.dart.textual_outline.expect
new file mode 100644
index 0000000..5408535
--- /dev/null
+++ b/pkg/front_end/testcases/value_class/simple.dart.textual_outline.expect
@@ -0,0 +1,9 @@
+const String valueClass = "valueClass";
+
+@valueClass
+class Animal {
+  final int numLegs;
+}
+
+main() {}
+expect(expected, actual, [expectNull = false]) {}
diff --git a/pkg/front_end/testcases/value_class/simple.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/value_class/simple.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..dabb2ae
--- /dev/null
+++ b/pkg/front_end/testcases/value_class/simple.dart.textual_outline_modelled.expect
@@ -0,0 +1,8 @@
+@valueClass
+class Animal {
+  final int numLegs;
+}
+
+const String valueClass = "valueClass";
+expect(expected, actual, [expectNull = false]) {}
+main() {}
diff --git a/pkg/front_end/testcases/value_class/super_type.dart.textual_outline.expect b/pkg/front_end/testcases/value_class/super_type.dart.textual_outline.expect
new file mode 100644
index 0000000..08894f3
--- /dev/null
+++ b/pkg/front_end/testcases/value_class/super_type.dart.textual_outline.expect
@@ -0,0 +1,15 @@
+const String valueClass = "valueClass";
+
+@valueClass
+class Animal {
+  final int numLegs;
+}
+
+@valueClass
+class Cat implements Animal {
+  final int numLegs;
+  final int numWhiskers;
+}
+
+main() {}
+expect(expected, actual, [expectNull = false]) {}
diff --git a/pkg/front_end/testcases/value_class/super_type.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/value_class/super_type.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..33c1c4f
--- /dev/null
+++ b/pkg/front_end/testcases/value_class/super_type.dart.textual_outline_modelled.expect
@@ -0,0 +1,14 @@
+@valueClass
+class Animal {
+  final int numLegs;
+}
+
+@valueClass
+class Cat implements Animal {
+  final int numLegs;
+  final int numWhiskers;
+}
+
+const String valueClass = "valueClass";
+expect(expected, actual, [expectNull = false]) {}
+main() {}
diff --git a/pkg/front_end/testcases/value_class/value_extends_non_value.dart.textual_outline.expect b/pkg/front_end/testcases/value_class/value_extends_non_value.dart.textual_outline.expect
new file mode 100644
index 0000000..ec2d5db
--- /dev/null
+++ b/pkg/front_end/testcases/value_class/value_extends_non_value.dart.textual_outline.expect
@@ -0,0 +1,10 @@
+const String valueClass = "valueClass";
+
+class Animal {
+  final int numLegs;
+}
+
+@valueClass
+class Cat extends Animal {}
+
+main() {}
diff --git a/pkg/front_end/testcases/value_class/value_extends_non_value.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/value_class/value_extends_non_value.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..89b6414
--- /dev/null
+++ b/pkg/front_end/testcases/value_class/value_extends_non_value.dart.textual_outline_modelled.expect
@@ -0,0 +1,9 @@
+@valueClass
+class Cat extends Animal {}
+
+class Animal {
+  final int numLegs;
+}
+
+const String valueClass = "valueClass";
+main() {}
diff --git a/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.textual_outline.expect b/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.textual_outline.expect
new file mode 100644
index 0000000..5d5b409
--- /dev/null
+++ b/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.textual_outline.expect
@@ -0,0 +1,10 @@
+const String valueClass = "valueClass";
+
+class Animal {
+  int numLegs;
+}
+
+@valueClass
+class Cat extends Animal {}
+
+main() {}
diff --git a/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..9ee23d7
--- /dev/null
+++ b/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.textual_outline_modelled.expect
@@ -0,0 +1,9 @@
+@valueClass
+class Cat extends Animal {}
+
+class Animal {
+  int numLegs;
+}
+
+const String valueClass = "valueClass";
+main() {}
diff --git a/pkg/front_end/testcases/value_class/value_implements_non_value.dart.textual_outline.expect b/pkg/front_end/testcases/value_class/value_implements_non_value.dart.textual_outline.expect
new file mode 100644
index 0000000..c0ada4f
--- /dev/null
+++ b/pkg/front_end/testcases/value_class/value_implements_non_value.dart.textual_outline.expect
@@ -0,0 +1,12 @@
+const String valueClass = "valueClass";
+
+class Animal {
+  final int numLegs;
+}
+
+@valueClass
+class Cat implements Animal {
+  final int numLegs;
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/value_class/value_implements_non_value.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/value_class/value_implements_non_value.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..ebcb028
--- /dev/null
+++ b/pkg/front_end/testcases/value_class/value_implements_non_value.dart.textual_outline_modelled.expect
@@ -0,0 +1,11 @@
+@valueClass
+class Cat implements Animal {
+  final int numLegs;
+}
+
+class Animal {
+  final int numLegs;
+}
+
+const String valueClass = "valueClass";
+main() {}
diff --git a/pkg/front_end/testcases/value_class/value_mixin_error.dart.textual_outline.expect b/pkg/front_end/testcases/value_class/value_mixin_error.dart.textual_outline.expect
new file mode 100644
index 0000000..c195f72
--- /dev/null
+++ b/pkg/front_end/testcases/value_class/value_mixin_error.dart.textual_outline.expect
@@ -0,0 +1,12 @@
+const String valueClass = "valueClass";
+
+@valueClass
+class A {}
+
+class B {}
+
+class C extends B with A {}
+
+class C extends A with B {}
+
+main() {}
diff --git a/pkg/front_end/testcases/value_class/value_mixin_error.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/value_class/value_mixin_error.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..17460dc
--- /dev/null
+++ b/pkg/front_end/testcases/value_class/value_mixin_error.dart.textual_outline_modelled.expect
@@ -0,0 +1,11 @@
+@valueClass
+class A {}
+
+class B {}
+
+class C extends A with B {}
+
+class C extends B with A {}
+
+const String valueClass = "valueClass";
+main() {}
diff --git a/pkg/kernel/lib/binary/ast_to_binary.dart b/pkg/kernel/lib/binary/ast_to_binary.dart
index 7654469..481479e 100644
--- a/pkg/kernel/lib/binary/ast_to_binary.dart
+++ b/pkg/kernel/lib/binary/ast_to_binary.dart
@@ -1191,6 +1191,19 @@
         !(node.isMemberSignature &&
             node.memberSignatureOriginReference == null),
         "No member signature origin for member signature $node.");
+    assert(!(node.isMemberSignature && node.isForwardingStub),
+        "Procedure is both member signature and forwarding stub: $node.");
+    assert(!(node.isMemberSignature && node.isForwardingSemiStub),
+        "Procedure is both member signature and forwarding semi stub: $node.");
+    assert(
+        !(node.forwardingStubInterfaceTarget is Procedure &&
+            (node.forwardingStubInterfaceTarget as Procedure)
+                .isMemberSignature),
+        "Forwarding stub interface target is member signature: $node.");
+    assert(
+        !(node.forwardingStubSuperTarget is Procedure &&
+            (node.forwardingStubSuperTarget as Procedure).isMemberSignature),
+        "Forwarding stub super target is member signature: $node.");
 
     procedureOffsets.add(getBufferOffset());
 
diff --git a/pkg/kernel/lib/transformations/track_widget_constructor_locations.dart b/pkg/kernel/lib/transformations/track_widget_constructor_locations.dart
index ec8c8c8..5e18e6f 100644
--- a/pkg/kernel/lib/transformations/track_widget_constructor_locations.dart
+++ b/pkg/kernel/lib/transformations/track_widget_constructor_locations.dart
@@ -209,16 +209,18 @@
       return node;
     }
 
-    _addLocationArgument(node, target.function, constructedClass);
+    _addLocationArgument(node, target.function, constructedClass,
+        isConst: node.isConst);
     return node;
   }
 
-  void _addLocationArgument(InvocationExpression node, FunctionNode function,
-      Class constructedClass) {
+  void _addLocationArgument(
+      InvocationExpression node, FunctionNode function, Class constructedClass,
+      {bool isConst: false}) {
     _maybeAddCreationLocationArgument(
       node.arguments,
       function,
-      _computeLocation(node, function, constructedClass),
+      _computeLocation(node, function, constructedClass, isConst: isConst),
       _locationClass,
     );
   }
@@ -233,17 +235,23 @@
       return node;
     }
 
-    _addLocationArgument(node, constructor.function, constructedClass);
+    _addLocationArgument(node, constructor.function, constructedClass,
+        isConst: node.isConst);
     return node;
   }
 
-  Expression _computeLocation(InvocationExpression node, FunctionNode function,
-      Class constructedClass) {
+  Expression _computeLocation(
+      InvocationExpression node, FunctionNode function, Class constructedClass,
+      {bool isConst: false}) {
     // For factory constructors we need to use the location specified as an
     // argument to the factory constructor rather than the location
     if (_currentFactory != null &&
         _tracker._isSubclassOf(
-            constructedClass, _currentFactory.enclosingClass)) {
+            constructedClass, _currentFactory.enclosingClass) &&
+        // If the constructor invocation is constant we cannot refer to the
+        // location parameter of the surrounding factory since it isn't a
+        // constant expression.
+        !isConst) {
       final VariableDeclaration creationLocationParameter = _getNamedParameter(
         _currentFactory.function,
         _creationLocationParameterName,
diff --git a/pkg/nnbd_migration/lib/src/decorated_type_operations.dart b/pkg/nnbd_migration/lib/src/decorated_type_operations.dart
index 1ff9b47..05b2e5f 100644
--- a/pkg/nnbd_migration/lib/src/decorated_type_operations.dart
+++ b/pkg/nnbd_migration/lib/src/decorated_type_operations.dart
@@ -21,6 +21,15 @@
       this._typeSystem, this._variableRepository, this._graph);
 
   @override
+  TypeClassification classifyType(DecoratedType type) {
+    if (type.type.isDartCoreNull) {
+      return TypeClassification.nullOrEquivalent;
+    } else {
+      return TypeClassification.potentiallyNullable;
+    }
+  }
+
+  @override
   DecoratedType factor(DecoratedType from, DecoratedType what) {
     // TODO(scheglov): https://github.com/dart-lang/sdk/issues/41672
     return from;
diff --git a/pkg/nnbd_migration/lib/src/edge_builder.dart b/pkg/nnbd_migration/lib/src/edge_builder.dart
index 8011686..af3f31d 100644
--- a/pkg/nnbd_migration/lib/src/edge_builder.dart
+++ b/pkg/nnbd_migration/lib/src/edge_builder.dart
@@ -414,11 +414,12 @@
     if (operatorType == TokenType.EQ_EQ || operatorType == TokenType.BANG_EQ) {
       var leftType = _dispatch(leftOperand);
       _graph.connectDummy(leftType.node, DummyOrigin(source, node));
-      _flowAnalysis.equalityOp_rightBegin(leftOperand);
+      _flowAnalysis.equalityOp_rightBegin(leftOperand, leftType);
       var rightType = _dispatch(rightOperand);
       _graph.connectDummy(rightType.node, DummyOrigin(source, node));
       bool notEqual = operatorType == TokenType.BANG_EQ;
-      _flowAnalysis.equalityOp_end(node, rightOperand, notEqual: notEqual);
+      _flowAnalysis.equalityOp_end(node, rightOperand, rightType,
+          notEqual: notEqual);
 
       void buildNullConditionInfo(NullLiteral nullLiteral,
           Expression otherOperand, NullabilityNode otherNode) {
diff --git a/pkg/vm_service/test/async_single_step_exception_test.dart b/pkg/vm_service/test/async_single_step_exception_test.dart
index 59c4a209..189196e 100644
--- a/pkg/vm_service/test/async_single_step_exception_test.dart
+++ b/pkg/vm_service/test/async_single_step_exception_test.dart
@@ -45,12 +45,6 @@
   stoppedAtLine(LINE_D), // await helper
   stepInto,
 
-  ...ifLazyAsyncStacks(<IsolateTest>[
-    hasStoppedAtBreakpoint,
-    stoppedAtLine(19), // helper() async { ... }
-    stepInto,
-  ]),
-
   hasStoppedAtBreakpoint,
   stoppedAtLine(LINE_A), // print helper
   smartNext,
diff --git a/pkg/vm_service/test/async_single_step_into_test.dart b/pkg/vm_service/test/async_single_step_into_test.dart
index 8f7373f..90be6df 100644
--- a/pkg/vm_service/test/async_single_step_into_test.dart
+++ b/pkg/vm_service/test/async_single_step_into_test.dart
@@ -34,12 +34,6 @@
   stoppedAtLine(LINE_D),
   stepInto,
 
-  ...ifLazyAsyncStacks(<IsolateTest>[
-    hasStoppedAtBreakpoint,
-    stoppedAtLine(16), // helper() async { ... }
-    stepInto,
-  ]),
-
   hasStoppedAtBreakpoint,
   stoppedAtLine(LINE_A),
   stepOver, // print.
diff --git a/pkg/vm_service/test/async_single_step_out_test.dart b/pkg/vm_service/test/async_single_step_out_test.dart
index 69ed577..fe8baed 100644
--- a/pkg/vm_service/test/async_single_step_out_test.dart
+++ b/pkg/vm_service/test/async_single_step_out_test.dart
@@ -35,12 +35,6 @@
   stoppedAtLine(LINE_D), // await helper
   stepInto,
 
-  ...ifLazyAsyncStacks(<IsolateTest>[
-    hasStoppedAtBreakpoint,
-    stoppedAtLine(17), // helper() async { ... }
-    stepInto,
-  ]),
-
   hasStoppedAtBreakpoint,
   stoppedAtLine(LINE_A), // print.
   stepOver,
diff --git a/pkg/vm_service/test/async_star_single_step_into_test.dart b/pkg/vm_service/test/async_star_single_step_into_test.dart
index 179b03d..061c2fd 100644
--- a/pkg/vm_service/test/async_star_single_step_into_test.dart
+++ b/pkg/vm_service/test/async_star_single_step_into_test.dart
@@ -45,12 +45,6 @@
   stoppedAtLine(LINE_F),
   stepInto,
 
-  ...ifLazyAsyncStacks(<IsolateTest>[
-    hasStoppedAtBreakpoint,
-    stoppedAtLine(23), // helper() async { ... }
-    stepInto,
-  ]),
-
   hasStoppedAtBreakpoint,
   stoppedAtLine(LINE_C),
   stepOver, // print.
@@ -58,12 +52,6 @@
   hasStoppedAtBreakpoint,
   stepInto,
 
-  ...ifLazyAsyncStacks(<IsolateTest>[
-    hasStoppedAtBreakpoint,
-    stoppedAtLine(26), // await for (...) { ... }
-    stepInto,
-  ]),
-
   hasStoppedAtBreakpoint,
   stoppedAtLine(LINE_A),
   // Resume here to exit the generator function.
diff --git a/pkg/vm_service/test/async_star_step_out_test.dart b/pkg/vm_service/test/async_star_step_out_test.dart
index 76e8e86..6e4cde9 100644
--- a/pkg/vm_service/test/async_star_step_out_test.dart
+++ b/pkg/vm_service/test/async_star_step_out_test.dart
@@ -49,12 +49,6 @@
   stoppedAtLine(LINE_F),
   stepInto,
 
-  ...ifLazyAsyncStacks(<IsolateTest>[
-    hasStoppedAtBreakpoint,
-    stoppedAtLine(26), // helper() async { ... }
-    stepInto,
-  ]),
-
   hasStoppedAtBreakpoint,
   stoppedAtLine(LINE_C),
   stepOver, // print.
@@ -62,12 +56,6 @@
   hasStoppedAtBreakpoint,
   stepInto,
 
-  ...ifLazyAsyncStacks(<IsolateTest>[
-    hasStoppedAtBreakpoint,
-    stoppedAtLine(29), // await for (...) {}
-    stepInto,
-  ]),
-
   hasStoppedAtBreakpoint,
   stoppedAtLine(LINE_A),
   stepOut, // step out of generator.
diff --git a/pkg/vm_service/test/async_step_out_test.dart b/pkg/vm_service/test/async_step_out_test.dart
index 8bbc4c8..3ccfb1d 100644
--- a/pkg/vm_service/test/async_step_out_test.dart
+++ b/pkg/vm_service/test/async_step_out_test.dart
@@ -37,12 +37,6 @@
   stoppedAtLine(LINE_E),
   stepInto,
 
-  ...ifLazyAsyncStacks(<IsolateTest>[
-    hasStoppedAtBreakpoint,
-    stoppedAtLine(18), // helper() async { ... }
-    stepInto,
-  ]),
-
   hasStoppedAtBreakpoint,
   stoppedAtLine(LINE_A),
   asyncNext,
diff --git a/pkg/vm_service/test/common/test_helper.dart b/pkg/vm_service/test/common/test_helper.dart
index f226cc0..1b19ba1 100644
--- a/pkg/vm_service/test/common/test_helper.dart
+++ b/pkg/vm_service/test/common/test_helper.dart
@@ -22,11 +22,6 @@
     ? ['--causal-async-stacks', '--no-lazy-async-stacks']
     : ['--no-causal-async-stacks', '--lazy-async-stacks'];
 
-List<IsolateTest> ifLazyAsyncStacks(List<IsolateTest> lazyTests) {
-  if (useCausalAsyncStacks) return const <IsolateTest>[];
-  return lazyTests;
-}
-
 /// Will be set to the http address of the VM's service protocol before
 /// any tests are invoked.
 String serviceHttpAddress;
@@ -222,13 +217,13 @@
           first = false;
           print('** Signaled to run test queries on $uri');
         }
-        print('>testee>out> $line');
+        stdout.write('>testee>out> ${line}\n');
       });
       process.stderr
           .transform(utf8.decoder)
           .transform(LineSplitter())
           .listen((line) {
-        print('>testee>err> $line');
+        stdout.write('>testee>err> ${line}\n');
       });
       process.exitCode.then((exitCode) {
         if ((exitCode != 0) && !killedByTester) {
diff --git a/runtime/bin/ffi_test/ffi_test_functions.cc b/runtime/bin/ffi_test/ffi_test_functions.cc
index 1d7082e..3b915c0 100644
--- a/runtime/bin/ffi_test/ffi_test_functions.cc
+++ b/runtime/bin/ffi_test/ffi_test_functions.cc
@@ -1038,4 +1038,8 @@
   p2[0] = 42;
 }
 
+DART_EXPORT int32_t PassStruct(void*) {
+  return 42;
+}
+
 }  // namespace dart
diff --git a/runtime/observatory/tests/service/async_single_step_exception_test.dart b/runtime/observatory/tests/service/async_single_step_exception_test.dart
index 6393d32..fdc490e 100644
--- a/runtime/observatory/tests/service/async_single_step_exception_test.dart
+++ b/runtime/observatory/tests/service/async_single_step_exception_test.dart
@@ -46,12 +46,6 @@
   stoppedAtLine(LINE_D), // await helper
   stepInto,
 
-  ...ifLazyAsyncStacks(<IsolateTest>[
-    hasStoppedAtBreakpoint,
-    stoppedAtLine(19), // helper() async { ... }
-    stepInto,
-  ]),
-
   hasStoppedAtBreakpoint,
   stoppedAtLine(LINE_A), // print helper
   smartNext,
diff --git a/runtime/observatory/tests/service/async_single_step_into_test.dart b/runtime/observatory/tests/service/async_single_step_into_test.dart
index 2f67565..8d8417f 100644
--- a/runtime/observatory/tests/service/async_single_step_into_test.dart
+++ b/runtime/observatory/tests/service/async_single_step_into_test.dart
@@ -34,12 +34,6 @@
   stoppedAtLine(LINE_D),
   stepInto,
 
-  ...ifLazyAsyncStacks(<IsolateTest>[
-    hasStoppedAtBreakpoint,
-    stoppedAtLine(16),
-    stepInto, // helper() async { ... }
-  ]),
-
   hasStoppedAtBreakpoint,
   stoppedAtLine(LINE_A),
   stepOver, // print.
diff --git a/runtime/observatory/tests/service/async_single_step_out_test.dart b/runtime/observatory/tests/service/async_single_step_out_test.dart
index f5ba1d6..2b51e24 100644
--- a/runtime/observatory/tests/service/async_single_step_out_test.dart
+++ b/runtime/observatory/tests/service/async_single_step_out_test.dart
@@ -35,12 +35,6 @@
   stoppedAtLine(LINE_D), // await helper
   stepInto,
 
-  ...ifLazyAsyncStacks(<IsolateTest>[
-    hasStoppedAtBreakpoint,
-    stoppedAtLine(17), // helper() async {}
-    stepInto,
-  ]),
-
   hasStoppedAtBreakpoint,
   stoppedAtLine(LINE_A), // print.
   stepOver,
@@ -57,7 +51,7 @@
   stoppedAtLine(25), // await helper (weird dispatching)
   smartNext,
 
-  hasStoppedAtBreakpoint, //19
+  hasStoppedAtBreakpoint,
   stoppedAtLine(LINE_E), // arrive after the await.
   resumeIsolate
 ];
diff --git a/runtime/observatory/tests/service/async_star_single_step_into_test.dart b/runtime/observatory/tests/service/async_star_single_step_into_test.dart
index 3a55fa0..65a784d 100644
--- a/runtime/observatory/tests/service/async_star_single_step_into_test.dart
+++ b/runtime/observatory/tests/service/async_star_single_step_into_test.dart
@@ -44,22 +44,10 @@
   stoppedAtLine(LINE_F),
   stepInto,
 
-  ...ifLazyAsyncStacks(<IsolateTest>[
-    hasStoppedAtBreakpoint,
-    stoppedAtLine(23), // helper() async { ... }
-    stepInto,
-  ]),
-
   hasStoppedAtBreakpoint,
   stoppedAtLine(LINE_C),
   stepOver, // print.
 
-  ...ifLazyAsyncStacks(<IsolateTest>[
-    hasStoppedAtBreakpoint,
-    stoppedAtLine(25), // await for ...
-    stepInto,
-  ]),
-
   hasStoppedAtBreakpoint,
   stepInto,
 
diff --git a/runtime/observatory/tests/service/async_star_step_out_test.dart b/runtime/observatory/tests/service/async_star_step_out_test.dart
index 4f44917..fca9d16 100644
--- a/runtime/observatory/tests/service/async_star_step_out_test.dart
+++ b/runtime/observatory/tests/service/async_star_step_out_test.dart
@@ -48,12 +48,6 @@
   stoppedAtLine(LINE_F),
   stepInto,
 
-  ...ifLazyAsyncStacks(<IsolateTest>[
-    hasStoppedAtBreakpoint,
-    stoppedAtLine(26), // helper() async {}
-    stepInto,
-  ]),
-
   hasStoppedAtBreakpoint,
   stoppedAtLine(LINE_C),
   stepOver, // print.
@@ -61,12 +55,6 @@
   hasStoppedAtBreakpoint,
   stepInto,
 
-  ...ifLazyAsyncStacks(<IsolateTest>[
-    hasStoppedAtBreakpoint,
-    stoppedAtLine(28), // await for ...
-    stepInto,
-  ]),
-
   hasStoppedAtBreakpoint,
   stoppedAtLine(LINE_A),
   stepOut, // step out of generator.
diff --git a/runtime/observatory/tests/service/async_step_out_test.dart b/runtime/observatory/tests/service/async_step_out_test.dart
index f581cca..f22f8d8 100644
--- a/runtime/observatory/tests/service/async_step_out_test.dart
+++ b/runtime/observatory/tests/service/async_step_out_test.dart
@@ -37,12 +37,6 @@
   stoppedAtLine(LINE_E),
   stepInto,
 
-  ...ifLazyAsyncStacks(<IsolateTest>[
-    hasStoppedAtBreakpoint,
-    stoppedAtLine(18), // helper() async { ... }
-    stepInto,
-  ]),
-
   hasStoppedAtBreakpoint,
   stoppedAtLine(LINE_A),
   asyncNext,
diff --git a/runtime/observatory/tests/service/test_helper.dart b/runtime/observatory/tests/service/test_helper.dart
index 6b9bb3b..ecf4736 100644
--- a/runtime/observatory/tests/service/test_helper.dart
+++ b/runtime/observatory/tests/service/test_helper.dart
@@ -25,11 +25,6 @@
     ? const ['--causal-async-stacks', '--no-lazy-async-stacks']
     : const ['--no-causal-async-stacks', '--lazy-async-stacks'];
 
-List<IsolateTest> ifLazyAsyncStacks(List<IsolateTest> lazyTests) {
-  if (useCausalAsyncStacks) return const <IsolateTest>[];
-  return lazyTests;
-}
-
 /// Will be set to the http address of the VM's service protocol before
 /// any tests are invoked.
 String serviceHttpAddress;
@@ -286,7 +281,7 @@
           .transform(utf8.decoder)
           .transform(new LineSplitter())
           .listen((line) {
-        print('>testee>err> $line');
+        print('>testee>err> ${line.trim()}');
       });
       process.exitCode.then((exitCode) async {
         await serviceInfoDir.delete(recursive: true);
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
index 01bade0..2c505b8 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
@@ -4182,7 +4182,7 @@
   Fragment otherwise_fragment(otherwise);
   otherwise_fragment += IntConstant(condition_start_offset.Pos());
   otherwise_fragment += IntConstant(condition_end_offset.Pos());
-  Tag tag = ReadTag();                   // read (first part of) message.
+  Tag tag = ReadTag();  // read (first part of) message.
   if (tag == kSomething) {
     otherwise_fragment += BuildExpression();  // read (rest of) message.
   } else {
@@ -4748,8 +4748,8 @@
                                         needs_stacktrace, is_synthetic);
   // Fill in the body of the catch.
   for (intptr_t i = 0; i < catch_count; ++i) {
-    intptr_t catch_offset = ReaderOffset();   // Catch has no tag.
-    TokenPosition position = ReadPosition();  // read position.
+    intptr_t catch_offset = ReaderOffset();          // Catch has no tag.
+    TokenPosition position = ReadPosition();         // read position.
     const AbstractType& type_guard = T.BuildType();  // read guard.
     handler_types.SetAt(i, type_guard);
 
@@ -5269,6 +5269,15 @@
       Function::ZoneHandle(Z, compiler::ffi::NativeCallbackFunction(
                                   native_sig, target, exceptional_return));
   code += Constant(result);
+
+  auto& ffi_callback_functions = GrowableObjectArray::Handle(Z);
+  ffi_callback_functions ^= I->object_store()->ffi_callback_functions();
+  if (ffi_callback_functions.IsNull()) {
+    ffi_callback_functions ^= GrowableObjectArray::New();
+    I->object_store()->set_ffi_callback_functions(ffi_callback_functions);
+  }
+  ffi_callback_functions.Add(result);
+
   return code;
 }
 
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index eaa2fbd..3669dc2 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -2207,6 +2207,8 @@
   class StackTrace& async_stack_trace = StackTrace::Handle(zone);
   Array& async_code_array = Array::Handle(zone);
   Array& async_pc_offset_array = Array::Handle(zone);
+
+  // Extract the eagerly recorded async stack from the current thread.
   StackTraceUtils::ExtractAsyncStackTraceInfo(
       thread, &async_function, &async_stack_trace, &async_code_array,
       &async_pc_offset_array);
@@ -3724,6 +3726,16 @@
   return bpt_location->AddPerClosure(this, closure, for_over_await);
 }
 
+Breakpoint* Debugger::SetBreakpointAtAsyncOp(const Function& async_op) {
+  const Script& script = Script::Handle(async_op.script());
+  BreakpointLocation* bpt_location =
+      SetBreakpoint(script, async_op.token_pos(), async_op.end_token_pos(), -1,
+                    -1 /* no line/col */, async_op);
+  auto bpt = bpt_location->AddSingleShot(this);
+  bpt->set_is_synthetic_async(true);
+  return bpt;
+}
+
 Breakpoint* Debugger::BreakpointAtActivation(const Instance& closure) {
   if (!closure.IsClosure()) {
     return NULL;
@@ -4458,6 +4470,37 @@
   ActivationFrame* frame = TopDartFrame();
   ASSERT(frame != NULL);
 
+  // Since lazy async stacks doesn't use the _asyncStackTraceHelper runtime
+  // entry, we need to manually set a synthetic breakpoint for async_op before
+  // we enter it.
+  if (FLAG_lazy_async_stacks) {
+    // async and async* functions always contain synthetic async_ops.
+    if ((frame->function().IsAsyncFunction() ||
+         frame->function().IsAsyncGenerator())) {
+      ASSERT(!frame->GetSavedCurrentContext().IsNull());
+      ASSERT(frame->GetSavedCurrentContext().num_variables() >
+             Context::kAsyncCompleterIndex);
+
+      const Object& jump_var = Object::Handle(
+          frame->GetSavedCurrentContext().At(Context::kAsyncCompleterIndex));
+
+      // Only set breakpoint when entering async_op the first time.
+      // :async_completer_var should be uninitialised at this point:
+      if (jump_var.IsNull()) {
+        const Function& async_op =
+            Function::Handle(frame->function().GetGeneratedClosure());
+        if (!async_op.IsNull()) {
+          SetBreakpointAtAsyncOp(async_op);
+          // After setting the breakpoint we stop stepping and continue the
+          // debugger until the next breakpoint, to step over all the
+          // synthetic code.
+          Continue();
+          return Error::null();
+        }
+      }
+    }
+  }
+
   if (FLAG_async_debugger) {
     if ((async_stepping_fp_ != 0) && (top_frame_awaiter_ != Object::null())) {
       // Check if the user has single stepped out of an async function with
diff --git a/runtime/vm/debugger.h b/runtime/vm/debugger.h
index 881e492..ed3760d 100644
--- a/runtime/vm/debugger.h
+++ b/runtime/vm/debugger.h
@@ -519,6 +519,10 @@
                                      intptr_t line_number,
                                      intptr_t column_number);
 
+  // Sets synthetic breakpoint at async_op to step over the synthetic part of
+  // the stack trace.
+  Breakpoint* SetBreakpointAtAsyncOp(const Function& async_op);
+
   BreakpointLocation* BreakpointLocationAtLineCol(const String& script_url,
                                                   intptr_t line_number,
                                                   intptr_t column_number);
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index c413708..20c9883 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -6969,6 +6969,26 @@
   }
 }
 
+FunctionPtr Function::GetGeneratedClosure() const {
+  const auto& closure_functions = GrowableObjectArray::Handle(
+      Isolate::Current()->object_store()->closure_functions());
+  auto& entry = Object::Handle();
+
+  for (auto i = (closure_functions.Length() - 1); i >= 0; i--) {
+    entry = closure_functions.At(i);
+
+    ASSERT(entry.IsFunction());
+
+    const auto& closure_function = Function::Cast(entry);
+    if (closure_function.parent_function() == raw() &&
+        closure_function.is_generated_body()) {
+      return closure_function.raw();
+    }
+  }
+
+  return Function::null();
+}
+
 // Enclosing outermost function of this local function.
 FunctionPtr Function::GetOutermostFunction() const {
   FunctionPtr parent = parent_function();
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index cc26637..533eb68 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -2746,6 +2746,11 @@
   // Enclosing function of this local function.
   FunctionPtr parent_function() const;
 
+  // Enclosed generated closure function of this local function.
+  // This will only work after the closure function has been allocated in the
+  // isolate's object_store.
+  FunctionPtr GetGeneratedClosure() const;
+
   // Enclosing outermost function of this local function.
   FunctionPtr GetOutermostFunction() const;
 
diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h
index 7f3c93e..52c75ed 100644
--- a/runtime/vm/object_store.h
+++ b/runtime/vm/object_store.h
@@ -216,6 +216,7 @@
   RW(Array, dispatch_table_code_entries)                                       \
   RW(GrowableObjectArray, code_order_tables)                                   \
   RW(Array, obfuscation_map)                                                   \
+  RW(GrowableObjectArray, ffi_callback_functions)                              \
   RW(Class, ffi_pointer_class)                                                 \
   RW(Class, ffi_native_type_class)                                             \
   RW(Class, ffi_struct_class)                                                  \
diff --git a/runtime/vm/program_visitor.cc b/runtime/vm/program_visitor.cc
index b5f73c3..fe04547 100644
--- a/runtime/vm/program_visitor.cc
+++ b/runtime/vm/program_visitor.cc
@@ -261,6 +261,16 @@
       walker.AddToWorklist(function);
       ASSERT(!function.HasImplicitClosureFunction());
     }
+    // TODO(dartbug.com/43049): Use a more general solution and remove manual
+    // tracking through object_store->ffi_callback_functions.
+    const auto& ffi_callback_entries = GrowableObjectArray::Handle(
+        zone, object_store->ffi_callback_functions());
+    if (!ffi_callback_entries.IsNull()) {
+      for (intptr_t i = 0; i < ffi_callback_entries.Length(); i++) {
+        function ^= ffi_callback_entries.At(i);
+        walker.AddToWorklist(function);
+      }
+    }
   }
 
   if (visitor->IsCodeVisitor()) {
@@ -382,7 +392,7 @@
         // directly.
         //
         // In precompiled mode, the binder runs after tree shaking, during which
-        // all targets have been compiled, and so the binder replace all static
+        // all targets have been compiled, and so the binder replaces all static
         // calls with direct calls to the target.
         //
         // Cf. runtime entry PatchStaticCall called from CallStaticFunction
diff --git a/runtime/vm/stack_trace.cc b/runtime/vm/stack_trace.cc
index 468edfc..2ea19b7 100644
--- a/runtime/vm/stack_trace.cc
+++ b/runtime/vm/stack_trace.cc
@@ -395,6 +395,7 @@
   CallerClosureFinder caller_closure_finder(zone);
   auto& pc_descs = PcDescriptors::Handle();
 
+  // Start by traversing the sync. part of the stack.
   for (; frame != nullptr; frame = frames.NextFrame()) {
     if (skip_frames > 0) {
       skip_frames--;
@@ -461,6 +462,7 @@
       // Skip: Already handled this frame's function above.
       closure = caller_closure_finder.FindCaller(closure);
 
+      // Traverse the trail of async futures all the way up.
       for (; !closure.IsNull();
            closure = caller_closure_finder.FindCaller(closure)) {
         function = closure.function();
diff --git a/tests/co19/co19-co19.status b/tests/co19/co19-co19.status
index f4ff221..3934f21 100644
--- a/tests/co19/co19-co19.status
+++ b/tests/co19/co19-co19.status
@@ -114,11 +114,6 @@
 LibTest/isolate/RawReceivePort/*: Skip # Not migrated to NNBD
 LibTest/isolate/ReceivePort/*: Skip # Not migrated to NNBD
 LibTest/isolate/SendPort/*: Skip # Not migrated to NNBD
-LibTest/math/*: Skip # Not migrated to NNBD
-LibTest/math/MutableRectangle/*: Skip # Not migrated to NNBD
-LibTest/math/Point/*: Skip # Not migrated to NNBD
-LibTest/math/Random/*: Skip # Not migrated to NNBD
-LibTest/math/Rectangle/*: Skip # Not migrated to NNBD
 LibTest/mirrors/*: Skip # Not migrated to NNBD
 LibTest/typed_data/*: Skip # Not migrated to NNBD
 LibTest/typed_data/ByteBuffer/*: Skip # Not migrated to NNBD
diff --git a/tests/ffi/function_callbacks_test.dart b/tests/ffi/function_callbacks_test.dart
index 24ca064..2b12a98 100644
--- a/tests/ffi/function_callbacks_test.dart
+++ b/tests/ffi/function_callbacks_test.dart
@@ -12,6 +12,7 @@
 // VMOptions=--use-slow-path --enable-testing-pragmas --stacktrace-every=100
 // VMOptions=--use-slow-path --enable-testing-pragmas --write-protect-code --no-dual-map-code
 // VMOptions=--use-slow-path --enable-testing-pragmas --write-protect-code --no-dual-map-code --stacktrace-every=100
+// VMOptions=--use-bare-instructions=false
 // SharedObjects=ffi_test_functions
 
 import 'dart:ffi';
diff --git a/tests/ffi/regress_43016_test.dart b/tests/ffi/regress_43016_test.dart
new file mode 100644
index 0000000..bb134bf
--- /dev/null
+++ b/tests/ffi/regress_43016_test.dart
@@ -0,0 +1,32 @@
+// 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.
+
+// VMOptions=--optimization-counter-threshold=5
+
+import 'dart:ffi';
+
+import 'dylib_utils.dart';
+
+class MyStruct extends Struct {}
+
+typedef _c_pass_struct = Int32 Function(Pointer<MyStruct>);
+
+typedef _dart_pass_struct = int Function(Pointer<MyStruct>);
+
+int pass_struct(Pointer<MyStruct> arg0) {
+  _pass_struct ??= ffiTestFunctions
+      .lookupFunction<_c_pass_struct, _dart_pass_struct>('PassStruct');
+  return _pass_struct!.call(arg0);
+}
+
+_dart_pass_struct? _pass_struct;
+
+final ffiTestFunctions = dlopenPlatformSpecific("ffi_test_functions");
+
+void main() {
+  // Trigger both the runtime entry and the IL in bytecode.
+  for (int i = 0; i < 10000; i++) {
+    pass_struct(nullptr);
+  }
+}
diff --git a/tests/ffi_2/function_callbacks_test.dart b/tests/ffi_2/function_callbacks_test.dart
index 24ca064..2b12a98 100644
--- a/tests/ffi_2/function_callbacks_test.dart
+++ b/tests/ffi_2/function_callbacks_test.dart
@@ -12,6 +12,7 @@
 // VMOptions=--use-slow-path --enable-testing-pragmas --stacktrace-every=100
 // VMOptions=--use-slow-path --enable-testing-pragmas --write-protect-code --no-dual-map-code
 // VMOptions=--use-slow-path --enable-testing-pragmas --write-protect-code --no-dual-map-code --stacktrace-every=100
+// VMOptions=--use-bare-instructions=false
 // SharedObjects=ffi_test_functions
 
 import 'dart:ffi';
diff --git a/tests/ffi_2/regress_43016_test.dart b/tests/ffi_2/regress_43016_test.dart
new file mode 100644
index 0000000..005b1df
--- /dev/null
+++ b/tests/ffi_2/regress_43016_test.dart
@@ -0,0 +1,32 @@
+// 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.
+
+// VMOptions=--optimization-counter-threshold=5
+
+import 'dart:ffi';
+
+import 'dylib_utils.dart';
+
+class MyStruct extends Struct {}
+
+typedef _c_pass_struct = Int32 Function(Pointer<MyStruct> arg0);
+
+typedef _dart_pass_struct = int Function(Pointer<MyStruct> arg0);
+
+int pass_struct(Pointer<MyStruct> arg0) {
+  _pass_struct ??= ffiTestFunctions
+      .lookupFunction<_c_pass_struct, _dart_pass_struct>('PassStruct');
+  return _pass_struct(arg0);
+}
+
+_dart_pass_struct _pass_struct;
+
+final ffiTestFunctions = dlopenPlatformSpecific("ffi_test_functions");
+
+void main() {
+  // Trigger both the runtime entry and the IL in bytecode.
+  for (int i = 0; i < 10000; i++) {
+    pass_struct(nullptr);
+  }
+}
diff --git a/tests/language/nnbd/type_promotion/assignment_inference_after_null_check_test.dart b/tests/language/nnbd/type_promotion/assignment_inference_after_null_check_test.dart
new file mode 100644
index 0000000..220bfbe
--- /dev/null
+++ b/tests/language/nnbd/type_promotion/assignment_inference_after_null_check_test.dart
@@ -0,0 +1,25 @@
+// 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.
+
+// The reason that `if (x == null)` doesn't promote x's type to `Null` is
+// because we lose type argument information that would be necessary for
+// inference.  This test makes sure that the type argument information is
+// appropriately preserved.
+
+// SharedOptions=--enable-experiment=non-nullable
+
+void f(List<int>? x) {
+  if (x == null) {
+    // If x were promoted to `Null`, inference would not know that `[]` should
+    // be considered to mean `<int>[]`, so either the line below would be a
+    // compile-time error, or a runtime error would occur later when we try to
+    // add an int to the list.
+    x = [];
+  }
+  x.add(0);
+}
+
+main() {
+  f(null);
+}
diff --git a/tests/language/nnbd/type_promotion/null_type_insufficient_for_equals_null_check_error_test.dart b/tests/language/nnbd/type_promotion/null_type_insufficient_for_equals_null_check_error_test.dart
new file mode 100644
index 0000000..30e882f
--- /dev/null
+++ b/tests/language/nnbd/type_promotion/null_type_insufficient_for_equals_null_check_error_test.dart
@@ -0,0 +1,61 @@
+// 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.
+
+// Given an expression E having type `Null`, the reason that `if (x != E)`
+// doesn't promote x's type to non-nullable is because evaluation of the
+// expression may change the value of `x`.  (Consider, for example, if E is the
+// expression `(x = null)`).  This test demonstrates the problem with `(x =
+// null)` and checks a few other cases.
+
+// SharedOptions=--enable-experiment=non-nullable
+
+void assignNullRhs(int? x) {
+  if (x != (x = null)) {
+    x.isEven;
+//  ^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+    //^
+    // [cfe] Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
+  }
+}
+
+void assignNullLhs(int? x) {
+  // In theory it would be sound to promote x in this case, because the
+  // assignment happens before the RHS is evaluated, but we prefer not to
+  // promote in order to be consistent with the `assignNullRhs` case.
+  if ((x = null) != x) {
+    x.isEven;
+//  ^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+    //^
+    // [cfe] Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
+  }
+}
+
+void unrelatedVarRhs(int? x, Null n) {
+  if (x != n) {
+    x.isEven;
+//  ^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+    //^
+    // [cfe] Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
+  }
+}
+
+void unrelatedVarLhs(int? x, Null n) {
+  if (n != x) {
+    x.isEven;
+//  ^
+// [analyzer] COMPILE_TIME_ERROR.UNCHECKED_USE_OF_NULLABLE_VALUE
+    //^
+    // [cfe] Property 'isEven' cannot be accessed on 'int?' because it is potentially null.
+  }
+}
+
+main() {
+  assignNullRhs(0);
+  assignNullLhs(0);
+  unrelatedVarLhs(0, null);
+  unrelatedVarRhs(0, null);
+}
diff --git a/tools/VERSION b/tools/VERSION
index 956d8fc..46dd6f8 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 10
 PATCH 0
-PRERELEASE 28
+PRERELEASE 29
 PRERELEASE_PATCH 0
\ No newline at end of file