Version 2.11.0-157.0.dev

Merge commit 'd966206c6defa2b52be74642318c780283f24bfb' into 'dev'
diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json
index 12e1c33..5ef3143 100644
--- a/.dart_tool/package_config.json
+++ b/.dart_tool/package_config.json
@@ -11,7 +11,7 @@
     "constraint, update this by running tools/generate_package_config.dart."
   ],
   "configVersion": 2,
-  "generated": "2020-08-18T15:38:52.410101",
+  "generated": "2020-09-18T09:56:27.880444",
   "generator": "tools/generate_package_config.dart",
   "packages": [
     {
@@ -184,7 +184,7 @@
       "name": "dart2js_info",
       "rootUri": "../third_party/pkg/dart2js_info",
       "packageUri": "lib/",
-      "languageVersion": "2.0"
+      "languageVersion": "2.3"
     },
     {
       "name": "dart2js_tools",
@@ -207,8 +207,7 @@
     {
       "name": "dart_style",
       "rootUri": "../third_party/pkg_tested/dart_style",
-      "packageUri": "lib/",
-      "languageVersion": "2.7"
+      "packageUri": "lib/"
     },
     {
       "name": "dartdev",
@@ -348,8 +347,7 @@
     {
       "name": "js_runtime",
       "rootUri": "../sdk/lib/_internal/js_runtime",
-      "packageUri": "lib/",
-      "languageVersion": "2.10"
+      "packageUri": "lib/"
     },
     {
       "name": "json_rpc_2",
@@ -426,7 +424,7 @@
       "name": "native_stack_traces",
       "rootUri": "../pkg/native_stack_traces",
       "packageUri": "lib/",
-      "languageVersion": "2.8"
+      "languageVersion": "2.10"
     },
     {
       "name": "nnbd_migration",
@@ -484,8 +482,7 @@
     {
       "name": "pub",
       "rootUri": "../third_party/pkg/pub",
-      "packageUri": "lib/",
-      "languageVersion": "2.3"
+      "packageUri": "lib/"
     },
     {
       "name": "pub_semver",
@@ -508,8 +505,7 @@
     {
       "name": "sdk_library_metadata",
       "rootUri": "../sdk/lib/_internal/sdk_library_metadata",
-      "packageUri": "lib/",
-      "languageVersion": "2.10"
+      "packageUri": "lib/"
     },
     {
       "name": "shelf",
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 643c771..9d443f4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,12 @@
 
 ### Tools
 
+#### Dartanalyzer
+
+* Removed the `--use-fasta-parser`, `--preview-dart-2`, and
+  `--enable-assert-initializers` command line options. These options haven't
+  been supported in a while and were no-ops.
+
 #### Linter
 
 Updated the Linter to `0.1.119`, which includes:
@@ -55,7 +61,7 @@
     deferred loading of types, pass `--no-defer-class-types`. See the original
     post on the [unsoundness in the deferred loading algorithm][].
 *   Enables a new sound deferred splitting algorithm. To explicitly disable
-    the new deferred splitting algorithm, pass `--no-new-deferred-split'.
+    the new deferred splitting algorithm, pass `--no-new-deferred-split`.
     See the original post on the
     [unsoundness in the deferred loading algorithm][].
 
diff --git a/DEPS b/DEPS
index c6af26a..9000961 100644
--- a/DEPS
+++ b/DEPS
@@ -44,7 +44,7 @@
   # 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": "b7660861df12eb489243a591e45f251f8cf8c4a8",
+  "co19_rev": "da33ec472443aa14d969bf54b9adc3af71cb6382",
   "co19_2_rev": "e48b3090826cf40b8037648f19d211e8eab1b4b6",
 
   # The internal benchmarks to use. See go/dart-benchmarks-internal
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 df90a5f..c2f43d8 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
@@ -609,6 +609,11 @@
   void parenthesizedExpression(
       Expression outerExpression, Expression innerExpression);
 
+  /// Attempt to promote [variable] to [type].  The client may use this to
+  /// ensure that a variable declaration of the form `var x = expr;` promotes
+  /// `x` to type `X&T` in the circumstance where the type of `expr` is `X&T`.
+  void promote(Variable variable, Type type);
+
   /// Retrieves the type that the [variable] is promoted to, if the [variable]
   /// is currently promoted.  Otherwise returns `null`.
   Type promotedType(Variable variable);
@@ -749,7 +754,12 @@
 
   /// Register write of the given [variable] in the current state.
   /// [writtenType] should be the type of the value that was written.
-  void write(Variable variable, Type writtenType);
+  ///
+  /// This should also be used for the implicit write to a non-final variable in
+  /// its initializer, to ensure that the type is promoted to non-nullable if
+  /// necessary; in this case, [viaInitializer] should be `true`.
+  void write(Variable variable, Type writtenType,
+      {bool viaInitializer = false});
 }
 
 /// Alternate implementation of [FlowAnalysis] that prints out inputs and output
@@ -1055,6 +1065,11 @@
   }
 
   @override
+  void promote(Variable variable, Type type) {
+    _wrap('promote($variable, $type', () => _wrapped.promote(variable, type));
+  }
+
+  @override
   Type promotedType(Variable variable) {
     return _wrap(
         'promotedType($variable)', () => _wrapped.promotedType(variable),
@@ -1156,9 +1171,12 @@
   }
 
   @override
-  void write(Variable variable, Type writtenType) {
-    _wrap('write($variable, $writtenType)',
-        () => _wrapped.write(variable, writtenType));
+  void write(Variable variable, Type writtenType,
+      {bool viaInitializer = false}) {
+    _wrap(
+        'write($variable, $writtenType, viaInitializer: $viaInitializer)',
+        () => _wrapped.write(variable, writtenType,
+            viaInitializer: viaInitializer));
   }
 
   T _wrap<T>(String description, T callback(),
@@ -1770,11 +1788,6 @@
           List<Type> newPromotedTypes) =>
       false;
 
-  /// Return `true` if the [variable] is a local variable (not a formal
-  /// parameter), and it has no declared type (no explicit type, and not
-  /// initializer).
-  bool isLocalVariableWithoutDeclaredType(Variable variable);
-
   /// Determines whether the given [type] is equivalent to the `Never` type.
   ///
   /// A type is equivalent to `Never` if it:
@@ -1985,11 +1998,6 @@
           promotedTypes, tested, true, false, writeCaptured);
     }
 
-    if (_isPromotableViaInitialization(typeOperations, variable)) {
-      return new VariableModel<Variable, Type>(
-          [writtenType], tested, true, false, writeCaptured);
-    }
-
     List<Type> newPromotedTypes = _demoteViaAssignment(
       writtenType,
       typeOperations,
@@ -2041,26 +2049,6 @@
     }
   }
 
-  /// We say that a variable `x` is promotable via initialization given
-  /// variable model `VM` if `x` is a local variable (not a formal parameter)
-  /// and:
-  /// * VM = VariableModel(declared, promoted, tested,
-  ///                      assigned, unassigned, captured)
-  /// * and `captured` is false
-  /// * and `promoted` is empty
-  /// * and `x` is declared with no explicit type and no initializer
-  /// * and `assigned` is false and `unassigned` is true
-  bool _isPromotableViaInitialization<Variable>(
-    TypeOperations<Variable, Type> typeOperations,
-    Variable variable,
-  ) {
-    return !writeCaptured &&
-        !assigned &&
-        unassigned &&
-        promotedTypes == null &&
-        typeOperations.isLocalVariableWithoutDeclaredType(variable);
-  }
-
   /// Determines whether a variable with the given [promotedTypes] should be
   /// promoted to [writtenType] based on types of interest.  If it should,
   /// returns an updated promotion chain; otherwise returns [promotedTypes]
@@ -2903,6 +2891,12 @@
   }
 
   @override
+  void promote(Variable variable, Type type) {
+    _current =
+        _current.tryPromoteForTypeCheck(typeOperations, variable, type).ifTrue;
+  }
+
+  @override
   Type promotedType(Variable variable) {
     return _current.infoFor(variable).promotedTypes?.last;
   }
@@ -3055,11 +3049,14 @@
   }
 
   @override
-  void write(Variable variable, Type writtenType) {
-    assert(
-        _assignedVariables._anywhere._written.contains(variable),
-        "Variable is written to, but was not included in "
-        "_variablesWrittenAnywhere: $variable");
+  void write(Variable variable, Type writtenType,
+      {bool viaInitializer = false}) {
+    if (!viaInitializer) {
+      assert(
+          _assignedVariables._anywhere._written.contains(variable),
+          "Variable is written to, but was not included in "
+          "_variablesWrittenAnywhere: $variable");
+    }
     _current = _current.write(variable, writtenType, typeOperations);
   }
 
diff --git a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
index 0e4375a..2df01db 100644
--- a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
@@ -4013,6 +4013,32 @@
 }
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<
+    Message Function(
+        String
+            name)> templateFinalNotAssignedError = const Template<
+        Message Function(String name)>(
+    messageTemplate:
+        r"""Final variable '#name' must be assigned before it can be used.""",
+    withArguments: _withArgumentsFinalNotAssignedError);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(String name)> codeFinalNotAssignedError =
+    const Code<Message Function(String name)>(
+        "FinalNotAssignedError", templateFinalNotAssignedError,
+        analyzerCodes: <String>["READ_POTENTIALLY_UNASSIGNED_FINAL"]);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsFinalNotAssignedError(String name) {
+  if (name.isEmpty) throw 'No name provided';
+  name = demangleMixinApplicationName(name);
+  return new Message(codeFinalNotAssignedError,
+      message:
+          """Final variable '${name}' must be assigned before it can be used.""",
+      arguments: {'name': name});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Null> codeForInLoopExactlyOneVariable =
     messageForInLoopExactlyOneVariable;
 
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 92c7bae..86ce5d9 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
@@ -1443,6 +1443,54 @@
       });
     });
 
+    test('promote promotes to a subtype and sets type of interest', () {
+      var h = _Harness();
+      var x = h.addVar('x', 'num?');
+      h.assignedVariables((vars) {
+        vars.write(x);
+      });
+      h.run((flow) {
+        flow.declare(x, true);
+        expect(flow.promotedType(x), isNull);
+        flow.promote(x, _Type('num'));
+        expect(flow.promotedType(x).type, 'num');
+        // Check that it's a type of interest by promoting and de-promoting.
+        h.if_(h.isType(h.variableRead(x), 'int'), () {
+          expect(flow.promotedType(x).type, 'int');
+          flow.write(x, _Type('num'));
+          expect(flow.promotedType(x).type, 'num');
+        });
+      });
+    });
+
+    test('promote does not promote to a non-subtype', () {
+      var h = _Harness();
+      var x = h.addVar('x', 'num?');
+      h.run((flow) {
+        flow.declare(x, true);
+        expect(flow.promotedType(x), isNull);
+        flow.promote(x, _Type('String'));
+        expect(flow.promotedType(x), isNull);
+      });
+    });
+
+    test('promote does not promote if variable is write-captured', () {
+      var h = _Harness();
+      var x = h.addVar('x', 'num?');
+      var functionNode = _Node();
+      h.assignedVariables(
+          (vars) => vars.function(functionNode, () => vars.write(x)));
+      h.run((flow) {
+        flow.declare(x, true);
+        expect(flow.promotedType(x), isNull);
+        flow.functionExpression_begin(functionNode);
+        flow.write(x, _Type('num'));
+        flow.functionExpression_end();
+        flow.promote(x, _Type('num'));
+        expect(flow.promotedType(x), isNull);
+      });
+    });
+
     test('promotedType handles not-yet-seen variables', () {
       // Note: this is needed for error recovery in the analyzer.
       var h = _Harness();
@@ -2658,21 +2706,6 @@
           });
         });
       });
-
-      test('promote via initialization', () {
-        var h = _Harness();
-        var x = _Var('x', null, isLocalVariableWithoutDeclaredType: true);
-
-        var s1 = FlowModel<_Var, _Type>(true).declare(x, false);
-        expect(s1.variableInfo, {
-          x: _matchVariableModel(chain: null),
-        });
-
-        var s2 = s1.write(x, _Type('int'), h);
-        expect(s2.variableInfo, {
-          x: _matchVariableModel(chain: ['int']),
-        });
-      });
     });
 
     group('demotion, to NonNull', () {
@@ -3790,11 +3823,6 @@
   }
 
   @override
-  bool isLocalVariableWithoutDeclaredType(_Var variable) {
-    return variable.isLocalVariableWithoutDeclaredType;
-  }
-
-  @override
   bool isNever(_Type type) {
     return type.type == 'Never';
   }
@@ -3956,13 +3984,8 @@
 class _Var {
   final String name;
   final _Type type;
-  final bool isLocalVariableWithoutDeclaredType;
 
-  _Var(
-    this.name,
-    this.type, {
-    this.isLocalVariableWithoutDeclaredType = false,
-  });
+  _Var(this.name, this.type);
 
   @override
   String toString() => '$type $name';
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/data/initialization.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/data/initialization.dart
index 6425744..3d890e8 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/data/initialization.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/data/initialization.dart
@@ -8,7 +8,7 @@
 localVariable() {
   var x;
   x = 1;
-  /*int*/ x;
+  x;
   x = 2.3;
   x;
 }
@@ -35,10 +35,10 @@
   var x;
   if (a) {
     x = 0;
-    /*int*/ x;
+    x;
   } else {
     x = 1.2;
-    /*double*/ x;
+    x;
   }
   x;
 }
@@ -47,12 +47,83 @@
   var x;
   if (a) {
     x = 0;
-    /*int*/ x;
+    x;
   } else {
     x = 1;
-    /*int*/ x;
+    x;
   }
-  /*int*/ x;
+  x;
+}
+
+localVariable_initialized_promoted_type_var<T>(T t) {
+  if (t is num) {
+    var x = /*T & num*/ t;
+    /*T & num*/ x;
+    // Check that it is a type of interest by promoting and then writing to it
+    if (/*T & num*/ x is int) {
+      /*T & int*/ x;
+      x = /*T & num*/ t;
+      /*T & num*/ x;
+    }
+  }
+}
+
+localVariable_initialized_unpromoted_type_var<T>(T t) {
+  var x = t;
+  x;
+  // Check that `T & Object` is a type of interest, by promoting and then
+  // writing to it
+  if (x is int && t is num) {
+    /*T & int*/ x;
+    x = /*T & num*/ t;
+    /*T & Object*/ x;
+  }
+}
+
+localVariable_initialized_unpromoted_type_var_with_bound<T extends num?>(T t) {
+  var x = t;
+  x;
+  // Check that `T & num` is a type of interest, by promoting and then writing
+  // to it
+  if (x is int && t is double) {
+    /*T & int*/ x;
+    x = /*T & double*/ t;
+    /*T & num*/ x;
+  }
+}
+
+localVariable_initialized_promoted_type_var_typed<T>(T t) {
+  if (t is num) {
+    // TODO(paulberry): This should promote to `T & Object`, because that's the
+    // non-nullable version of T, but it shouldn't promote to `T & num`.
+    T x = /*T & num*/ t;
+    x;
+    // Check that `T & Object` is a type of interest by promoting and then
+    // writing to it
+    if (x is int) {
+      /*T & int*/ x;
+      x = /*T & num*/ t;
+      /*T & Object*/ x;
+    }
+  }
+}
+
+localVariable_initialized_promoted_type_var_final<T>(T t) {
+  if (t is num) {
+    final x = /*T & num*/ t;
+    /*T & num*/ x;
+    // Note: it's not observable whether it's a type of interest because we
+    // can't write to it again.
+  }
+}
+
+localVariable_initialized_promoted_type_var_final_typed<T>(T t) {
+  if (t is num) {
+    final T x = /*T & num*/ t;
+    x;
+    // Note: it's not observable whether it's a type of interest because we
+    // can't write to it again.
+  }
 }
 
 localVariable_notDefinitelyUnassigned(bool a) {
diff --git a/pkg/analysis_server/doc/api.html b/pkg/analysis_server/doc/api.html
index 8af47db..7514dc1 100644
--- a/pkg/analysis_server/doc/api.html
+++ b/pkg/analysis_server/doc/api.html
@@ -109,7 +109,7 @@
 <body>
 <h1>Analysis Server API Specification</h1>
 <h1 style="color:#999999">Version
-  1.29.0
+  1.29.1
 </h1>
 <p>
   This document contains a specification of the API provided by the
@@ -2267,6 +2267,13 @@
       Return the set of fixes that are available for the errors at
       a given offset in a given file.
     </p>
+    <p>
+      If a request is made for a file which does not exist, or
+      which is not currently subject to analysis (e.g. because it
+      is not associated with any analysis root specified to
+      analysis.setAnalysisRoots), an error of type
+      <tt>GET_FIXES_INVALID_FILE</tt> will be generated.
+    </p>
     
     
   <h4>parameters:</h4><dl><dt class="field"><b>file: <a href="#type_FilePath">FilePath</a></b></dt><dd>
@@ -5216,6 +5223,13 @@
           which does not match a file currently subject to
           analysis.
         </p>
+      </dd><dt class="value">GET_FIXES_INVALID_FILE</dt><dd>
+        
+        <p>
+          An "edit.getFixes" request specified a FilePath
+          which does not match a file currently subject to
+          analysis.
+        </p>
       </dd><dt class="value">GET_IMPORTED_ELEMENTS_INVALID_FILE</dt><dd>
         
         <p>
diff --git a/pkg/analysis_server/lib/protocol/protocol.dart b/pkg/analysis_server/lib/protocol/protocol.dart
index d45f7d3..53b008f 100644
--- a/pkg/analysis_server/lib/protocol/protocol.dart
+++ b/pkg/analysis_server/lib/protocol/protocol.dart
@@ -366,6 +366,13 @@
                 'Error during `analysis.getErrors`: invalid file.'));
 
   /// Initialize a newly created instance to represent the
+  /// GET_FIXES_INVALID_FILE error condition.
+  Response.getFixesInvalidFile(Request request)
+      : this(request.id,
+            error: RequestError(RequestErrorCode.GET_FIXES_INVALID_FILE,
+                'Error during `edit.getFixes`: invalid file.'));
+
+  /// Initialize a newly created instance to represent the
   /// GET_IMPORTED_ELEMENTS_INVALID_FILE error condition.
   Response.getImportedElementsInvalidFile(Request request)
       : this(request.id,
diff --git a/pkg/analysis_server/lib/protocol/protocol_constants.dart b/pkg/analysis_server/lib/protocol/protocol_constants.dart
index 8bfb877..76c886f 100644
--- a/pkg/analysis_server/lib/protocol/protocol_constants.dart
+++ b/pkg/analysis_server/lib/protocol/protocol_constants.dart
@@ -6,7 +6,7 @@
 // To regenerate the file, use the script
 // "pkg/analysis_server/tool/spec/generate_files".
 
-const String PROTOCOL_VERSION = '1.29.0';
+const String PROTOCOL_VERSION = '1.29.1';
 
 const String ANALYSIS_NOTIFICATION_ANALYZED_FILES = 'analysis.analyzedFiles';
 const String ANALYSIS_NOTIFICATION_ANALYZED_FILES_DIRECTORIES = 'directories';
diff --git a/pkg/analysis_server/lib/protocol/protocol_generated.dart b/pkg/analysis_server/lib/protocol/protocol_generated.dart
index 51ece87..06c3551 100644
--- a/pkg/analysis_server/lib/protocol/protocol_generated.dart
+++ b/pkg/analysis_server/lib/protocol/protocol_generated.dart
@@ -17810,6 +17810,7 @@
 ///   FORMAT_INVALID_FILE
 ///   FORMAT_WITH_ERRORS
 ///   GET_ERRORS_INVALID_FILE
+///   GET_FIXES_INVALID_FILE
 ///   GET_IMPORTED_ELEMENTS_INVALID_FILE
 ///   GET_KYTHE_ENTRIES_INVALID_FILE
 ///   GET_NAVIGATION_INVALID_FILE
@@ -17891,6 +17892,11 @@
   static const RequestErrorCode GET_ERRORS_INVALID_FILE =
       RequestErrorCode._('GET_ERRORS_INVALID_FILE');
 
+  /// An "edit.getFixes" request specified a FilePath which does not match a
+  /// file currently subject to analysis.
+  static const RequestErrorCode GET_FIXES_INVALID_FILE =
+      RequestErrorCode._('GET_FIXES_INVALID_FILE');
+
   /// An "analysis.getImportedElements" request specified a FilePath that does
   /// not match a file currently subject to analysis.
   static const RequestErrorCode GET_IMPORTED_ELEMENTS_INVALID_FILE =
@@ -18022,6 +18028,7 @@
     FORMAT_INVALID_FILE,
     FORMAT_WITH_ERRORS,
     GET_ERRORS_INVALID_FILE,
+    GET_FIXES_INVALID_FILE,
     GET_IMPORTED_ELEMENTS_INVALID_FILE,
     GET_KYTHE_ENTRIES_INVALID_FILE,
     GET_NAVIGATION_INVALID_FILE,
@@ -18076,6 +18083,8 @@
         return FORMAT_WITH_ERRORS;
       case 'GET_ERRORS_INVALID_FILE':
         return GET_ERRORS_INVALID_FILE;
+      case 'GET_FIXES_INVALID_FILE':
+        return GET_FIXES_INVALID_FILE;
       case 'GET_IMPORTED_ELEMENTS_INVALID_FILE':
         return GET_IMPORTED_ELEMENTS_INVALID_FILE;
       case 'GET_KYTHE_ENTRIES_INVALID_FILE':
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index 3e87f9c..2c9e1e4 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -639,9 +639,6 @@
   /// ML completion is enabled if this is non-null.
   String completionModelFolder;
 
-  /// Whether to enable parsing via the Fasta parser.
-  bool useFastaParser = true;
-
   /// Return `true` if the new relevance computations should be used when
   /// computing code completion suggestions.
   bool useNewRelevance = true;
diff --git a/pkg/analysis_server/lib/src/analysis_server_abstract.dart b/pkg/analysis_server/lib/src/analysis_server_abstract.dart
index c56feb0..e18292c 100644
--- a/pkg/analysis_server/lib/src/analysis_server_abstract.dart
+++ b/pkg/analysis_server/lib/src/analysis_server_abstract.dart
@@ -162,7 +162,6 @@
       sdkLanguageVersion: analyzer_features.ExperimentStatus.currentVersion,
       flags: options.enabledExperiments,
     );
-    defaultContextOptions.useFastaParser = options.useFastaParser;
 
     {
       var name = options.newAnalysisDriverLog;
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index 1254bc7..b09a113 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -747,11 +747,12 @@
   void _analyzeDataFile(AnalysisDriver driver, String path) {
     List<protocol.AnalysisError> convertedErrors;
     try {
+      var file = resourceProvider.getFile(path);
+      var packageName = file.parent.parent.shortName;
       var content = _readFile(path);
       var errorListener = RecordingErrorListener();
-      var errorReporter = ErrorReporter(
-          errorListener, resourceProvider.getFile(path).createSource());
-      var parser = TransformSetParser(errorReporter);
+      var errorReporter = ErrorReporter(errorListener, file.createSource());
+      var parser = TransformSetParser(errorReporter, packageName);
       parser.parse(content);
       var converter = AnalyzerConverter();
       convertedErrors = converter.convertAnalysisErrors(errorListener.errors,
diff --git a/pkg/analysis_server/lib/src/edit/edit_domain.dart b/pkg/analysis_server/lib/src/edit/edit_domain.dart
index 8ce7662..95ed5c8 100644
--- a/pkg/analysis_server/lib/src/edit/edit_domain.dart
+++ b/pkg/analysis_server/lib/src/edit/edit_domain.dart
@@ -280,6 +280,12 @@
     if (server.sendResponseErrorIfInvalidFilePath(request, file)) {
       return;
     }
+
+    if (!server.contextManager.isInAnalysisRoot(file)) {
+      server.sendResponse(Response.getFixesInvalidFile(request));
+      return;
+    }
+
     //
     // Allow plugins to start computing fixes.
     //
diff --git a/pkg/analysis_server/lib/src/lsp/client_configuration.dart b/pkg/analysis_server/lib/src/lsp/client_configuration.dart
index ebf42b7..55bfaf5 100644
--- a/pkg/analysis_server/lib/src/lsp/client_configuration.dart
+++ b/pkg/analysis_server/lib/src/lsp/client_configuration.dart
@@ -7,6 +7,19 @@
 class LspClientConfiguration {
   final Map<String, dynamic> _settings = <String, dynamic>{};
 
+  List<String> get analysisExcludedFolders {
+    // This setting is documented as a string array, but because editors are
+    // unlikely to provide validation, support single strings for convenience.
+    final value = _settings['analysisExcludedFolders'];
+    if (value is String) {
+      return [value];
+    } else if (value is List && value.every((s) => s is String)) {
+      return value.cast<String>();
+    } else {
+      return const [];
+    }
+  }
+
   bool get enableSdkFormatter => _settings['enableSdkFormatter'] ?? true;
   int get lineLength => _settings['lineLength'];
 
@@ -17,6 +30,13 @@
   bool get previewCommitCharacters =>
       _settings['previewCommitCharacters'] ?? false;
 
+  /// Returns whether or not the provided new configuration changes any values
+  /// that would require analysis roots to be updated.
+  bool affectsAnalysisRoots(Map<String, dynamic> newConfig) {
+    return _settings['analysisExcludedFolders'] !=
+        newConfig['analysisExcludedFolders'];
+  }
+
   void replace(Map<String, dynamic> newConfig) {
     _settings
       ..clear()
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
index 6fb0452..0e5a949 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_code_actions.dart
@@ -44,6 +44,11 @@
       return success(const []);
     }
 
+    final path = pathOfDoc(params.textDocument);
+    if (!path.isError && !server.isAnalyzedFile(path.result)) {
+      return success(const []);
+    }
+
     final capabilities = server?.clientCapabilities?.textDocument;
 
     final clientSupportsWorkspaceApplyEdit =
@@ -60,7 +65,6 @@
     final clientSupportedDiagnosticTags = HashSet<DiagnosticTag>.of(
         capabilities?.publishDiagnostics?.tagSupport?.valueSet ?? []);
 
-    final path = pathOfDoc(params.textDocument);
     final unit = await path.mapResult(requireResolvedUnit);
 
     return unit.mapResult((unit) {
diff --git a/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart b/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
index 027f52e..32e92de 100644
--- a/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
+++ b/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
@@ -48,6 +48,7 @@
 import 'package:analyzer_plugin/protocol/protocol_common.dart' as plugin;
 import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
 import 'package:analyzer_plugin/src/protocol/protocol_internal.dart' as plugin;
+import 'package:path/path.dart';
 import 'package:watcher/watcher.dart';
 
 /// Instances of the class [LspAnalysisServer] implement an LSP-based server
@@ -218,7 +219,15 @@
           result is List<dynamic> &&
           result.length == 1 &&
           result.first is Map<String, dynamic>) {
-        clientConfiguration.replace(result.first);
+        final newConfig = result.first;
+        final refreshRoots =
+            clientConfiguration.affectsAnalysisRoots(newConfig);
+
+        clientConfiguration.replace(newConfig);
+
+        if (refreshRoots) {
+          _refreshAnalysisRoots();
+        }
       }
     }
 
@@ -320,6 +329,15 @@
     }, socketError);
   }
 
+  /// Returns `true` if the [file] with the given absolute path is included
+  /// in an analysis root and not excluded.
+  bool isAnalyzedFile(String file) {
+    return contextManager.isInAnalysisRoot(file) &&
+        // Dot folders are not analyzed (skipped over in _handleWatchEventImpl)
+        !contextManager.isContainedInDotFolder(file) &&
+        !contextManager.isIgnored(file);
+  }
+
   /// Logs the error on the client using window/logMessage.
   void logErrorToClient(String message) {
     channel.sendNotification(NotificationMessage(
@@ -532,12 +550,7 @@
   /// Returns `true` if errors should be reported for [file] with the given
   /// absolute path.
   bool shouldSendErrorsNotificationFor(String file) {
-    // Errors should not be reported for things that are explicitly skipped
-    // during normal analysis (for example dot folders are skipped over in
-    // _handleWatchEventImpl).
-    return contextManager.isInAnalysisRoot(file) &&
-        !contextManager.isContainedInDotFolder(file) &&
-        !contextManager.isIgnored(file);
+    return isAnalyzedFile(file);
   }
 
   /// Returns `true` if Flutter outlines should be sent for [file] with the
@@ -614,9 +627,19 @@
       ..addAll(_temporaryAnalysisRoots.values)
       ..toList();
 
+    final excludedPaths = clientConfiguration.analysisExcludedFolders
+        .expand((excludePath) => isAbsolute(excludePath)
+            ? [excludePath]
+            // Apply the relative path to each open workspace folder.
+            // TODO(dantup): Consider supporting per-workspace config by
+            // calling workspace/configuration whenever workspace folders change
+            // and caching the config for each one.
+            : _explicitAnalysisRoots.map((root) => join(root, excludePath)))
+        .toList();
+
     declarationsTracker?.discardContexts();
-    notificationManager.setAnalysisRoots(includedPaths.toList(), []);
-    contextManager.setRoots(includedPaths.toList(), []);
+    notificationManager.setAnalysisRoots(includedPaths.toList(), excludedPaths);
+    contextManager.setRoots(includedPaths.toList(), excludedPaths);
     addContextsToDeclarationsTracker();
   }
 
diff --git a/pkg/analysis_server/lib/src/server/driver.dart b/pkg/analysis_server/lib/src/server/driver.dart
index 44939fc..298fd30 100644
--- a/pkg/analysis_server/lib/src/server/driver.dart
+++ b/pkg/analysis_server/lib/src/server/driver.dart
@@ -110,6 +110,7 @@
   void addOption(String name,
       {String abbr,
       String help,
+      String valueHelp,
       List<String> allowed,
       Map<String, String> allowedHelp,
       String defaultsTo,
@@ -118,6 +119,7 @@
     _parser.addOption(name,
         abbr: abbr,
         help: help,
+        valueHelp: valueHelp,
         allowed: allowed,
         allowedHelp: allowedHelp,
         defaultsTo: defaultsTo,
@@ -276,9 +278,6 @@
   /// The path to the data cache.
   static const String CACHE_FOLDER = 'cache';
 
-  /// Whether to enable parsing via the Fasta parser.
-  static const String USE_FASTA_PARSER = 'use-fasta-parser';
-
   /// The name of the flag to use the Language Server Protocol (LSP).
   static const String USE_LSP = 'lsp';
 
@@ -341,7 +340,6 @@
       analysisServerOptions.enabledExperiments =
           (results[ENABLE_EXPERIMENT_OPTION] as List).cast<String>().toList();
     }
-    analysisServerOptions.useFastaParser = results[USE_FASTA_PARSER];
     analysisServerOptions.useNewRelevance = results[USE_NEW_RELEVANCE];
 
     // Read in any per-SDK overrides specified in <sdk>/config/settings.json.
@@ -747,9 +745,15 @@
   /// Create and return the parser used to parse the command-line arguments.
   CommandLineParser _createArgParser() {
     var parser = CommandLineParser();
+    parser.addFlag(HELP_OPTION,
+        help: 'print this help message without starting a server',
+        abbr: 'h',
+        defaultsTo: false,
+        negatable: false);
     parser.addOption(CLIENT_ID,
-        help: 'an identifier used to identify the client');
-    parser.addOption(CLIENT_VERSION, help: 'the version of the client');
+        valueHelp: 'name', help: 'an identifier used to identify the client');
+    parser.addOption(CLIENT_VERSION,
+        valueHelp: 'version', help: 'the version of the client');
     parser.addFlag(DARTPAD_OPTION,
         help: 'enable DartPad specific functionality',
         defaultsTo: false,
@@ -774,18 +778,15 @@
         help: 'enable sending instrumentation information to a server',
         defaultsTo: false,
         negatable: false);
-    parser.addFlag(HELP_OPTION,
-        help: 'print this help message without starting a server',
-        abbr: 'h',
-        defaultsTo: false,
-        negatable: false);
     parser.addOption(INSTRUMENTATION_LOG_FILE,
+        valueHelp: 'file path',
         help: 'write instrumentation data to the given file');
     parser.addFlag(INTERNAL_PRINT_TO_CONSOLE,
         help: 'enable sending `print` output to the console',
         defaultsTo: false,
         negatable: false);
     parser.addOption(NEW_ANALYSIS_DRIVER_LOG,
+        valueHelp: 'path',
         help: "set a destination for the new analysis driver's log");
     parser.addFlag(ANALYTICS_FLAG,
         help: 'enable or disable sending analytics information to Google',
@@ -795,9 +796,11 @@
         help: 'suppress analytics for this session',
         hide: !telemetry.SHOW_ANALYTICS_UI);
     parser.addOption(PORT_OPTION,
+        valueHelp: 'port',
         help: 'the http diagnostic port on which the server provides'
             ' status and performance information');
-    parser.addOption(SDK_OPTION, help: '[path] the path to the sdk');
+    parser.addOption(SDK_OPTION,
+        valueHelp: 'path', help: 'Path to the Dart sdk');
     parser.addFlag(USE_ANALYSIS_HIGHLIGHT2,
         help: 'enable version 2 of semantic highlight',
         defaultsTo: false,
@@ -806,6 +809,7 @@
         help: 'an option for reading files (some clients normalize eol '
             'characters, which make the file offset and range information '
             'incorrect)',
+        valueHelp: 'mode',
         allowed: ['as-is', 'normalize-eol-always'],
         allowedHelp: {
           'as-is': 'file contents are read as-is',
@@ -814,21 +818,21 @@
         },
         defaultsTo: 'as-is');
     parser.addOption(CACHE_FOLDER,
-        help: '[path] path to the location where to cache data');
-    parser.addFlag('preview-dart-2',
-        help: 'Enable the Dart 2.0 preview (deprecated)', hide: true);
-    parser.addFlag(USE_FASTA_PARSER,
-        defaultsTo: true,
-        help: 'Whether to enable parsing via the Fasta parser');
+        valueHelp: 'path', help: 'Path to the location to write cache data');
     parser.addFlag(USE_LSP,
-        defaultsTo: false, help: 'Whether to use the Language Server Protocol');
+        defaultsTo: false,
+        negatable: false,
+        help: 'Whether to use the Language Server Protocol');
     parser.addFlag(ENABLE_COMPLETION_MODEL,
         help: 'Whether or not to turn on ML ranking for code completion');
     parser.addOption(COMPLETION_MODEL_FOLDER,
-        help: '[path] path to the location of a code completion model');
+        valueHelp: 'path',
+        help: 'Path to the location of a code completion model');
     parser.addOption(TRAIN_USING,
+        valueHelp: 'path',
         help: 'Pass in a directory to analyze for purposes of training an '
             'analysis server snapshot.');
+
     //
     // Temporary flags.
     //
@@ -836,6 +840,12 @@
         defaultsTo: true,
         help: 'Use the new relevance computation for code completion.');
 
+    //
+    // Deprecated options - no longer read from.
+    //
+    parser.addFlag('use-fasta-parser', defaultsTo: true, hide: true);
+    parser.addFlag('preview-dart-2', hide: true);
+
     return parser;
   }
 
diff --git a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
index 357c58f..6f994e4 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
@@ -192,7 +192,8 @@
     Future<void> compute(CorrectionProducer producer) async {
       producer.configure(context);
 
-      var builder = ChangeBuilder(workspace: context.workspace);
+      var builder = ChangeBuilder(
+          workspace: context.workspace, eol: context.utils.endOfLine);
       await producer.compute(builder);
 
       _addAssistFromBuilder(builder, producer.assistKind,
@@ -246,7 +247,8 @@
         var producer = generator();
         producer.configure(context);
 
-        var builder = ChangeBuilder(workspace: context.workspace);
+        var builder = ChangeBuilder(
+            workspace: context.workspace, eol: context.utils.endOfLine);
         await producer.compute(builder);
         _addAssistFromBuilder(builder, producer.assistKind,
             args: producer.assistArguments);
@@ -256,7 +258,8 @@
       var multiProducer = multiGenerator();
       multiProducer.configure(context);
       for (var producer in multiProducer.producers) {
-        var builder = ChangeBuilder(workspace: context.workspace);
+        var builder = ChangeBuilder(
+            workspace: context.workspace, eol: context.utils.endOfLine);
         producer.configure(context);
         await producer.compute(builder);
         _addAssistFromBuilder(builder, producer.assistKind,
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_documentation_into_line.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_documentation_into_line.dart
index 7459fdb..d2c7fd5 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_documentation_into_line.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_documentation_into_line.dart
@@ -32,7 +32,7 @@
       return null;
     }
     var text = token.lexeme;
-    var lines = text.split('\n');
+    var lines = text.split(eol);
     var prefix = utils.getNodePrefix(comment);
     var newLines = <String>[];
     var firstLine = true;
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/data_driven.dart b/pkg/analysis_server/lib/src/services/correction/dart/data_driven.dart
index bcf7198..234f33a 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/data_driven.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/data_driven.dart
@@ -22,12 +22,16 @@
   @override
   Iterable<CorrectionProducer> get producers sync* {
     var name = _name;
-    var importedUris = <String>[];
+    var importedUris = <Uri>[];
     var library = resolvedResult.libraryElement;
     for (var importElement in library.imports) {
       // TODO(brianwilkerson) Filter based on combinators to help avoid making
       //  invalid suggestions.
-      importedUris.add(importElement.uri);
+      var uri = importElement.uri;
+      if (uri != null) {
+        // The [uri] is `null` if the literal string is not a valid URI.
+        importedUris.add(Uri.parse(uri));
+      }
     }
     for (var set in _availableTransformSetsForLibrary(library)) {
       for (var transform in set.transformsFor(name, importedUris)) {
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/add_type_parameter.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/add_type_parameter.dart
index 50ef9fe..936237a 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/add_type_parameter.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/add_type_parameter.dart
@@ -101,44 +101,67 @@
 
   void _applyToTypeArguments(
       DartFileEditBuilder builder, DataDrivenFix fix, _TypeArgumentData data) {
+    var context = TemplateContext(fix.node, fix.utils);
     var typeArguments = data.typeArguments;
-    var argumentValueText = argumentValue.generate(fix.node, fix.utils);
     if (typeArguments == null) {
       // Adding the first type argument.
-      builder.addSimpleInsertion(data.newListOffset, '<$argumentValueText>');
+      builder.addInsertion(data.newListOffset, (builder) {
+        builder.write('<');
+        argumentValue.writeOn(builder, context);
+        builder.write('>');
+      });
     } else {
       if (index == 0) {
         // Inserting the type argument at the beginning of the list.
-        builder.addSimpleInsertion(
-            typeArguments.leftBracket.end, '$argumentValueText, ');
+        builder.addInsertion(typeArguments.leftBracket.end, (builder) {
+          argumentValue.writeOn(builder, context);
+          builder.write(', ');
+        });
       } else {
         // Inserting the type argument after an existing type argument.
         var previous = typeArguments.arguments[index - 1];
-        builder.addSimpleInsertion(previous.end, ', $argumentValueText');
+        builder.addInsertion(previous.end, (builder) {
+          builder.write(', ');
+          argumentValue.writeOn(builder, context);
+        });
       }
     }
   }
 
   void _applyToTypeParameters(
       DartFileEditBuilder builder, DataDrivenFix fix, _TypeParameterData data) {
-    var extendsClause = '';
-    if (extendedType != null) {
-      extendsClause = ' extends ${extendedType.generate(fix.node, fix.utils)}';
+    var context = TemplateContext(fix.node, fix.utils);
+
+    void writeParameter(DartEditBuilder builder) {
+      builder.write(name);
+      if (extendedType != null) {
+        builder.write(' extends ');
+        extendedType.writeOn(builder, context);
+      }
     }
-    var argumentValue = '$name$extendsClause';
+
     var typeParameters = data.typeParameters;
     if (typeParameters == null) {
       // Adding the first type argument.
-      builder.addSimpleInsertion(data.newListOffset, '<$argumentValue>');
+      builder.addInsertion(data.newListOffset, (builder) {
+        builder.write('<');
+        writeParameter(builder);
+        builder.write('>');
+      });
     } else {
       if (index == 0) {
         // Inserting the type argument at the beginning of the list.
-        builder.addSimpleInsertion(
-            typeParameters.leftBracket.end, '$argumentValue, ');
+        builder.addInsertion(typeParameters.leftBracket.end, (builder) {
+          writeParameter(builder);
+          builder.write(', ');
+        });
       } else {
         // Inserting the type argument after an existing type argument.
         var previous = typeParameters.typeParameters[index - 1];
-        builder.addSimpleInsertion(previous.end, ', $argumentValue');
+        builder.addInsertion(previous.end, (builder) {
+          builder.write(', ');
+          writeParameter(builder);
+        });
       }
     }
   }
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/code_template.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/code_template.dart
index 941d9be..cf17314 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/code_template.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/code_template.dart
@@ -5,6 +5,7 @@
 import 'package:analysis_server/src/services/correction/fix/data_driven/value_generator.dart';
 import 'package:analysis_server/src/services/correction/util.dart';
 import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart';
 
 /// An object used to generate code to be inserted.
 class CodeTemplate {
@@ -18,15 +19,6 @@
   /// [components].
   CodeTemplate(this.kind, this.components);
 
-  String generate(AstNode node, CorrectionUtils utils) {
-    var context = TemplateContext(node, utils);
-    var buffer = StringBuffer();
-    for (var component in components) {
-      component.appendTo(buffer, context);
-    }
-    return buffer.toString();
-  }
-
   /// Use the [context] to validate that this template will be able to generate
   /// a value.
   bool validate(TemplateContext context) {
@@ -37,6 +29,12 @@
     }
     return true;
   }
+
+  void writeOn(DartEditBuilder builder, TemplateContext context) {
+    for (var component in components) {
+      component.writeOn(builder, context);
+    }
+  }
 }
 
 /// The kinds of code that can be generated by a template.
@@ -47,14 +45,14 @@
 
 /// An object used to compute some portion of a template.
 abstract class TemplateComponent {
-  /// Append the text contributed by this component to the given [sink], using
-  /// the [context] to access needed information that isn't already known to
-  /// this component.
-  void appendTo(StringSink sink, TemplateContext context);
-
   /// Use the [context] to validate that this component will be able to generate
   /// a value.
   bool validate(TemplateContext context);
+
+  /// Write the text contributed by this component to the given [builder], using
+  /// the [context] to access needed information that isn't already known to
+  /// this component.
+  void writeOn(DartEditBuilder builder, TemplateContext context);
 }
 
 /// The context in which a template is being evaluated.
@@ -65,20 +63,8 @@
   /// The utilities used to help extract the code associated with various nodes.
   final CorrectionUtils utils;
 
-  /// A table mapping variable names to the values of those variables after they
-  /// have been computed. Used to prevent computing the same value multiple
-  /// times.
-  final Map<ValueGenerator, String> _variableValues = {};
-
   /// Initialize a newly created variable support.
   TemplateContext(this.node, this.utils);
-
-  /// Return the value of the variable with the given [name].
-  String valueOf(ValueGenerator generator) {
-    return _variableValues.putIfAbsent(generator, () {
-      return generator.from(this);
-    });
-  }
 }
 
 /// Literal text within a template.
@@ -90,13 +76,13 @@
   TemplateText(this.text);
 
   @override
-  void appendTo(StringSink sink, TemplateContext context) {
-    sink.write(text);
+  bool validate(TemplateContext context) {
+    return true;
   }
 
   @override
-  bool validate(TemplateContext context) {
-    return true;
+  void writeOn(DartEditBuilder builder, TemplateContext context) {
+    builder.write(text);
   }
 }
 
@@ -109,12 +95,12 @@
   TemplateVariable(this.generator);
 
   @override
-  void appendTo(StringSink sink, TemplateContext context) {
-    sink.write(context.valueOf(generator));
+  bool validate(TemplateContext context) {
+    return generator.validate(context);
   }
 
   @override
-  bool validate(TemplateContext context) {
-    return generator.validate(context);
+  void writeOn(DartEditBuilder builder, TemplateContext context) {
+    generator.writeOn(builder, context);
   }
 }
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/element_descriptor.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/element_descriptor.dart
index a0db646..1b25a68 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/element_descriptor.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/element_descriptor.dart
@@ -7,7 +7,7 @@
 /// The path to an element.
 class ElementDescriptor {
   /// The URIs of the library in which the element is defined.
-  final List<String> libraryUris;
+  final List<Uri> libraryUris;
 
   /// The kind of element that was changed.
   final String _kind;
@@ -30,7 +30,7 @@
 
   /// Return `true` if this descriptor matches an element with the given [name]
   /// in a library that imports the [importedUris].
-  bool matches(String name, List<String> importedUris) {
+  bool matches(String name, List<Uri> importedUris) {
     var lastComponent = components.last;
     if (lastComponent.isEmpty) {
       if (components[components.length - 2] != name) {
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/modify_parameters.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/modify_parameters.dart
index 857a509..3cd6143 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/modify_parameters.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/modify_parameters.dart
@@ -91,12 +91,12 @@
     /// Write to the [builder] the argument associated with a single
     /// [parameter].
     void writeArgument(DartEditBuilder builder, AddParameter parameter) {
-      var value = parameter.argumentValue.generate(argumentList, fix.utils);
       if (!parameter.isPositional) {
         builder.write(parameter.name);
         builder.write(': ');
       }
-      builder.write(value);
+      parameter.argumentValue
+          .writeOn(builder, TemplateContext(argumentList, fix.utils));
     }
 
     var insertionRanges = argumentsToInsert.contiguousSubRanges.toList();
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform.dart
index ca9a24c..989b614 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform.dart
@@ -31,7 +31,7 @@
   /// Return `true` if this transform can be applied to fix an issue related to
   /// an element with the given [name] in a library that imports the
   /// [importedUris].
-  bool appliesTo(String name, List<String> importedUris) {
+  bool appliesTo(String name, List<Uri> importedUris) {
     return element.matches(name, importedUris);
   }
 }
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set.dart
index e5c7445..5a966c6 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set.dart
@@ -18,7 +18,7 @@
 
   /// Return a list of the transforms that apply for a reference to the given
   /// [name] in a library that imports the [importedUris].
-  List<Transform> transformsFor(String name, List<String> importedUris) {
+  List<Transform> transformsFor(String name, List<Uri> importedUris) {
     var result = <Transform>[];
     for (var transform in _transforms) {
       if (transform.appliesTo(name, importedUris)) {
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_manager.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_manager.dart
index 52cecbb..b477af8 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_manager.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_manager.dart
@@ -25,6 +25,9 @@
     var workspace = library.session.analysisContext.workspace;
     var libraryPath = library.source.fullName;
     var package = workspace.findPackageFor(libraryPath);
+    if (package == null) {
+      return transformSets;
+    }
     var packageMap = package.packagesAvailableTo(libraryPath);
     for (var entry in packageMap.entries) {
       var directory = entry.value[0];
@@ -45,8 +48,10 @@
     try {
       // TODO(brianwilkerson) Consider caching the transform sets.
       var content = file.readAsStringSync();
-      var parser = TransformSetParser(ErrorReporter(
-          AnalysisErrorListener.NULL_LISTENER, file.createSource()));
+      var parser = TransformSetParser(
+          ErrorReporter(
+              AnalysisErrorListener.NULL_LISTENER, file.createSource()),
+          file.parent.parent.shortName);
       return parser.parse(content);
     } on FileSystemException {
       // Fall through to return `null`.
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_parser.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_parser.dart
index 1521f7c..96b3af0 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_parser.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_parser.dart
@@ -106,13 +106,15 @@
   /// The error reporter to which diagnostics will be reported.
   final ErrorReporter errorReporter;
 
+  final String packageName;
+
   /// The parameter modifications associated with the current transform, or
   /// `null` if the current transform does not yet have any such modifications.
   List<ParameterModification> _parameterModifications;
 
   /// Initialize a newly created parser to report diagnostics to the
   /// [errorReporter].
-  TransformSetParser(this.errorReporter);
+  TransformSetParser(this.errorReporter, this.packageName);
 
   /// Return the result of parsing the file [content] into a transform set, or
   /// `null` if the content does not represent a valid transform set.
@@ -466,7 +468,7 @@
   ElementDescriptor _translateElement(YamlNode node, ErrorContext context) {
     if (node is YamlMap) {
       var uris = _translateList(node.valueAt(_urisKey),
-          ErrorContext(key: _urisKey, parentNode: node), _translateString);
+          ErrorContext(key: _urisKey, parentNode: node), _translateUri);
       var elementKey = _singleKey(node, const [
         _classKey,
         _constantKey,
@@ -526,7 +528,7 @@
   ValueGenerator _translateImportValue(YamlMap node) {
     _reportUnsupportedKeys(node, const {_kindKey, _nameKey, _urisKey});
     var uris = _translateList(node.valueAt(_urisKey),
-        ErrorContext(key: _urisKey, parentNode: node), _translateString);
+        ErrorContext(key: _urisKey, parentNode: node), _translateUri);
     var name = _translateString(
         node.valueAt(_nameKey), ErrorContext(key: _nameKey, parentNode: node));
     if (uris == null || name == null) {
@@ -752,6 +754,30 @@
     }
   }
 
+  /// Translate the [node] into a URI. Return the resulting URI, or `null` if
+  /// the [node] does not represent a valid URI. If the [node] is not valid, use
+  /// the [context] to report the error.
+  Uri _translateUri(YamlNode node, ErrorContext context,
+      {bool required = true}) {
+    if (node is YamlScalar) {
+      var value = node.value;
+      if (value is String) {
+        if (!(value.startsWith('dart:') || value.startsWith('package:'))) {
+          value = 'package:$packageName/$value';
+        }
+        return Uri.parse(value);
+      }
+      return _reportInvalidValue(node, context, 'URI');
+    } else if (node == null) {
+      if (required) {
+        return _reportMissingKey(context);
+      }
+      return null;
+    } else {
+      return _reportInvalidValue(node, context, 'URI');
+    }
+  }
+
   /// Translate the [node] into a value extractor. Return the resulting
   /// extractor, or `null` if the [node] does not represent a valid value
   /// extractor. If the [node] is not valid, use the [context] to report the
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/value_generator.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/value_generator.dart
index 43d83fc..1214e8b 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/value_generator.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/value_generator.dart
@@ -5,6 +5,7 @@
 import 'package:analysis_server/src/services/correction/fix/data_driven/code_template.dart';
 import 'package:analysis_server/src/services/correction/fix/data_driven/parameter_reference.dart';
 import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart';
 
 /// Use a specified argument from an invocation as the value of a template
 /// variable.
@@ -19,18 +20,6 @@
   ArgumentExpression(this.parameter) : assert(parameter != null);
 
   @override
-  String from(TemplateContext context) {
-    var argumentList = _getArgumentList(context.node);
-    if (argumentList != null) {
-      var expression = parameter.argumentFrom(argumentList);
-      if (expression != null) {
-        return context.utils.getNodeText(expression);
-      }
-    }
-    return null;
-  }
-
-  @override
   bool validate(TemplateContext context) {
     var argumentList = _getArgumentList(context.node);
     if (argumentList == null) {
@@ -43,6 +32,17 @@
     return true;
   }
 
+  @override
+  void writeOn(DartEditBuilder builder, TemplateContext context) {
+    var argumentList = _getArgumentList(context.node);
+    if (argumentList != null) {
+      var expression = parameter.argumentFrom(argumentList);
+      if (expression != null) {
+        builder.write(context.utils.getNodeText(expression));
+      }
+    }
+  }
+
   /// Return the argument list associated with the given [node].
   ArgumentList _getArgumentList(AstNode node) {
     if (node is ArgumentList) {
@@ -67,7 +67,7 @@
 /// value of a template variable.
 class ImportedName extends ValueGenerator {
   /// The URIs of the libraries from which the name can be imported.
-  final List<String> uris;
+  final List<Uri> uris;
 
   /// The name to be used.
   final String name;
@@ -75,25 +75,25 @@
   ImportedName(this.uris, this.name);
 
   @override
-  String from(TemplateContext context) {
-    // TODO(brianwilkerson) Figure out how to add the import when necessary.
-    return name;
-  }
-
-  @override
   bool validate(TemplateContext context) {
     // TODO(brianwilkerson) Validate that the import can be added.
     return true;
   }
+
+  @override
+  void writeOn(DartEditBuilder builder, TemplateContext context) {
+    builder.writeImportedName(uris, name);
+  }
 }
 
 /// An object used to generate the value of a template variable.
 abstract class ValueGenerator {
-  /// Use the [context] to generate the value of a template variable and return
-  /// the generated value.
-  String from(TemplateContext context);
-
   /// Use the [context] to validate that this generator will be able to generate
   /// a value.
   bool validate(TemplateContext context);
+
+  /// Write the value generated by this generator to the given [builder], using
+  /// the [context] to access needed information that isn't already known to
+  /// this generator.
+  void writeOn(DartEditBuilder builder, TemplateContext context);
 }
diff --git a/pkg/analysis_server/lib/src/services/refactoring/extract_widget.dart b/pkg/analysis_server/lib/src/services/refactoring/extract_widget.dart
index 58adedd5..09b73f8 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/extract_widget.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/extract_widget.dart
@@ -141,7 +141,8 @@
 
   @override
   Future<SourceChange> createChange() async {
-    var builder = ChangeBuilder(session: sessionHelper.session);
+    var builder =
+        ChangeBuilder(session: sessionHelper.session, eol: utils.endOfLine);
     await builder.addDartFileEdit(resolveResult.path, (builder) {
       if (_expression != null) {
         builder.addReplacement(range.node(_expression), (builder) {
diff --git a/pkg/analysis_server/test/abstract_single_unit.dart b/pkg/analysis_server/test/abstract_single_unit.dart
index 5b10d92..d40c389 100644
--- a/pkg/analysis_server/test/abstract_single_unit.dart
+++ b/pkg/analysis_server/test/abstract_single_unit.dart
@@ -7,12 +7,14 @@
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/error/error.dart';
+import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/src/dart/ast/element_locator.dart';
 import 'package:analyzer/src/dart/ast/utilities.dart';
 import 'package:analyzer/src/dart/error/hint_codes.dart';
 import 'package:analyzer/src/generated/java_engine.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/test_utilities/find_node.dart';
+import 'package:analyzer/src/test_utilities/platform.dart';
 import 'package:test/test.dart';
 
 import 'abstract_context.dart';
@@ -20,6 +22,9 @@
 class AbstractSingleUnitTest extends AbstractContextTest {
   bool verifyNoTestUnitErrors = true;
 
+  /// Whether to rewrite line endings in test code based on platform.
+  bool useLineEndingsForPlatform = false;
+
   String testCode;
   String testFile;
   Source testSource;
@@ -29,6 +34,14 @@
   LibraryElement testLibraryElement;
   FindNode findNode;
 
+  @override
+  Source addSource(String path, String content, [Uri uri]) {
+    if (useLineEndingsForPlatform) {
+      content = normalizeNewlinesForPlatform(content);
+    }
+    return super.addSource(path, content, uri);
+  }
+
   void addTestSource(String code, [Uri uri]) {
     testCode = code;
     testSource = addSource(testFile, code, uri);
@@ -106,7 +119,18 @@
     return length;
   }
 
+  @override
+  File newFile(String path, {String content = ''}) {
+    if (useLineEndingsForPlatform) {
+      content = normalizeNewlinesForPlatform(content);
+    }
+    return super.newFile(path, content: content);
+  }
+
   Future<void> resolveTestUnit(String code) async {
+    if (useLineEndingsForPlatform) {
+      code = normalizeNewlinesForPlatform(code);
+    }
     addTestSource(code);
     testAnalysisResult = await session.getResolvedUnit(testFile);
     testUnit = testAnalysisResult.unit;
diff --git a/pkg/analysis_server/test/edit/fixes_test.dart b/pkg/analysis_server/test/edit/fixes_test.dart
index 7de1b0d..19588f5 100644
--- a/pkg/analysis_server/test/edit/fixes_test.dart
+++ b/pkg/analysis_server/test/edit/fixes_test.dart
@@ -29,6 +29,24 @@
     handler = EditDomainHandler(server);
   }
 
+  Future<void> test_fileOutsideRoot() async {
+    final outsideFile = '/foo/test.dart';
+    newFile(outsideFile, content: 'bad code to create error');
+
+    // Set up the original project, as the code fix code won't run at all
+    // if there are no contexts.
+    createProject();
+    await waitForTasksFinished();
+
+    var request =
+        EditGetFixesParams(convertPath(outsideFile), 0).toRequest('0');
+    var response = await waitResponse(request);
+    expect(
+      response,
+      isResponseFailure('0', RequestErrorCode.GET_FIXES_INVALID_FILE),
+    );
+  }
+
   Future<void> test_fixUndefinedClass() async {
     createProject();
     addTestFile('''
diff --git a/pkg/analysis_server/test/integration/support/integration_test_methods.dart b/pkg/analysis_server/test/integration/support/integration_test_methods.dart
index 9799790..c6f966e 100644
--- a/pkg/analysis_server/test/integration/support/integration_test_methods.dart
+++ b/pkg/analysis_server/test/integration/support/integration_test_methods.dart
@@ -1708,6 +1708,11 @@
   /// Return the set of fixes that are available for the errors at a given
   /// offset in a given file.
   ///
+  /// If a request is made for a file which does not exist, or which is not
+  /// currently subject to analysis (e.g. because it is not associated with any
+  /// analysis root specified to analysis.setAnalysisRoots), an error of type
+  /// GET_FIXES_INVALID_FILE will be generated.
+  ///
   /// Parameters
   ///
   /// file: FilePath
diff --git a/pkg/analysis_server/test/integration/support/protocol_matchers.dart b/pkg/analysis_server/test/integration/support/protocol_matchers.dart
index ffeed70..354c2aa 100644
--- a/pkg/analysis_server/test/integration/support/protocol_matchers.dart
+++ b/pkg/analysis_server/test/integration/support/protocol_matchers.dart
@@ -1365,6 +1365,7 @@
 ///   FORMAT_INVALID_FILE
 ///   FORMAT_WITH_ERRORS
 ///   GET_ERRORS_INVALID_FILE
+///   GET_FIXES_INVALID_FILE
 ///   GET_IMPORTED_ELEMENTS_INVALID_FILE
 ///   GET_KYTHE_ENTRIES_INVALID_FILE
 ///   GET_NAVIGATION_INVALID_FILE
@@ -1401,6 +1402,7 @@
   'FORMAT_INVALID_FILE',
   'FORMAT_WITH_ERRORS',
   'GET_ERRORS_INVALID_FILE',
+  'GET_FIXES_INVALID_FILE',
   'GET_IMPORTED_ELEMENTS_INVALID_FILE',
   'GET_KYTHE_ENTRIES_INVALID_FILE',
   'GET_NAVIGATION_INVALID_FILE',
diff --git a/pkg/analysis_server/test/lsp/code_actions_fixes_test.dart b/pkg/analysis_server/test/lsp/code_actions_fixes_test.dart
index ac4a575..0082910 100644
--- a/pkg/analysis_server/test/lsp/code_actions_fixes_test.dart
+++ b/pkg/analysis_server/test/lsp/code_actions_fixes_test.dart
@@ -195,4 +195,17 @@
     applyChanges(contents, fixAction.edit.changes);
     expect(contents[mainFilePath], equals(expectedContent));
   }
+
+  Future<void> test_outsideRoot() async {
+    final otherFilePath = '/home/otherProject/foo.dart';
+    final otherFileUri = Uri.file(otherFilePath);
+    await newFile(otherFilePath, content: 'bad code to create error');
+    await initialize(
+      textDocumentCapabilities: withCodeActionKinds(
+          emptyTextDocumentClientCapabilities, [CodeActionKind.QuickFix]),
+    );
+
+    final codeActions = await getCodeActions(otherFileUri.toString());
+    expect(codeActions, isEmpty);
+  }
 }
diff --git a/pkg/analysis_server/test/lsp/configuration_test.dart b/pkg/analysis_server/test/lsp/configuration_test.dart
index 16ea16e..0a864ee 100644
--- a/pkg/analysis_server/test/lsp/configuration_test.dart
+++ b/pkg/analysis_server/test/lsp/configuration_test.dart
@@ -48,6 +48,29 @@
     expect(registration, isNull);
   }
 
+  Future<void> test_configurationDidChange_refreshesRoots() async {
+    await provideConfig(
+      () => initialize(
+          workspaceCapabilities: withDidChangeConfigurationDynamicRegistration(
+              withConfigurationSupport(emptyWorkspaceClientCapabilities))),
+      {}, // Empty config
+    );
+
+    // Ensure the roots are as expected before we udpate the config.
+    expect(server.contextManager.includedPaths, equals([projectFolderPath]));
+    expect(server.contextManager.excludedPaths, isEmpty);
+
+    // Notify the server of updated config that includes an excluded path.
+    final excludedFolderPath = join(projectFolderPath, 'excluded');
+    await updateConfig({
+      'analysisExcludedFolders': [excludedFolderPath]
+    });
+
+    // Ensure the roots were updated by the config change.
+    expect(server.contextManager.includedPaths, equals([projectFolderPath]));
+    expect(server.contextManager.excludedPaths, equals([excludedFolderPath]));
+  }
+
   Future<void> test_configurationDidChange_supported() async {
     final registrations = <Registration>[];
     await monitorDynamicRegistrations(
diff --git a/pkg/analysis_server/test/lsp/initialization_test.dart b/pkg/analysis_server/test/lsp/initialization_test.dart
index eeebebb..4bae1b9 100644
--- a/pkg/analysis_server/test/lsp/initialization_test.dart
+++ b/pkg/analysis_server/test/lsp/initialization_test.dart
@@ -331,6 +331,53 @@
     expect(server.contextManager.includedPaths, equals([]));
   }
 
+  Future<void> test_excludedFolders_absolute() async {
+    final excludedFolderPath = join(projectFolderPath, 'excluded');
+
+    await provideConfig(
+      () => initialize(
+          workspaceCapabilities:
+              withConfigurationSupport(emptyWorkspaceClientCapabilities)),
+      // Exclude the folder with a relative path.
+      {
+        'analysisExcludedFolders': [excludedFolderPath]
+      },
+    );
+    expect(server.contextManager.includedPaths, equals([projectFolderPath]));
+    expect(server.contextManager.excludedPaths, equals([excludedFolderPath]));
+  }
+
+  Future<void> test_excludedFolders_nonList() async {
+    final excludedFolderPath = join(projectFolderPath, 'excluded');
+
+    await provideConfig(
+      () => initialize(
+          workspaceCapabilities:
+              withConfigurationSupport(emptyWorkspaceClientCapabilities)),
+      // Include a single string instead of an array since it's an easy mistake
+      // to make without editor validation of settings.
+      {'analysisExcludedFolders': 'excluded'},
+    );
+    expect(server.contextManager.includedPaths, equals([projectFolderPath]));
+    expect(server.contextManager.excludedPaths, equals([excludedFolderPath]));
+  }
+
+  Future<void> test_excludedFolders_relative() async {
+    final excludedFolderPath = join(projectFolderPath, 'excluded');
+
+    await provideConfig(
+      () => initialize(
+          workspaceCapabilities:
+              withConfigurationSupport(emptyWorkspaceClientCapabilities)),
+      // Exclude the folder with a relative path.
+      {
+        'analysisExcludedFolders': ['excluded']
+      },
+    );
+    expect(server.contextManager.includedPaths, equals([projectFolderPath]));
+    expect(server.contextManager.excludedPaths, equals([excludedFolderPath]));
+  }
+
   Future<void> test_initialize() async {
     final response = await initialize();
     expect(response, isNotNull);
diff --git a/pkg/analysis_server/test/services/refactoring/abstract_refactoring.dart b/pkg/analysis_server/test/services/refactoring/abstract_refactoring.dart
index 1353f6d..9f40c52 100644
--- a/pkg/analysis_server/test/services/refactoring/abstract_refactoring.dart
+++ b/pkg/analysis_server/test/services/refactoring/abstract_refactoring.dart
@@ -7,6 +7,7 @@
 import 'package:analysis_server/src/services/search/search_engine.dart';
 import 'package:analysis_server/src/services/search/search_engine_internal.dart';
 import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/test_utilities/platform.dart';
 import 'package:analyzer_plugin/protocol/protocol_common.dart'
     show RefactoringProblemSeverity, SourceChange, SourceEdit;
 import 'package:test/test.dart';
@@ -38,6 +39,9 @@
   /// Asserts that [refactoringChange] contains a [FileEdit] for the file
   /// with the given [path], and it results the [expectedCode].
   void assertFileChangeResult(String path, String expectedCode) {
+    if (useLineEndingsForPlatform) {
+      expectedCode = normalizeNewlinesForPlatform(expectedCode);
+    }
     // prepare FileEdit
     var fileEdit = refactoringChange.getFileEdit(convertPath(path));
     expect(fileEdit, isNotNull, reason: 'No file edit for $path');
@@ -112,6 +116,9 @@
   /// Asserts that [refactoringChange] contains a [FileEdit] for [testFile], and
   /// it results the [expectedCode].
   void assertTestChangeResult(String expectedCode) {
+    if (useLineEndingsForPlatform) {
+      expectedCode = normalizeNewlinesForPlatform(expectedCode);
+    }
     // prepare FileEdit
     var fileEdit = refactoringChange.getFileEdit(testFile);
     expect(fileEdit, isNotNull);
@@ -131,6 +138,8 @@
   @override
   void setUp() {
     super.setUp();
+    // TODO(dantup): Get these tests passing with either line ending and change this to true.
+    useLineEndingsForPlatform = false;
     searchEngine = SearchEngineImpl([driver]);
   }
 }
diff --git a/pkg/analysis_server/test/services/refactoring/extract_method_test.dart b/pkg/analysis_server/test/services/refactoring/extract_method_test.dart
index 5f53c00..9db1931 100644
--- a/pkg/analysis_server/test/services/refactoring/extract_method_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/extract_method_test.dart
@@ -2923,7 +2923,8 @@
   }
 
   void _createRefactoringForStartEndComments() {
-    var offset = findEnd('// start') + '\n'.length;
+    final eol = testCode.contains('\r\n') ? '\r\n' : '\r';
+    var offset = findEnd('// start') + eol.length;
     var end = findOffset('// end');
     _createRefactoring(offset, end - offset);
   }
diff --git a/pkg/analysis_server/test/services/refactoring/extract_widget_test.dart b/pkg/analysis_server/test/services/refactoring/extract_widget_test.dart
index b25f74c..8c1da18 100644
--- a/pkg/analysis_server/test/services/refactoring/extract_widget_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/extract_widget_test.dart
@@ -442,7 +442,7 @@
   Widget build(BuildContext context) {
     return createColumn();
   }
-  
+
   Widget createColumn() {
     var a = new Text('AAA');
     var b = new Text('BBB');
@@ -499,7 +499,7 @@
       ],
     );
   }
-  
+
   Widget createColumn(String p1, int p2) {
     var a = new Text('$foo $p1');
     var b = new Text('$p2');
@@ -571,7 +571,7 @@
       ],
     );
   }
-  
+
   Widget createColumn({String p1, int p2}) {
     var a = new Text('$foo $p1');
     var b = new Text('$p2');
diff --git a/pkg/analysis_server/test/src/services/correction/assist/assist_processor.dart b/pkg/analysis_server/test/src/services/correction/assist/assist_processor.dart
index 3a9e20f..478f098 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/assist_processor.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/assist_processor.dart
@@ -6,6 +6,7 @@
 import 'package:analysis_server/src/services/correction/assist.dart';
 import 'package:analysis_server/src/services/correction/assist_internal.dart';
 import 'package:analysis_server/src/services/correction/change_workspace.dart';
+import 'package:analyzer/src/test_utilities/platform.dart';
 import 'package:analyzer_plugin/protocol/protocol_common.dart'
     hide AnalysisError;
 import 'package:analyzer_plugin/protocol/protocol_common.dart';
@@ -53,6 +54,11 @@
   /// have been applied.
   Future<void> assertHasAssist(String expected,
       {Map<String, List<String>> additionallyChangedFiles}) async {
+    if (useLineEndingsForPlatform) {
+      expected = normalizeNewlinesForPlatform(expected);
+      additionallyChangedFiles = additionallyChangedFiles?.map((key, value) =>
+          MapEntry(key, value.map(normalizeNewlinesForPlatform).toList()));
+    }
     var assist = await _assertHasAssist();
     _change = assist.change;
     expect(_change.id, kind.id);
@@ -80,6 +86,9 @@
   /// given [snippet] which produces the [expected] code when applied to [testCode].
   Future<void> assertHasAssistAt(String snippet, String expected,
       {int length = 0}) async {
+    if (useLineEndingsForPlatform) {
+      expected = normalizeNewlinesForPlatform(expected);
+    }
     _offset = findOffset(snippet);
     _length = length;
     var assist = await _assertHasAssist();
@@ -134,6 +143,10 @@
 
   @override
   Future<void> resolveTestUnit(String code) async {
+    if (useLineEndingsForPlatform) {
+      code = normalizeNewlinesForPlatform(code);
+    }
+    final eol = code.contains('\r\n') ? '\r\n' : '\n';
     var offset = code.indexOf('/*caret*/');
     if (offset >= 0) {
       var endOffset = offset + '/*caret*/'.length;
@@ -141,13 +154,13 @@
       _offset = offset;
       _length = 0;
     } else {
-      var startOffset = code.indexOf('// start\n');
-      var endOffset = code.indexOf('// end\n');
+      var startOffset = code.indexOf('// start$eol');
+      var endOffset = code.indexOf('// end$eol');
       if (startOffset >= 0 && endOffset >= 0) {
-        var startLength = '// start\n'.length;
+        var startLength = '// start$eol'.length;
         code = code.substring(0, startOffset) +
             code.substring(startOffset + startLength, endOffset) +
-            code.substring(endOffset + '// end\n'.length);
+            code.substring(endOffset + '// end$eol'.length);
         _offset = startOffset;
         _length = endOffset - startLength - _offset;
       } else {
@@ -158,6 +171,12 @@
     return super.resolveTestUnit(code);
   }
 
+  @override
+  void setUp() {
+    super.setUp();
+    useLineEndingsForPlatform = true;
+  }
+
   /// Computes assists and verifies that there is an assist of the given kind.
   Future<Assist> _assertHasAssist() async {
     var assists = await _computeAssists();
diff --git a/pkg/analysis_server/test/src/services/correction/assist/flutter_convert_to_children_test.dart b/pkg/analysis_server/test/src/services/correction/assist/flutter_convert_to_children_test.dart
index b34b23d..f2db30e 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/flutter_convert_to_children_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/flutter_convert_to_children_test.dart
@@ -19,6 +19,13 @@
   @override
   AssistKind get kind => DartAssistKind.FLUTTER_CONVERT_TO_CHILDREN;
 
+  @override
+  void setUp() {
+    super.setUp();
+    // TODO(dantup): Get these tests passing with either line ending.
+    useLineEndingsForPlatform = false;
+  }
+
   Future<void> test_childUnresolved() async {
     addFlutterPackage();
     verifyNoTestUnitErrors = false;
diff --git a/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_generic_test.dart b/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_generic_test.dart
index 794cc11..d53dda2 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_generic_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/flutter_wrap_generic_test.dart
@@ -19,6 +19,13 @@
   @override
   AssistKind get kind => DartAssistKind.FLUTTER_WRAP_GENERIC;
 
+  @override
+  void setUp() {
+    super.setUp();
+    // TODO(dantup): Get these tests passing with either line ending.
+    useLineEndingsForPlatform = false;
+  }
+
   Future<void> test_minimal() async {
     addFlutterPackage();
     await resolveTestUnit('''
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_flutter_child_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_flutter_child_test.dart
index 3e17f59..c4268d2 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/convert_flutter_child_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_flutter_child_test.dart
@@ -19,6 +19,13 @@
   @override
   FixKind get kind => DartFixKind.CONVERT_FLUTTER_CHILD;
 
+  @override
+  void setUp() {
+    super.setUp();
+    // TODO(dantup): Get these tests passing with either line ending.
+    useLineEndingsForPlatform = false;
+  }
+
   Future<void> test_hasList() async {
     addFlutterPackage();
     await resolveTestUnit('''
diff --git a/pkg/analysis_server/test/src/services/correction/fix/create_local_variable_test.dart b/pkg/analysis_server/test/src/services/correction/fix/create_local_variable_test.dart
index e9253d7..a57a686 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/create_local_variable_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/create_local_variable_test.dart
@@ -20,6 +20,13 @@
   @override
   FixKind get kind => DartFixKind.CREATE_LOCAL_VARIABLE;
 
+  @override
+  void setUp() {
+    super.setUp();
+    // TODO(dantup): Get these tests passing with either line ending.
+    useLineEndingsForPlatform = false;
+  }
+
   Future<void> test_functionType_named() async {
     await resolveTestUnit('''
 typedef MY_FUNCTION(int p);
diff --git a/pkg/analysis_server/test/src/services/correction/fix/create_missing_overrides_test.dart b/pkg/analysis_server/test/src/services/correction/fix/create_missing_overrides_test.dart
index 5103e74..d397540 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/create_missing_overrides_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/create_missing_overrides_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analysis_server/src/services/correction/fix.dart';
+import 'package:analyzer/src/dart/analysis/experiments.dart';
 import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -12,6 +13,7 @@
 void main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(CreateMissingOverridesTest);
+    defineReflectiveTests(CreateMissingOverridesWithNullSafetyTest);
   });
 }
 
@@ -197,34 +199,6 @@
 ''');
   }
 
-  Future<void> test_lineEndings() async {
-    // TODO(dantup): Remove the need for this here, and have all of the tests
-    // test with CRLF when running on Windows.
-    final newlineWithoutCarriageReturn = RegExp(r'(?<!\r)\n');
-    String asCrLf(String input) =>
-        input.replaceAll(newlineWithoutCarriageReturn, '\r\n');
-    await resolveTestUnit(asCrLf('''
-class A {
-  void ma() {}
-}
-
-class B implements A {
-}
-'''));
-    await assertHasFix(asCrLf('''
-class A {
-  void ma() {}
-}
-
-class B implements A {
-  @override
-  void ma() {
-    // TODO: implement ma
-  }
-}
-'''));
-  }
-
   Future<void> test_mergeToField_getterSetter() async {
     await resolveTestUnit('''
 class A {
@@ -606,3 +580,58 @@
 ''');
   }
 }
+
+@reflectiveTest
+class CreateMissingOverridesWithNullSafetyTest extends FixProcessorTest {
+  @override
+  List<String> get experiments => [EnableString.non_nullable];
+
+  @override
+  FixKind get kind => DartFixKind.CREATE_MISSING_OVERRIDES;
+
+  Future<void> test_method_generic_nullable_dynamic() async {
+    // https://github.com/dart-lang/sdk/issues/43535
+    await resolveTestUnit('''
+class A {
+  void doSomething(Map<String, dynamic>? m) {}
+}
+
+class B implements A {}
+''');
+    await assertHasFix('''
+class A {
+  void doSomething(Map<String, dynamic>? m) {}
+}
+
+class B implements A {
+  @override
+  void doSomething(Map<String, dynamic>? m) {
+    // TODO: implement doSomething
+  }
+}
+''');
+  }
+
+  Future<void> test_method_generic_nullable_Never() async {
+    // https://github.com/dart-lang/sdk/issues/43535
+    await resolveTestUnit('''
+class A {
+  void doSomething(Map<String, Never>? m) {}
+}
+
+class B implements A {}
+''');
+    await assertHasFix('''
+class A {
+  void doSomething(Map<String, Never>? m) {}
+}
+
+class B implements A {
+  @override
+  void doSomething(Map<String, Never>? m) {
+    // TODO: implement doSomething
+  }
+}
+''');
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/add_type_parameter_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/add_type_parameter_test.dart
index e83eb02..c36b226 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/add_type_parameter_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/add_type_parameter_test.dart
@@ -458,7 +458,7 @@
       Transform(
           title: 'title',
           element: ElementDescriptor(
-              libraryUris: [importUri],
+              libraryUris: [Uri.parse(importUri)],
               // The kind isn't important to these tests.
               kind: '',
               components: components ?? ['C', 'm']),
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/code_template_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/code_template_test.dart
index 5713fb6..4802e4a 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/code_template_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/code_template_test.dart
@@ -7,6 +7,7 @@
 import 'package:analysis_server/src/services/correction/fix/data_driven/value_generator.dart';
 import 'package:analysis_server/src/services/correction/util.dart';
 import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -76,7 +77,14 @@
     var statement = body.block.statements[0] as ExpressionStatement;
     var node = statement.expression;
     var template = CodeTemplate(CodeTemplateKind.expression, components);
-    var result = template.generate(node, CorrectionUtils(testAnalysisResult));
+    var builder = ChangeBuilder(session: session);
+    var context = TemplateContext(node, CorrectionUtils(testAnalysisResult));
+    await builder.addDartFileEdit(testFile, (builder) {
+      builder.addInsertion(0, (builder) {
+        template.writeOn(builder, context);
+      });
+    });
+    var result = builder.sourceChange.edits[0].edits[0].replacement;
     expect(result, expectedResult);
   }
 
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/modify_parameters_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/modify_parameters_test.dart
index f0adabd..6d5e0aa 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/modify_parameters_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/modify_parameters_test.dart
@@ -877,7 +877,7 @@
       Transform(
           title: 'title',
           element: ElementDescriptor(
-              libraryUris: [importUri],
+              libraryUris: [Uri.parse(importUri)],
               // The kind isn't important to these tests.
               kind: '',
               components: originalComponents),
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/rename_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/rename_test.dart
index 4aff96a..0bd6479 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/rename_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/rename_test.dart
@@ -1036,7 +1036,9 @@
   Transform _rename(List<String> components, String newName) => Transform(
           title: 'title',
           element: ElementDescriptor(
-              libraryUris: [importUri], kind: _kind, components: components),
+              libraryUris: [Uri.parse(importUri)],
+              kind: _kind,
+              components: components),
           changes: [
             Rename(newName: newName),
           ]);
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test.dart
index 9e8c38a..45e1702 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test.dart
@@ -23,6 +23,8 @@
 
 @reflectiveTest
 class TransformSetParserTest extends AbstractTransformSetParserTest {
+  List<Uri> get uris => [Uri.parse('package:myPackage/test.dart')];
+
   void test_addParameter_optionalNamed() {
     parse('''
 version: 1
@@ -44,7 +46,7 @@
             kind: 'argument'
             index: 1
 ''');
-    var transforms = result.transformsFor('f', ['test.dart']);
+    var transforms = result.transformsFor('f', uris);
     expect(transforms, hasLength(1));
     var transform = transforms[0];
     expect(transform.title, 'Add');
@@ -80,7 +82,7 @@
       name: 'p'
       style: optional_positional
 ''');
-    var transforms = result.transformsFor('f', ['test.dart']);
+    var transforms = result.transformsFor('f', uris);
     expect(transforms, hasLength(1));
     var transform = transforms[0];
     expect(transform.title, 'Add');
@@ -116,7 +118,7 @@
             kind: 'argument'
             index: 1
 ''');
-    var transforms = result.transformsFor('f', ['test.dart']);
+    var transforms = result.transformsFor('f', uris);
     expect(transforms, hasLength(1));
     var transform = transforms[0];
     expect(transform.title, 'Add');
@@ -158,7 +160,7 @@
             kind: 'argument'
             index: 1
 ''');
-    var transforms = result.transformsFor('f', ['test.dart']);
+    var transforms = result.transformsFor('f', uris);
     expect(transforms, hasLength(1));
     var transform = transforms[0];
     expect(transform.title, 'Add');
@@ -203,7 +205,7 @@
             kind: 'argument'
             index: 2
 ''');
-    var transforms = result.transformsFor('f', ['test.dart']);
+    var transforms = result.transformsFor('f', uris);
     expect(transforms, hasLength(1));
     var transform = transforms[0];
     expect(transform.title, 'Add');
@@ -252,7 +254,7 @@
             uris: ['dart:core']
             name: 'String'
 ''');
-    var transforms = result.transformsFor('A', ['test.dart']);
+    var transforms = result.transformsFor('A', uris);
     expect(transforms, hasLength(1));
     var transform = transforms[0];
     expect(transform.title, 'Add');
@@ -263,7 +265,7 @@
     var components = change.argumentValue.components;
     expect(components, hasLength(1));
     var value = (components[0] as TemplateVariable).generator as ImportedName;
-    expect(value.uris, ['dart:core']);
+    expect(value.uris, [Uri.parse('dart:core')]);
     expect(value.name, 'String');
   }
 
@@ -288,7 +290,7 @@
             kind: 'argument'
             name: 'p'
 ''');
-    var transforms = result.transformsFor('A', ['test.dart']);
+    var transforms = result.transformsFor('A', uris);
     expect(transforms, hasLength(1));
     var transform = transforms[0];
     expect(transform.title, 'Add');
@@ -329,7 +331,7 @@
             kind: 'argument'
             index: 2
 ''');
-    var transforms = result.transformsFor('A', ['test.dart']);
+    var transforms = result.transformsFor('A', uris);
     expect(transforms, hasLength(1));
     var transform = transforms[0];
     expect(transform.title, 'Add');
@@ -361,7 +363,7 @@
     getter: 'g'
   changes: []
 ''');
-    var transforms = result.transformsFor('g', ['test.dart']);
+    var transforms = result.transformsFor('g', uris);
     expect(transforms, hasLength(1));
     var transform = transforms[0];
     expect(transform.title, 'Rename g');
@@ -380,7 +382,7 @@
     inMixin: 'A'
   changes: []
 ''');
-    var transforms = result.transformsFor('g', ['test.dart']);
+    var transforms = result.transformsFor('g', uris);
     expect(transforms, hasLength(1));
     var transform = transforms[0];
     expect(transform.title, 'Rename g');
@@ -398,7 +400,7 @@
     getter: 'g'
   changes: []
 ''');
-    var transforms = result.transformsFor('g', ['test.dart']);
+    var transforms = result.transformsFor('g', uris);
     expect(transforms, hasLength(1));
     var transform = transforms[0];
     expect(transform.title, 'Rename g');
@@ -417,7 +419,7 @@
     inClass: 'A'
   changes: []
 ''');
-    var transforms = result.transformsFor('m', ['test.dart']);
+    var transforms = result.transformsFor('m', uris);
     expect(transforms, hasLength(1));
     var transform = transforms[0];
     expect(transform.title, 'Rename m');
@@ -458,7 +460,7 @@
     - kind: 'removeParameter'
       name: 'p'
 ''');
-    var transforms = result.transformsFor('f', ['test.dart']);
+    var transforms = result.transformsFor('f', uris);
     expect(transforms, hasLength(1));
     var transform = transforms[0];
     expect(transform.title, 'Remove');
@@ -484,7 +486,7 @@
     - kind: 'removeParameter'
       index: 0
 ''');
-    var transforms = result.transformsFor('f', ['test.dart']);
+    var transforms = result.transformsFor('f', uris);
     expect(transforms, hasLength(1));
     var transform = transforms[0];
     expect(transform.title, 'Remove');
@@ -511,7 +513,7 @@
     - kind: 'rename'
       newName: 'B'
 ''');
-    var transforms = result.transformsFor('A', ['test.dart']);
+    var transforms = result.transformsFor('A', uris);
     expect(transforms, hasLength(1));
     var transform = transforms[0];
     expect(transform.title, 'Rename A');
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test_support.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test_support.dart
index 1fa4200..789ef46 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test_support.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test_support.dart
@@ -37,7 +37,7 @@
   void parse(String content) {
     errorListener = GatheringErrorListener();
     var errorReporter = ErrorReporter(errorListener, MockSource('data.yaml'));
-    var parser = TransformSetParser(errorReporter);
+    var parser = TransformSetParser(errorReporter, 'myPackage');
     result = parser.parse(content);
   }
 }
diff --git a/pkg/analysis_server/test/src/services/correction/fix/fix_processor.dart b/pkg/analysis_server/test/src/services/correction/fix/fix_processor.dart
index f5d7d59..a7fb58c 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/fix_processor.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/fix_processor.dart
@@ -11,6 +11,7 @@
 import 'package:analyzer/src/dart/analysis/byte_store.dart';
 import 'package:analyzer/src/dart/error/lint_codes.dart';
 import 'package:analyzer/src/services/available_declarations.dart';
+import 'package:analyzer/src/test_utilities/platform.dart';
 import 'package:analyzer_plugin/protocol/protocol_common.dart'
     hide AnalysisError;
 import 'package:analyzer_plugin/utilities/change_builder/change_workspace.dart';
@@ -86,6 +87,9 @@
       String target,
       int expectedNumberOfFixesForKind,
       String matchFixMessage}) async {
+    if (useLineEndingsForPlatform) {
+      expected = normalizeNewlinesForPlatform(expected);
+    }
     var error = await _findErrorToFix(errorFilter, length: length);
     var fix = await _assertHasFix(error,
         expectedNumberOfFixesForKind: expectedNumberOfFixesForKind,
@@ -108,6 +112,9 @@
 
   void assertHasFixAllFix(ErrorCode errorCode, String expected,
       {String target}) async {
+    if (useLineEndingsForPlatform) {
+      expected = normalizeNewlinesForPlatform(expected);
+    }
     var error = await _findErrorToFixOfType(errorCode);
     var fix = await _assertHasFixAllFix(error);
     change = fix.change;
@@ -169,6 +176,7 @@
   void setUp() {
     super.setUp();
     verifyNoTestUnitErrors = false;
+    useLineEndingsForPlatform = true;
     _createAnalysisOptionsFile();
   }
 
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_unused_import_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_unused_import_test.dart
index f3f154c..f54560f 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_unused_import_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_unused_import_test.dart
@@ -20,6 +20,13 @@
   @override
   FixKind get kind => DartFixKind.REMOVE_UNUSED_IMPORT;
 
+  @override
+  void setUp() {
+    super.setUp();
+    // TODO(dantup): Get these tests passing with either line ending.
+    useLineEndingsForPlatform = false;
+  }
+
   Future<void> test_all_diverseImports() async {
     await resolveTestUnit('''
 import 'dart:math';
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_unused_parameter_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_unused_parameter_test.dart
index 3d8e7ef..f35360f 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_unused_parameter_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_unused_parameter_test.dart
@@ -63,7 +63,7 @@
 class C {
   C(int b = 1,);
 }
-''', errorFilter: (e) => e.offset == 14);
+''', errorFilter: (e) => e.offset == testCode.indexOf('int a'));
   }
 
   Future<void> test_first_requiredPositional_second_optionalNamed() async {
diff --git a/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java b/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java
index ee2d987..f3f3dd1 100644
--- a/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java
+++ b/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java
@@ -574,6 +574,10 @@
    *
    * Return the set of fixes that are available for the errors at a given offset in a given file.
    *
+   * If a request is made for a file which does not exist, or which is not currently subject to
+   * analysis (e.g. because it is not associated with any analysis root specified to
+   * analysis.setAnalysisRoots), an error of type GET_FIXES_INVALID_FILE will be generated.
+   *
    * @param file The file containing the errors for which fixes are being requested.
    * @param offset The offset used to select the errors for which fixes will be returned.
    */
diff --git a/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java b/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java
index 0129bac..44da4d7 100644
--- a/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java
+++ b/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java
@@ -77,6 +77,12 @@
   public static final String GET_ERRORS_INVALID_FILE = "GET_ERRORS_INVALID_FILE";
 
   /**
+   * An "edit.getFixes" request specified a FilePath which does not match a file currently subject to
+   * analysis.
+   */
+  public static final String GET_FIXES_INVALID_FILE = "GET_FIXES_INVALID_FILE";
+
+  /**
    * An "analysis.getImportedElements" request specified a FilePath that does not match a file
    * currently subject to analysis.
    */
diff --git a/pkg/analysis_server/tool/spec/spec_input.html b/pkg/analysis_server/tool/spec/spec_input.html
index 0247bb1..6bcf904 100644
--- a/pkg/analysis_server/tool/spec/spec_input.html
+++ b/pkg/analysis_server/tool/spec/spec_input.html
@@ -7,7 +7,7 @@
 <body>
 <h1>Analysis Server API Specification</h1>
 <h1 style="color:#999999">Version
-  <version>1.29.0</version>
+  <version>1.29.1</version>
 </h1>
 <p>
   This document contains a specification of the API provided by the
@@ -2345,6 +2345,13 @@
       Return the set of fixes that are available for the errors at
       a given offset in a given file.
     </p>
+    <p>
+      If a request is made for a file which does not exist, or
+      which is not currently subject to analysis (e.g. because it
+      is not associated with any analysis root specified to
+      analysis.setAnalysisRoots), an error of type
+      <tt>GET_FIXES_INVALID_FILE</tt> will be generated.
+    </p>
     <params>
       <field name="file">
         <ref>FilePath</ref>
@@ -5004,6 +5011,14 @@
         </p>
       </value>
       <value>
+        <code>GET_FIXES_INVALID_FILE</code>
+        <p>
+          An "edit.getFixes" request specified a FilePath
+          which does not match a file currently subject to
+          analysis.
+        </p>
+      </value>
+      <value>
         <code>GET_IMPORTED_ELEMENTS_INVALID_FILE</code>
         <p>
           An "analysis.getImportedElements" request specified a FilePath that
diff --git a/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart b/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart
index 8bfb877..76c886f 100644
--- a/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart
+++ b/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart
@@ -6,7 +6,7 @@
 // To regenerate the file, use the script
 // "pkg/analysis_server/tool/spec/generate_files".
 
-const String PROTOCOL_VERSION = '1.29.0';
+const String PROTOCOL_VERSION = '1.29.1';
 
 const String ANALYSIS_NOTIFICATION_ANALYZED_FILES = 'analysis.analyzedFiles';
 const String ANALYSIS_NOTIFICATION_ANALYZED_FILES_DIRECTORIES = 'directories';
diff --git a/pkg/analysis_server_client/lib/src/protocol/protocol_generated.dart b/pkg/analysis_server_client/lib/src/protocol/protocol_generated.dart
index 29ae9ac..b6d697f 100644
--- a/pkg/analysis_server_client/lib/src/protocol/protocol_generated.dart
+++ b/pkg/analysis_server_client/lib/src/protocol/protocol_generated.dart
@@ -17810,6 +17810,7 @@
 ///   FORMAT_INVALID_FILE
 ///   FORMAT_WITH_ERRORS
 ///   GET_ERRORS_INVALID_FILE
+///   GET_FIXES_INVALID_FILE
 ///   GET_IMPORTED_ELEMENTS_INVALID_FILE
 ///   GET_KYTHE_ENTRIES_INVALID_FILE
 ///   GET_NAVIGATION_INVALID_FILE
@@ -17891,6 +17892,11 @@
   static const RequestErrorCode GET_ERRORS_INVALID_FILE =
       RequestErrorCode._('GET_ERRORS_INVALID_FILE');
 
+  /// An "edit.getFixes" request specified a FilePath which does not match a
+  /// file currently subject to analysis.
+  static const RequestErrorCode GET_FIXES_INVALID_FILE =
+      RequestErrorCode._('GET_FIXES_INVALID_FILE');
+
   /// An "analysis.getImportedElements" request specified a FilePath that does
   /// not match a file currently subject to analysis.
   static const RequestErrorCode GET_IMPORTED_ELEMENTS_INVALID_FILE =
@@ -18022,6 +18028,7 @@
     FORMAT_INVALID_FILE,
     FORMAT_WITH_ERRORS,
     GET_ERRORS_INVALID_FILE,
+    GET_FIXES_INVALID_FILE,
     GET_IMPORTED_ELEMENTS_INVALID_FILE,
     GET_KYTHE_ENTRIES_INVALID_FILE,
     GET_NAVIGATION_INVALID_FILE,
@@ -18076,6 +18083,8 @@
         return FORMAT_WITH_ERRORS;
       case 'GET_ERRORS_INVALID_FILE':
         return GET_ERRORS_INVALID_FILE;
+      case 'GET_FIXES_INVALID_FILE':
+        return GET_FIXES_INVALID_FILE;
       case 'GET_IMPORTED_ELEMENTS_INVALID_FILE':
         return GET_IMPORTED_ELEMENTS_INVALID_FILE;
       case 'GET_KYTHE_ENTRIES_INVALID_FILE':
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index 9312ea8..e65f60b 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -514,6 +514,7 @@
   HintCode.INVALID_REQUIRED_OPTIONAL_POSITIONAL_PARAM,
   HintCode.INVALID_REQUIRED_POSITIONAL_PARAM,
   HintCode.INVALID_SEALED_ANNOTATION,
+  HintCode.INVALID_USE_OF_INTERNAL_MEMBER,
   HintCode.INVALID_USE_OF_PROTECTED_MEMBER,
   HintCode.INVALID_USE_OF_VISIBLE_FOR_TEMPLATE_MEMBER,
   HintCode.INVALID_USE_OF_VISIBLE_FOR_TESTING_MEMBER,
diff --git a/pkg/analyzer/lib/src/dart/analysis/experiments.g.dart b/pkg/analyzer/lib/src/dart/analysis/experiments.g.dart
index 74f160b..9f390a8 100644
--- a/pkg/analyzer/lib/src/dart/analysis/experiments.g.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/experiments.g.dart
@@ -8,7 +8,7 @@
 
 /// The current version of the Dart language (or, for non-stable releases, the
 /// version of the language currently in the process of being developed).
-const _currentVersion = '2.10.0';
+const _currentVersion = '2.11.0';
 
 /// A map containing information about all known experimental flags.
 final _knownFeatures = <String, ExperimentalFeature>{
diff --git a/pkg/analyzer/lib/src/dart/element/scope.dart b/pkg/analyzer/lib/src/dart/element/scope.dart
index fa08358..d04ddfa 100644
--- a/pkg/analyzer/lib/src/dart/element/scope.dart
+++ b/pkg/analyzer/lib/src/dart/element/scope.dart
@@ -184,12 +184,16 @@
   final Map<String, Element> _getters = {};
   final Map<String, Element> _setters = {};
   final Set<ExtensionElement> _extensions = {};
+  LibraryElement _deferredLibrary;
 
   PrefixScope(this._library, PrefixElement prefix) {
     for (var import in _library.imports) {
       if (import.prefix == prefix) {
         var elements = impl.NamespaceBuilder().getImportedElements(import);
         elements.forEach(_add);
+        if (import.isDeferred) {
+          _deferredLibrary ??= import.importedLibrary;
+        }
       }
     }
   }
@@ -203,6 +207,10 @@
 
   @override
   ScopeLookupResult lookup2(String id) {
+    if (_deferredLibrary != null && id == FunctionElement.LOAD_LIBRARY_NAME) {
+      return ScopeLookupResult(_deferredLibrary.loadLibraryFunction, null);
+    }
+
     var getter = _getters[id];
     var setter = _setters[id];
     return ScopeLookupResult(getter, setter);
diff --git a/pkg/analyzer/lib/src/dart/element/type_constraint_gatherer.dart b/pkg/analyzer/lib/src/dart/element/type_constraint_gatherer.dart
index 21cdd9c..c3040b2 100644
--- a/pkg/analyzer/lib/src/dart/element/type_constraint_gatherer.dart
+++ b/pkg/analyzer/lib/src/dart/element/type_constraint_gatherer.dart
@@ -139,8 +139,19 @@
 
     // If `Q` is a legacy type `Q0*` then the match holds under constraint
     // set `C`:
-    //   Only if `P` is a subtype match for `Q?` under constraint set `C`.
     if (Q_nullability == NullabilitySuffix.star) {
+      // If `P` is `dynamic` or `void` and `P` is a subtype match
+      // for `Q0` under constraint set `C`.
+      if (identical(P, DynamicTypeImpl.instance) ||
+          identical(P, VoidTypeImpl.instance)) {
+        var rewind = _constraints.length;
+        var Q0 = (Q as TypeImpl).withNullability(NullabilitySuffix.none);
+        if (trySubtypeMatch(P, Q0, leftSchema)) {
+          return true;
+        }
+        _constraints.length = rewind;
+      }
+      // Or if `P` is a subtype match for `Q0?` under constraint set `C`.
       var Qq = (Q as TypeImpl).withNullability(NullabilitySuffix.question);
       return trySubtypeMatch(P, Qq, leftSchema);
     }
@@ -201,6 +212,16 @@
         _constraints.length = rewind;
       }
 
+      // Or if `P` is `dynamic` or `void` and `Object` is a subtype match
+      // for `Q0` under constraint set `C`.
+      if (identical(P, DynamicTypeImpl.instance) ||
+          identical(P, VoidTypeImpl.instance)) {
+        if (trySubtypeMatch(_typeSystem.objectNone, Q0, leftSchema)) {
+          return true;
+        }
+        _constraints.length = rewind;
+      }
+
       // Or if `P` is a subtype match for `Q0` under non-empty
       // constraint set `C`.
       var P_matches_Q0 = trySubtypeMatch(P, Q0, leftSchema);
diff --git a/pkg/analyzer/lib/src/dart/error/hint_codes.dart b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
index 9be0aa2..fb65bd2 100644
--- a/pkg/analyzer/lib/src/dart/error/hint_codes.dart
+++ b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
@@ -943,6 +943,17 @@
       correction: "Remove @sealed.");
 
   /**
+   * This hint is generated anywhere where a member annotated with `@internal`
+   * is used outside of the package in which it is declared.
+   *
+   * Parameters:
+   * 0: the name of the member
+   */
+  static const HintCode INVALID_USE_OF_INTERNAL_MEMBER = HintCode(
+      'INVALID_USE_OF_INTERNAL_MEMBER',
+      "The member '{0}' can only be used within its package.");
+
+  /**
    * This hint is generated anywhere where a member annotated with `@protected`
    * is used outside of an instance member of a subclass.
    *
diff --git a/pkg/analyzer/lib/src/dart/micro/libraries_log.dart b/pkg/analyzer/lib/src/dart/micro/libraries_log.dart
new file mode 100644
index 0000000..a67988b
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/micro/libraries_log.dart
@@ -0,0 +1,88 @@
+// 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.
+
+import 'package:meta/meta.dart';
+
+class ChangeFileLoadEntry extends LibrariesLogEntry {
+  /// The path of the file that was reported as changed.
+  final String target;
+
+  /// The files that depend transitively on the [target]. These files are
+  /// removed from the state, and from the element factory.
+  final List<LibrariesLogFile> removed = [];
+
+  ChangeFileLoadEntry._(this.target);
+
+  void addRemoved({
+    @required String path,
+    @required Uri uri,
+  }) {
+    removed.add(
+      LibrariesLogFile._(path, uri),
+    );
+  }
+
+  @override
+  String toString() {
+    return 'Change(target: $target, removed: $removed)';
+  }
+}
+
+class LibrariesLog {
+  final List<LibrariesLogEntry> entries = [];
+
+  ChangeFileLoadEntry changeFile(String path) {
+    var entry = ChangeFileLoadEntry._(path);
+    entries.add(entry);
+    return entry;
+  }
+
+  LoadLibrariesForTargetLogEntry loadForTarget({
+    @required String path,
+    @required Uri uri,
+  }) {
+    var entry = LoadLibrariesForTargetLogEntry._(
+      LibrariesLogFile._(path, uri),
+    );
+    entries.add(entry);
+    return entry;
+  }
+}
+
+abstract class LibrariesLogEntry {
+  final DateTime time = DateTime.now();
+}
+
+class LibrariesLogFile {
+  final String path;
+  final Uri uri;
+
+  LibrariesLogFile._(this.path, this.uri);
+
+  @override
+  String toString() {
+    return '(path: $path, uri: $uri)';
+  }
+}
+
+class LoadLibrariesForTargetLogEntry extends LibrariesLogEntry {
+  final LibrariesLogFile target;
+  final List<LibrariesLogFile> loaded = [];
+
+  LoadLibrariesForTargetLogEntry._(this.target);
+
+  void addLibrary({
+    @required String path,
+    @required Uri uri,
+  }) {
+    loaded.add(
+      LibrariesLogFile._(path, uri),
+    );
+  }
+
+  @override
+  String toString() {
+    return 'Load(target: $target, loaded: $loaded)';
+  }
+}
diff --git a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
index 7d07bcf..206d69c 100644
--- a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
+++ b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
@@ -20,8 +20,10 @@
 import 'package:analyzer/src/dart/analysis/results.dart';
 import 'package:analyzer/src/dart/micro/analysis_context.dart';
 import 'package:analyzer/src/dart/micro/cider_byte_store.dart';
+import 'package:analyzer/src/dart/micro/libraries_log.dart';
 import 'package:analyzer/src/dart/micro/library_analyzer.dart';
 import 'package:analyzer/src/dart/micro/library_graph.dart';
+import 'package:analyzer/src/exception/exception.dart';
 import 'package:analyzer/src/generated/engine.dart'
     show AnalysisEngine, AnalysisOptionsImpl;
 import 'package:analyzer/src/generated/source.dart';
@@ -73,6 +75,8 @@
 
   MicroContextObjects contextObjects;
 
+  final LibrariesLog _librariesLog = LibrariesLog();
+
   _LibraryContext libraryContext;
 
   FileResolver(
@@ -117,6 +121,10 @@
     );
   }
 
+  List<LibrariesLogEntry> get librariesLogEntries {
+    return _librariesLog.entries;
+  }
+
   /// Update the resolver to reflect the fact that the file with the given
   /// [path] was changed. We need to make sure that when this file, of any file
   /// that directly or indirectly referenced it, is resolved, we used the new
@@ -130,6 +138,15 @@
     var removedFiles = <FileState>[];
     fsState.changeFile(path, removedFiles);
 
+    // Update the log.
+    var logEntry = _librariesLog.changeFile(path);
+    for (var removedFile in removedFiles) {
+      logEntry.addRemoved(
+        path: removedFile.path,
+        uri: removedFile.uri,
+      );
+    }
+
     // Remove libraries represented by removed files.
     // If we need these libraries later, we will relink and reattach them.
     if (libraryContext != null) {
@@ -307,15 +324,28 @@
             (file) => file.getContentWithSameDigest(),
           );
 
-          results = performance.run('analyze', (performance) {
-            return NullSafetyUnderstandingFlag.enableNullSafetyTypes(() {
-              return libraryAnalyzer.analyzeSync(
-                completionPath: completionOffset != null ? path : null,
-                completionOffset: completionOffset,
-                performance: performance,
-              );
+          try {
+            results = performance.run('analyze', (performance) {
+              return NullSafetyUnderstandingFlag.enableNullSafetyTypes(() {
+                return libraryAnalyzer.analyzeSync(
+                  completionPath: completionOffset != null ? path : null,
+                  completionOffset: completionOffset,
+                  performance: performance,
+                );
+              });
             });
-          });
+          } catch (exception, stackTrace) {
+            var fileContentMap = <String, String>{};
+            for (var file in libraryFile.libraryFiles) {
+              var path = file.path;
+              fileContentMap[path] = _getFileContent(path);
+            }
+            throw CaughtExceptionWithFiles(
+              exception,
+              stackTrace,
+              fileContentMap,
+            );
+          }
         });
         UnitAnalysisResult fileResult = results[file];
 
@@ -398,6 +428,7 @@
         resourceProvider,
         byteStore,
         contextObjects,
+        _librariesLog,
       );
     }
   }
@@ -539,6 +570,7 @@
   final ResourceProvider resourceProvider;
   final CiderByteStore byteStore;
   final MicroContextObjects contextObjects;
+  final LibrariesLog librariesLog;
 
   LinkedElementFactory elementFactory;
 
@@ -549,6 +581,7 @@
     this.resourceProvider,
     this.byteStore,
     this.contextObjects,
+    this.librariesLog,
   ) {
     // TODO(scheglov) remove it?
     _createElementFactory();
@@ -565,9 +598,21 @@
     var librariesLinkedTimer = Stopwatch();
     var inputsTimer = Stopwatch();
 
+    var logEntry = librariesLog.loadForTarget(
+      path: targetLibrary.path,
+      uri: targetLibrary.uri,
+    );
+
     void loadBundle(LibraryCycle cycle) {
       if (!loadedBundles.add(cycle)) return;
 
+      for (var library in cycle.libraries) {
+        logEntry.addLibrary(
+          path: library.path,
+          uri: library.uri,
+        );
+      }
+
       performance.getDataInt('cycleCount').increment();
       performance.getDataInt('libraryCount').add(cycle.libraries.length);
 
diff --git a/pkg/analyzer/lib/src/dart/resolver/annotation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/annotation_resolver.dart
new file mode 100644
index 0000000..92fef68
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/resolver/annotation_resolver.dart
@@ -0,0 +1,343 @@
+// 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.
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/error/listener.dart';
+import 'package:analyzer/src/dart/constant/utilities.dart';
+import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/dart/resolver/property_element_resolver.dart';
+import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/resolver.dart';
+
+class AnnotationResolver {
+  final ResolverVisitor _resolver;
+
+  AnnotationResolver(this._resolver);
+
+  LibraryElement get _definingLibrary => _resolver.definingLibrary;
+
+  ErrorReporter get _errorReporter => _resolver.errorReporter;
+
+  void resolve(Annotation node) {
+    AstNode parent = node.parent;
+
+    _resolve1(node);
+
+    node.constructorName?.accept(_resolver);
+    Element element = node.element;
+    if (element is ExecutableElement) {
+      InferenceContext.setType(node.arguments, element.type);
+    }
+    node.arguments?.accept(_resolver);
+
+    ElementAnnotationImpl elementAnnotationImpl = node.elementAnnotation;
+    if (elementAnnotationImpl == null) {
+      // Analyzer ignores annotations on "part of" directives.
+      assert(parent is PartOfDirective);
+    } else {
+      elementAnnotationImpl.annotationAst = _createCloner().cloneNode(node);
+    }
+  }
+
+  /// Return a newly created cloner that can be used to clone constant
+  /// expressions.
+  ///
+  /// TODO(scheglov) this is duplicate
+  ConstantAstCloner _createCloner() {
+    return ConstantAstCloner();
+  }
+
+  InterfaceType _instantiateAnnotationClass(ClassElement element) {
+    return element.instantiate(
+      typeArguments: List.filled(
+        element.typeParameters.length,
+        DynamicTypeImpl.instance,
+      ),
+      nullabilitySuffix: _resolver.noneOrStarSuffix,
+    );
+  }
+
+  void _resolve1(Annotation node) {
+    var nodeName = node.name;
+
+    if (nodeName is PrefixedIdentifier) {
+      var prefix = nodeName.prefix;
+      var identifier = nodeName.identifier;
+
+      prefix.accept(_resolver);
+      var prefixElement = prefix.staticElement;
+
+      if (prefixElement is ClassElement && node.arguments != null) {
+        var element = prefixElement.getNamedConstructor(identifier.name);
+        element = _resolver.toLegacyElement(element);
+
+        identifier.staticElement = element;
+        identifier.staticType = element?.type ?? DynamicTypeImpl.instance;
+        // TODO(scheglov) error?
+      } else if (prefixElement is PrefixElement) {
+        var resolver = PropertyElementResolver(_resolver);
+        var result = resolver.resolvePrefixedIdentifier(
+          node: nodeName,
+          hasRead: true,
+          hasWrite: false,
+          forAnnotation: true,
+        );
+
+        var element = result.readElement;
+        identifier.staticElement = element;
+
+        if (element == null) {
+          _errorReporter.reportErrorForNode(
+            CompileTimeErrorCode.UNDEFINED_ANNOTATION,
+            node,
+            [identifier.name],
+          );
+        }
+      } else {
+        var resolver = PropertyElementResolver(_resolver);
+        var result = resolver.resolvePrefixedIdentifier(
+          node: nodeName,
+          hasRead: true,
+          hasWrite: false,
+          forAnnotation: true,
+        );
+
+        var element = result.readElement;
+        identifier.staticElement = element;
+
+        DartType type;
+        if (element is PropertyAccessorElement && element.isGetter) {
+          type = element.returnType;
+        } else {
+          type = DynamicTypeImpl.instance;
+        }
+        identifier.staticType = type;
+      }
+    } else {
+      var identifier = nodeName as SimpleIdentifier;
+
+      var resolver = PropertyElementResolver(_resolver);
+      var result = resolver.resolveSimpleIdentifier(
+        node: identifier,
+        hasRead: true,
+        hasWrite: false,
+      );
+
+      var element = result.readElement;
+      identifier.staticElement = element;
+
+      if (element == null) {
+        _errorReporter.reportErrorForNode(
+          CompileTimeErrorCode.UNDEFINED_ANNOTATION,
+          node,
+          [identifier.name],
+        );
+      }
+
+      DartType type;
+      if (element is ClassElement) {
+        type = _resolver.typeProvider.typeType;
+      } else if (element is PropertyAccessorElement && element.isGetter) {
+        type = element.returnType;
+      } else {
+        type = DynamicTypeImpl.instance;
+      }
+      identifier.staticType = type;
+    }
+
+    _resolveAnnotationElement(node);
+  }
+
+  void _resolveAnnotationConstructorInvocationArguments(
+      Annotation annotation, ConstructorElement constructor) {
+    ArgumentList argumentList = annotation.arguments;
+    // error will be reported in ConstantVerifier
+    if (argumentList == null) {
+      return;
+    }
+    // resolve arguments to parameters
+    List<ParameterElement> parameters =
+        _resolveArgumentsToFunction(argumentList, constructor);
+    if (parameters != null) {
+      argumentList.correspondingStaticParameters = parameters;
+    }
+  }
+
+  /// Continues resolution of the given [annotation].
+  void _resolveAnnotationElement(Annotation annotation) {
+    SimpleIdentifier nameNode1;
+    SimpleIdentifier nameNode2;
+    {
+      Identifier annName = annotation.name;
+      if (annName is PrefixedIdentifier) {
+        nameNode1 = annName.prefix;
+        nameNode2 = annName.identifier;
+      } else {
+        nameNode1 = annName as SimpleIdentifier;
+        nameNode2 = null;
+      }
+    }
+    SimpleIdentifier nameNode3 = annotation.constructorName;
+    ConstructorElement constructor;
+    bool undefined = false;
+    //
+    // CONST or Class(args)
+    //
+    if (nameNode1 != null && nameNode2 == null && nameNode3 == null) {
+      Element element1 = nameNode1.staticElement;
+      // TODO(scheglov) Must be const.
+      if (element1 is VariableElement) {
+        return;
+      }
+      // CONST
+      if (element1 is PropertyAccessorElement) {
+        _resolveAnnotationElementGetter(annotation, element1);
+        return;
+      }
+      // Class(args)
+      if (element1 is ClassElement) {
+        constructor = _instantiateAnnotationClass(element1)
+            .lookUpConstructor(null, _definingLibrary);
+        constructor = _resolver.toLegacyElement(constructor);
+      } else if (element1 == null) {
+        undefined = true;
+      }
+    }
+    //
+    // prefix.CONST or prefix.Class() or Class.CONST or Class.constructor(args)
+    //
+    if (nameNode1 != null && nameNode2 != null && nameNode3 == null) {
+      Element element1 = nameNode1.staticElement;
+      Element element2 = nameNode2.staticElement;
+      // Class.CONST - not resolved yet
+      if (element1 is ClassElement) {
+        element2 = element1.lookUpGetter(nameNode2.name, _definingLibrary);
+        element2 = _resolver.toLegacyElement(element2);
+      }
+      // prefix.CONST or Class.CONST
+      if (element2 is PropertyAccessorElement) {
+        nameNode2.staticElement = element2;
+        annotation.element = element2;
+        _resolveAnnotationElementGetter(annotation, element2);
+        return;
+      }
+      // prefix.Class()
+      if (element2 is ClassElement) {
+        constructor = element2.unnamedConstructor;
+        constructor = _resolver.toLegacyElement(constructor);
+      }
+      // Class.constructor(args)
+      if (element1 is ClassElement) {
+        constructor = _instantiateAnnotationClass(element1)
+            .lookUpConstructor(nameNode2.name, _definingLibrary);
+        constructor = _resolver.toLegacyElement(constructor);
+        nameNode2.staticElement = constructor;
+      }
+      if (element1 is PrefixElement && element2 == null) {
+        undefined = true;
+      }
+      if (element1 == null && element2 == null) {
+        undefined = true;
+      }
+    }
+    //
+    // prefix.Class.CONST or prefix.Class.constructor(args)
+    //
+    if (nameNode1 != null && nameNode2 != null && nameNode3 != null) {
+      Element element2 = nameNode2.staticElement;
+      // element2 should be ClassElement
+      if (element2 is ClassElement) {
+        String name3 = nameNode3.name;
+        // prefix.Class.CONST
+        PropertyAccessorElement getter =
+            element2.lookUpGetter(name3, _definingLibrary);
+        if (getter != null) {
+          getter = _resolver.toLegacyElement(getter);
+          nameNode3.staticElement = getter;
+          annotation.element = getter;
+          _resolveAnnotationElementGetter(annotation, getter);
+          return;
+        }
+        // prefix.Class.constructor(args)
+        constructor = _instantiateAnnotationClass(element2)
+            .lookUpConstructor(name3, _definingLibrary);
+        constructor = _resolver.toLegacyElement(constructor);
+        nameNode3.staticElement = constructor;
+      } else if (element2 == null) {
+        undefined = true;
+      }
+    }
+    // we need constructor
+    if (constructor == null) {
+      if (!undefined) {
+        // If the class was not found then we've already reported the error.
+        _errorReporter.reportErrorForNode(
+            CompileTimeErrorCode.INVALID_ANNOTATION, annotation);
+      }
+      return;
+    }
+    // record element
+    annotation.element = constructor;
+    // resolve arguments
+    _resolveAnnotationConstructorInvocationArguments(annotation, constructor);
+  }
+
+  void _resolveAnnotationElementGetter(
+      Annotation annotation, PropertyAccessorElement accessorElement) {
+    // accessor should be synthetic
+    if (!accessorElement.isSynthetic) {
+      _errorReporter.reportErrorForNode(
+          CompileTimeErrorCode.INVALID_ANNOTATION_GETTER, annotation);
+      return;
+    }
+    // variable should be constant
+    VariableElement variableElement = accessorElement.variable;
+    if (!variableElement.isConst) {
+      _errorReporter.reportErrorForNode(
+          CompileTimeErrorCode.INVALID_ANNOTATION, annotation);
+      return;
+    }
+    // no arguments
+    if (annotation.arguments != null) {
+      _errorReporter.reportErrorForNode(
+          CompileTimeErrorCode.ANNOTATION_WITH_NON_CLASS,
+          annotation.name,
+          [annotation.name]);
+    }
+    // OK
+    return;
+  }
+
+  /// Given an [argumentList] and the [executableElement] that will be invoked
+  /// using those argument, compute the list of parameters that correspond to
+  /// the list of arguments. An error will be reported if any of the arguments
+  /// cannot be matched to a parameter. Return the parameters that correspond to
+  /// the arguments, or `null` if no correspondence could be computed.
+  ///
+  /// TODO(scheglov) this is duplicate
+  List<ParameterElement> _resolveArgumentsToFunction(
+      ArgumentList argumentList, ExecutableElement executableElement) {
+    if (executableElement == null) {
+      return null;
+    }
+    List<ParameterElement> parameters = executableElement.parameters;
+    return _resolveArgumentsToParameters(argumentList, parameters);
+  }
+
+  /// Given an [argumentList] and the [parameters] related to the element that
+  /// will be invoked using those arguments, compute the list of parameters that
+  /// correspond to the list of arguments. An error will be reported if any of
+  /// the arguments cannot be matched to a parameter. Return the parameters that
+  /// correspond to the arguments.
+  ///
+  /// TODO(scheglov) this is duplicate
+  List<ParameterElement> _resolveArgumentsToParameters(
+      ArgumentList argumentList, List<ParameterElement> parameters) {
+    return ResolverVisitor.resolveArgumentsToParameters(
+        argumentList, parameters, _errorReporter.reportErrorForNode);
+  }
+}
diff --git a/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
index 0190caa..59d39ff 100644
--- a/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
@@ -10,16 +10,12 @@
 import 'package:analyzer/error/listener.dart';
 import 'package:analyzer/src/dart/ast/ast.dart';
 import 'package:analyzer/src/dart/ast/token.dart';
-import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/type_system.dart';
 import 'package:analyzer/src/dart/resolver/flow_analysis_visitor.dart';
 import 'package:analyzer/src/dart/resolver/invocation_inference_helper.dart';
-import 'package:analyzer/src/dart/resolver/property_element_resolver.dart';
 import 'package:analyzer/src/dart/resolver/type_property_resolver.dart';
-import 'package:analyzer/src/error/assignment_verifier.dart';
 import 'package:analyzer/src/error/codes.dart';
-import 'package:analyzer/src/generated/migration.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:meta/meta.dart';
 
@@ -47,52 +43,66 @@
 
   bool get _isNonNullableByDefault => _typeSystem.isNonNullableByDefault;
 
-  MigrationResolutionHooks get _migrationResolutionHooks {
-    return _resolver.migrationResolutionHooks;
-  }
-
   TypeProvider get _typeProvider => _resolver.typeProvider;
 
   TypeSystemImpl get _typeSystem => _resolver.typeSystem;
 
   void resolve(AssignmentExpressionImpl node) {
+    var operator = node.operator.type;
+    var hasRead = operator != TokenType.EQ;
+    var isIfNull = operator == TokenType.QUESTION_QUESTION_EQ;
+
+    var leftResolution = _resolver.resolveForWrite(
+      node: node.leftHandSide,
+      hasRead: hasRead,
+    );
+
     var left = node.leftHandSide;
     var right = node.rightHandSide;
 
-    if (left is IndexExpression) {
-      _resolve_IndexExpression(node, left);
-      return;
+    var readElement = leftResolution.readElement;
+    var writeElement = leftResolution.writeElement;
+
+    if (hasRead) {
+      _resolver.setReadElement(left, readElement);
+    }
+    _resolver.setWriteElement(left, writeElement);
+
+    _resolver.setAssignmentBackwardCompatibility(
+      assignment: node,
+      left: left,
+      hasRead: hasRead,
+    );
+
+    _resolveOperator(node);
+
+    {
+      var leftType = node.writeType;
+      if (writeElement is VariableElement) {
+        leftType = _resolver.localVariableTypeProvider.getType(left);
+      }
+      _setRhsContext(node, leftType, operator, right);
     }
 
-    if (left is PrefixedIdentifier) {
-      _resolve_PrefixedIdentifier(node, left);
-      return;
+    var flow = _flowAnalysis?.flow;
+    if (flow != null && isIfNull) {
+      flow.ifNullExpression_rightBegin(left, node.readType);
     }
 
-    if (left is PropertyAccess) {
-      _resolve_PropertyAccess(node, left);
-      return;
-    }
+    right.accept(_resolver);
 
-    if (left is SimpleIdentifier) {
-      _resolve_SimpleIdentifier(node, left);
-      return;
-    }
+    _resolveTypes(node);
 
-    left?.accept(_resolver);
-    left = node.leftHandSide;
-
-    var operator = node.operator.type;
-    if (operator != TokenType.EQ) {
-      if (node.readElement == null || node.readType == null) {
-        _resolver.setReadElement(left, null);
+    if (flow != null) {
+      if (writeElement is VariableElement) {
+        flow.write(writeElement, node.staticType);
+      }
+      if (isIfNull) {
+        flow.ifNullExpression_end();
       }
     }
-    if (node.writeElement == null || node.writeType == null) {
-      _resolver.setWriteElement(left, null);
-    }
 
-    _resolve3(node, left, operator, right);
+    _resolver.nullShortingTermination(node);
   }
 
   void _checkForInvalidAssignment(
@@ -139,30 +149,8 @@
     return true;
   }
 
-  /// Record that the static type of the given node is the given type.
-  ///
-  /// @param expression the node whose type is to be recorded
-  /// @param type the static type of the node
-  ///
-  /// TODO(scheglov) this is duplication
-  void _recordStaticType(Expression expression, DartType type) {
-    if (_resolver.migrationResolutionHooks != null) {
-      type = _migrationResolutionHooks.modifyExpressionType(expression, type);
-    }
-
-    // TODO(scheglov) type cannot be null
-    if (type == null) {
-      expression.staticType = DynamicTypeImpl.instance;
-    } else {
-      expression.staticType = type;
-      if (_typeSystem.isBottom(type)) {
-        _flowAnalysis?.flow?.handleExit();
-      }
-    }
-  }
-
-  void _resolve1(AssignmentExpressionImpl node) {
-    var leftHandSide = node.leftHandSide;
+  void _resolveOperator(AssignmentExpressionImpl node) {
+    var left = node.leftHandSide;
     var operator = node.operator;
     var operatorType = operator.type;
 
@@ -171,7 +159,8 @@
       return;
     }
 
-    _assignmentShared.checkFinalAlreadyAssigned(leftHandSide);
+    // TODO(scheglov) Use VariableElement and do in resolveForWrite() ?
+    _assignmentShared.checkFinalAlreadyAssigned(left);
 
     // Values of the type void cannot be used.
     // Example: `y += 0`, is not allowed.
@@ -196,10 +185,10 @@
     var methodName = binaryOperatorType.lexeme;
 
     var result = _typePropertyResolver.resolve(
-      receiver: leftHandSide,
+      receiver: left,
       receiverType: leftType,
       name: methodName,
-      receiverErrorNode: leftHandSide,
+      receiverErrorNode: left,
       nameErrorEntity: operator,
     );
     node.staticElement = result.getter;
@@ -212,170 +201,6 @@
     }
   }
 
-  void _resolve3(AssignmentExpressionImpl node, Expression left,
-      TokenType operator, Expression right) {
-    _resolve1(node);
-
-    {
-      var leftType = node.writeType;
-      if (node.writeElement is VariableElement) {
-        leftType = _resolver.localVariableTypeProvider.getType(left);
-      }
-      _setRhsContext(node, leftType, operator, right);
-    }
-
-    var flow = _flowAnalysis?.flow;
-    if (flow != null && operator == TokenType.QUESTION_QUESTION_EQ) {
-      flow.ifNullExpression_rightBegin(left, node.readType);
-    }
-
-    right?.accept(_resolver);
-    right = node.rightHandSide;
-
-    _resolveTypes(node);
-
-    _resolver.nullShortingTermination(node);
-
-    if (flow != null) {
-      if (node.writeElement is VariableElement) {
-        flow.write(node.writeElement, node.staticType);
-      }
-      if (node.operator.type == TokenType.QUESTION_QUESTION_EQ) {
-        flow.ifNullExpression_end();
-      }
-    }
-  }
-
-  void _resolve_IndexExpression(
-    AssignmentExpressionImpl node,
-    IndexExpression left,
-  ) {
-    left.target?.accept(_resolver);
-    _resolver.startNullAwareIndexExpression(left);
-
-    var operator = node.operator.type;
-    var hasRead = operator != TokenType.EQ;
-
-    var resolver = PropertyElementResolver(_resolver);
-    var result = resolver.resolveIndexExpression(
-      node: left,
-      hasRead: hasRead,
-      hasWrite: true,
-    );
-
-    var readElement = result.readElement;
-    var writeElement = result.writeElement;
-
-    InferenceContext.setType(left.index, result.indexContextType);
-    left.index.accept(_resolver);
-
-    if (hasRead) {
-      _resolver.setReadElement(left, readElement);
-    }
-    _resolver.setWriteElement(left, writeElement);
-
-    _setBackwardCompatibility(node);
-
-    var right = node.rightHandSide;
-    _resolve3(node, left, operator, right);
-  }
-
-  void _resolve_PrefixedIdentifier(
-    AssignmentExpressionImpl node,
-    PrefixedIdentifier left,
-  ) {
-    left.prefix?.accept(_resolver);
-
-    var operator = node.operator.type;
-    var hasRead = operator != TokenType.EQ;
-
-    var resolver = PropertyElementResolver(_resolver);
-    var result = resolver.resolvePrefixedIdentifier(
-      node: left,
-      hasRead: hasRead,
-      hasWrite: true,
-    );
-
-    var readElement = result.readElement;
-    var writeElement = result.writeElement;
-
-    if (hasRead) {
-      _resolver.setReadElement(left, readElement);
-    }
-    _resolver.setWriteElement(left, writeElement);
-
-    _setBackwardCompatibility(node);
-
-    var right = node.rightHandSide;
-    _resolve3(node, left, operator, right);
-  }
-
-  void _resolve_PropertyAccess(
-    AssignmentExpressionImpl node,
-    PropertyAccess left,
-  ) {
-    left.target?.accept(_resolver);
-
-    var operator = node.operator.type;
-    var hasRead = operator != TokenType.EQ;
-
-    _resolver.startNullAwarePropertyAccess(left);
-
-    var resolver = PropertyElementResolver(_resolver);
-    var result = resolver.resolvePropertyAccess(
-      node: left,
-      hasRead: hasRead,
-      hasWrite: true,
-    );
-
-    var readElement = result.readElement;
-    var writeElement = result.writeElement;
-
-    if (hasRead) {
-      _resolver.setReadElement(left, readElement);
-    }
-    _resolver.setWriteElement(left, writeElement);
-
-    _setBackwardCompatibility(node);
-
-    var right = node.rightHandSide;
-    _resolve3(node, left, operator, right);
-  }
-
-  void _resolve_SimpleIdentifier(
-    AssignmentExpressionImpl node,
-    SimpleIdentifier left,
-  ) {
-    var right = node.rightHandSide;
-    var operator = node.operator.type;
-
-    if (operator != TokenType.EQ) {
-      var readLookup = _resolver.lexicalLookup(node: left, setter: false);
-      var readElement = readLookup.requested;
-      _resolver.setReadElement(left, readElement);
-    }
-
-    var writeLookup = _resolver.lexicalLookup(node: left, setter: true);
-    var writeElement = writeLookup.requested ?? writeLookup.recovery;
-    _resolver.setWriteElement(left, writeElement);
-
-    AssignmentVerifier(_resolver.definingLibrary, _errorReporter).verify(
-      node: left,
-      requested: writeLookup.requested,
-      recovery: writeLookup.recovery,
-      receiverTypeObject: null,
-    );
-
-    _setBackwardCompatibility(node);
-
-    if (operator != TokenType.EQ) {
-      // TODO(scheglov) Change this method to work with elements.
-      _resolver.checkReadOfNotAssignedLocalVariable(left);
-    }
-
-    _resolve3(node, left, operator, right);
-  }
-
   void _resolveTypes(AssignmentExpressionImpl node) {
     DartType assignedType;
     DartType nodeType;
@@ -426,56 +251,6 @@
     );
   }
 
-  /// TODO(scheglov) This is mostly necessary for backward compatibility.
-  /// Although we also use `staticElement` for `getType(left)` below.
-  void _setBackwardCompatibility(AssignmentExpressionImpl node) {
-    var operator = node.operator.type;
-
-    var left = node.leftHandSide;
-    var hasRead = operator != TokenType.EQ;
-
-    if (left is IndexExpression) {
-      if (hasRead) {
-        left.staticElement = node.writeElement;
-        left.auxiliaryElements = AuxiliaryElements(node.readElement);
-        _resolver.setReadElement(node, node.readElement);
-        _resolver.setWriteElement(node, node.writeElement);
-      } else {
-        left.staticElement = node.writeElement;
-        _resolver.setWriteElement(node, node.writeElement);
-      }
-      _recordStaticType(left, node.writeType);
-      return;
-    }
-
-    SimpleIdentifier leftIdentifier;
-    if (left is PrefixedIdentifier) {
-      leftIdentifier = left.identifier;
-      _recordStaticType(left, node.writeType);
-    } else if (left is PropertyAccess) {
-      leftIdentifier = left.propertyName;
-      _recordStaticType(left, node.writeType);
-    } else if (left is SimpleIdentifier) {
-      leftIdentifier = left;
-    }
-
-    if (hasRead) {
-      var readElement = node.readElement;
-      if (readElement is PropertyAccessorElement) {
-        leftIdentifier.auxiliaryElements = AuxiliaryElements(readElement);
-      }
-    }
-
-    leftIdentifier.staticElement = node.writeElement;
-    if (node.readElement is VariableElement) {
-      var leftType =
-          _resolver.localVariableTypeProvider.getType(leftIdentifier);
-      _recordStaticType(leftIdentifier, leftType);
-    } else {
-      _recordStaticType(leftIdentifier, node.writeType);
-    }
-  }
-
   void _setRhsContext(AssignmentExpressionImpl node, DartType leftType,
       TokenType operator, Expression right) {
     switch (operator) {
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 be06c78..4455cf3 100644
--- a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
@@ -341,13 +341,6 @@
   }
 
   @override
-  bool isLocalVariableWithoutDeclaredType(PromotableElement variable) {
-    return variable is LocalVariableElement &&
-        variable.hasImplicitType &&
-        !variable.hasInitializer;
-  }
-
-  @override
   bool isNever(DartType type) {
     return typeSystem.isBottom(type);
   }
diff --git a/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart b/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart
index 2329df1..c22c1e4 100644
--- a/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/invocation_inference_helper.dart
@@ -196,6 +196,31 @@
     return false;
   }
 
+  /// Given an uninstantiated generic function type, referenced by the
+  /// [identifier] in the tear-off [expression], try to infer the instantiated
+  /// generic function type from the surrounding context.
+  DartType inferTearOff(
+    Expression expression,
+    SimpleIdentifier identifier,
+    DartType tearOffType,
+  ) {
+    var context = InferenceContext.getContext(expression);
+    if (context is FunctionType && tearOffType is FunctionType) {
+      var typeArguments = _typeSystem.inferFunctionTypeInstantiation(
+        context,
+        tearOffType,
+        errorReporter: _resolver.errorReporter,
+        errorNode: expression,
+      );
+      (identifier as SimpleIdentifierImpl).tearOffTypeArgumentTypes =
+          typeArguments;
+      if (typeArguments.isNotEmpty) {
+        return tearOffType.instantiate(typeArguments);
+      }
+    }
+    return tearOffType;
+  }
+
   /// Record that the static type of the given node is the given type.
   ///
   /// @param expression the node whose type is to be recorded
diff --git a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
index e8c0531..951bde7 100644
--- a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
@@ -475,8 +475,6 @@
 
   void _resolveReceiverNull(
       MethodInvocation node, SimpleIdentifier nameNode, String name) {
-    _resolver.checkReadOfNotAssignedLocalVariable(nameNode);
-
     var element = nameScope.lookup2(name).getter;
     if (element != null) {
       element = _resolver.toLegacyElement(element);
@@ -492,6 +490,7 @@
         return _setResolution(node, element.type);
       }
       if (element is VariableElement) {
+        _resolver.checkReadOfNotAssignedLocalVariable(nameNode, element);
         var targetType = _localVariableTypeProvider.getType(nameNode);
         return _rewriteAsFunctionExpressionInvocation(node, targetType);
       }
diff --git a/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart
index bcebac1..75d46e2 100644
--- a/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/postfix_expression_resolver.dart
@@ -52,26 +52,26 @@
       return;
     }
 
-    node.operand.accept(_resolver);
+    var operandResolution = _resolver.resolveForWrite(
+      node: node.operand,
+      hasRead: true,
+    );
+
+    var readElement = operandResolution.readElement;
+    var writeElement = operandResolution.writeElement;
 
     var operand = node.operand;
-    if (operand is SimpleIdentifier) {
-      var element = operand.staticElement;
-      // ElementResolver does not set it.
-      if (element is VariableElement) {
-        _resolver.setReadElement(operand, element);
-        _resolver.setWriteElement(operand, element);
-      }
-    }
+    _resolver.setReadElement(operand, readElement);
+    _resolver.setWriteElement(operand, writeElement);
 
-    if (node.readElement == null || node.readType == null) {
-      _resolver.setReadElement(operand, null);
-    }
-    if (node.writeElement == null || node.writeType == null) {
-      _resolver.setWriteElement(operand, null);
-    }
+    _resolver.setAssignmentBackwardCompatibility(
+      assignment: node,
+      left: operand,
+      hasRead: true,
+    );
 
-    _assignmentShared.checkFinalAlreadyAssigned(node.operand);
+    // TODO(scheglov) Use VariableElement and do in resolveForWrite() ?
+    _assignmentShared.checkFinalAlreadyAssigned(operand);
 
     var receiverType = node.readType;
     _resolve1(node, receiverType);
diff --git a/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart
index 76cde43..62142f1 100644
--- a/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/prefix_expression_resolver.dart
@@ -49,32 +49,34 @@
 
   void resolve(PrefixExpressionImpl node) {
     var operator = node.operator.type;
+
     if (operator == TokenType.BANG) {
       _resolveNegation(node);
       return;
     }
 
-    node.operand.accept(_resolver);
-
-    var operand = node.operand;
-    if (operand is SimpleIdentifier) {
-      var element = operand.staticElement;
-      // ElementResolver does not set it.
-      if (element is VariableElement) {
-        _resolver.setReadElement(operand, element);
-        _resolver.setWriteElement(operand, element);
-      }
-    }
-
-    if (node.readElement == null || node.readType == null) {
-      _resolver.setReadElement(operand, null);
-    }
-    if (node.writeElement == null || node.writeType == null) {
-      _resolver.setWriteElement(operand, null);
-    }
-
     if (operator.isIncrementOperator) {
+      var operandResolution = _resolver.resolveForWrite(
+        node: node.operand,
+        hasRead: true,
+      );
+
+      var readElement = operandResolution.readElement;
+      var writeElement = operandResolution.writeElement;
+
+      var operand = node.operand;
+      _resolver.setReadElement(operand, readElement);
+      _resolver.setWriteElement(operand, writeElement);
+
+      _resolver.setAssignmentBackwardCompatibility(
+        assignment: node,
+        left: operand,
+        hasRead: true,
+      );
+
       _assignmentShared.checkFinalAlreadyAssigned(node.operand);
+    } else {
+      node.operand.accept(_resolver);
     }
 
     _resolve1(node);
diff --git a/pkg/analyzer/lib/src/dart/resolver/prefixed_identifier_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/prefixed_identifier_resolver.dart
new file mode 100644
index 0000000..54a67e4
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/resolver/prefixed_identifier_resolver.dart
@@ -0,0 +1,194 @@
+// 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.
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/type_provider.dart';
+import 'package:analyzer/src/dart/resolver/invocation_inference_helper.dart';
+import 'package:analyzer/src/dart/resolver/property_element_resolver.dart';
+import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/resolver.dart';
+
+class PrefixedIdentifierResolver {
+  final ResolverVisitor _resolver;
+
+  PrefixedIdentifierResolver(this._resolver);
+
+  InvocationInferenceHelper get _inferenceHelper => _resolver.inferenceHelper;
+
+  TypeProviderImpl get _typeProvider => _resolver.typeProvider;
+
+  void resolve(PrefixedIdentifier node) {
+    node.prefix.accept(_resolver);
+
+    var resolver = PropertyElementResolver(_resolver);
+    var result = resolver.resolvePrefixedIdentifier(
+      node: node,
+      hasRead: true,
+      hasWrite: false,
+    );
+
+    var identifier = node.identifier;
+    identifier.staticElement = result.readElement;
+
+    _resolve2(node);
+  }
+
+  /// Return the type that should be recorded for a node that resolved to the given accessor.
+  ///
+  /// @param accessor the accessor that the node resolved to
+  /// @return the type that should be recorded for a node that resolved to the given accessor
+  ///
+  /// TODO(scheglov) this is duplicate
+  DartType _getTypeOfProperty(PropertyAccessorElement accessor) {
+    FunctionType functionType = accessor.type;
+    if (functionType == null) {
+      // TODO(brianwilkerson) Report this internal error. This happens when we
+      // are analyzing a reference to a property before we have analyzed the
+      // declaration of the property or when the property does not have a
+      // defined type.
+      return DynamicTypeImpl.instance;
+    }
+    if (accessor.isSetter) {
+      List<DartType> parameterTypes = functionType.normalParameterTypes;
+      if (parameterTypes != null && parameterTypes.isNotEmpty) {
+        return parameterTypes[0];
+      }
+      PropertyAccessorElement getter = accessor.variable.getter;
+      if (getter != null) {
+        functionType = getter.type;
+        if (functionType != null) {
+          return functionType.returnType;
+        }
+      }
+      return DynamicTypeImpl.instance;
+    }
+    return functionType.returnType;
+  }
+
+  /// Return `true` if the given [node] is not a type literal.
+  ///
+  /// TODO(scheglov) this is duplicate
+  bool _isExpressionIdentifier(Identifier node) {
+    var parent = node.parent;
+    if (node is SimpleIdentifier && node.inDeclarationContext()) {
+      return false;
+    }
+    if (parent is ConstructorDeclaration) {
+      if (parent.name == node || parent.returnType == node) {
+        return false;
+      }
+    }
+    if (parent is ConstructorName ||
+        parent is MethodInvocation ||
+        parent is PrefixedIdentifier && parent.prefix == node ||
+        parent is PropertyAccess ||
+        parent is TypeName) {
+      return false;
+    }
+    return true;
+  }
+
+  /// Record that the static type of the given node is the given type.
+  ///
+  /// @param expression the node whose type is to be recorded
+  /// @param type the static type of the node
+  ///
+  /// TODO(scheglov) this is duplicate
+  void _recordStaticType(Expression expression, DartType type) {
+    _inferenceHelper.recordStaticType(expression, type);
+  }
+
+  void _resolve2(PrefixedIdentifier node) {
+    SimpleIdentifier prefixedIdentifier = node.identifier;
+    Element staticElement = prefixedIdentifier.staticElement;
+
+    if (staticElement is ExtensionElement) {
+      _setExtensionIdentifierType(node);
+      return;
+    }
+
+    if (identical(node.prefix.staticType, NeverTypeImpl.instance)) {
+      _recordStaticType(prefixedIdentifier, NeverTypeImpl.instance);
+      _recordStaticType(node, NeverTypeImpl.instance);
+      return;
+    }
+
+    DartType staticType = DynamicTypeImpl.instance;
+    if (staticElement is ClassElement) {
+      if (_isExpressionIdentifier(node)) {
+        var type = _typeProvider.typeType;
+        node.staticType = type;
+        node.identifier.staticType = type;
+      }
+      return;
+    } else if (staticElement is DynamicElementImpl) {
+      var type = _typeProvider.typeType;
+      node.staticType = type;
+      node.identifier.staticType = type;
+      return;
+    } else if (staticElement is FunctionTypeAliasElement) {
+      if (node.parent is TypeName) {
+        // no type
+      } else {
+        var type = _typeProvider.typeType;
+        node.staticType = type;
+        node.identifier.staticType = type;
+      }
+      return;
+    } else if (staticElement is MethodElement) {
+      staticType = staticElement.type;
+    } else if (staticElement is PropertyAccessorElement) {
+      staticType = _getTypeOfProperty(staticElement);
+    } else if (staticElement is ExecutableElement) {
+      staticType = staticElement.type;
+    } else if (staticElement is VariableElement) {
+      staticType = staticElement.type;
+    }
+
+    staticType =
+        _inferenceHelper.inferTearOff(node, node.identifier, staticType);
+
+    _recordStaticType(prefixedIdentifier, staticType);
+    _recordStaticType(node, staticType);
+  }
+
+  /// TODO(scheglov) this is duplicate
+  void _setExtensionIdentifierType(Identifier node) {
+    if (node is SimpleIdentifier && node.inDeclarationContext()) {
+      return;
+    }
+
+    var parent = node.parent;
+
+    if (parent is PrefixedIdentifier && parent.identifier == node) {
+      node = parent;
+      parent = node.parent;
+    }
+
+    if (parent is CommentReference ||
+        parent is ExtensionOverride && parent.extensionName == node ||
+        parent is MethodInvocation && parent.target == node ||
+        parent is PrefixedIdentifier && parent.prefix == node ||
+        parent is PropertyAccess && parent.target == node) {
+      return;
+    }
+
+    _resolver.errorReporter.reportErrorForNode(
+      CompileTimeErrorCode.EXTENSION_AS_EXPRESSION,
+      node,
+      [node.name],
+    );
+
+    if (node is PrefixedIdentifier) {
+      node.identifier.staticType = DynamicTypeImpl.instance;
+      node.staticType = DynamicTypeImpl.instance;
+    } else if (node is SimpleIdentifier) {
+      node.staticType = DynamicTypeImpl.instance;
+    }
+  }
+}
diff --git a/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
index b3ed076..08ce229 100644
--- a/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
@@ -13,6 +13,7 @@
 import 'package:analyzer/src/dart/element/type_system.dart';
 import 'package:analyzer/src/dart/resolver/extension_member_resolver.dart';
 import 'package:analyzer/src/dart/resolver/resolution_result.dart';
+import 'package:analyzer/src/dart/resolver/scope.dart';
 import 'package:analyzer/src/error/assignment_verifier.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/generated/resolver.dart';
@@ -125,30 +126,19 @@
     @required PrefixedIdentifier node,
     @required bool hasRead,
     @required bool hasWrite,
+    bool forAnnotation = false,
   }) {
     var prefix = node.prefix;
     var identifier = node.identifier;
 
     var prefixElement = prefix.staticElement;
     if (prefixElement is PrefixElement) {
-      var lookupResult = prefixElement.scope.lookup2(identifier.name);
-
-      var readElement = _resolver.toLegacyElement(lookupResult.getter);
-      var writeElement = _resolver.toLegacyElement(lookupResult.setter);
-
-      if (hasRead && readElement == null || hasWrite && writeElement == null) {
-        _errorReporter.reportErrorForNode(
-          CompileTimeErrorCode.UNDEFINED_PREFIXED_NAME,
-          identifier,
-          [identifier.name, prefixElement.name],
-        );
-      }
-
-      return PropertyElementResolverResult(
-        readElementRequested: readElement,
-        readElementRecovery: null,
-        writeElementRequested: writeElement,
-        writeElementRecovery: null,
+      return _resolveTargetPrefixElement(
+        target: prefixElement,
+        identifier: identifier,
+        hasRead: hasRead,
+        hasWrite: hasWrite,
+        forAnnotation: forAnnotation,
       );
     }
 
@@ -198,6 +188,42 @@
     );
   }
 
+  PropertyElementResolverResult resolveSimpleIdentifier({
+    @required SimpleIdentifier node,
+    @required bool hasRead,
+    @required bool hasWrite,
+  }) {
+    Element readElementRequested;
+    Element readElementRecovery;
+    if (hasRead) {
+      var readLookup = _resolver.lexicalLookup(node: node, setter: false);
+      readElementRequested = readLookup.requested;
+      _resolver.checkReadOfNotAssignedLocalVariable(node, readElementRequested);
+    }
+
+    Element writeElementRequested;
+    Element writeElementRecovery;
+    if (hasWrite) {
+      var writeLookup = _resolver.lexicalLookup(node: node, setter: true);
+      writeElementRequested = writeLookup.requested;
+      writeElementRecovery = writeLookup.recovery;
+
+      AssignmentVerifier(_resolver.definingLibrary, _errorReporter).verify(
+        node: node,
+        requested: writeElementRequested,
+        recovery: writeElementRecovery,
+        receiverTypeObject: null,
+      );
+    }
+
+    return PropertyElementResolverResult(
+      readElementRequested: readElementRequested,
+      readElementRecovery: readElementRecovery,
+      writeElementRequested: writeElementRequested,
+      writeElementRecovery: writeElementRecovery,
+    );
+  }
+
   void _checkExtensionOverrideStaticMember(
     SimpleIdentifier propertyName,
     ExecutableElement element,
@@ -515,6 +541,40 @@
     );
   }
 
+  PropertyElementResolverResult _resolveTargetPrefixElement({
+    @required PrefixElement target,
+    @required SimpleIdentifier identifier,
+    @required bool hasRead,
+    @required bool hasWrite,
+    @required bool forAnnotation,
+  }) {
+    var lookupResult = target.scope.lookup2(identifier.name);
+
+    var readElement = _resolver.toLegacyElement(lookupResult.getter);
+    var writeElement = _resolver.toLegacyElement(lookupResult.setter);
+
+    if (hasRead && readElement == null || hasWrite && writeElement == null) {
+      if (!forAnnotation &&
+          !_resolver.nameScope.shouldIgnoreUndefined2(
+            prefix: target.name,
+            name: identifier.name,
+          )) {
+        _errorReporter.reportErrorForNode(
+          CompileTimeErrorCode.UNDEFINED_PREFIXED_NAME,
+          identifier,
+          [identifier.name, target.name],
+        );
+      }
+    }
+
+    return PropertyElementResolverResult(
+      readElementRequested: readElement,
+      readElementRecovery: null,
+      writeElementRequested: writeElement,
+      writeElementRecovery: null,
+    );
+  }
+
   PropertyElementResolverResult _resolveTargetSuperExpression({
     @required SuperExpression target,
     @required SimpleIdentifier propertyName,
diff --git a/pkg/analyzer/lib/src/error/best_practices_verifier.dart b/pkg/analyzer/lib/src/error/best_practices_verifier.dart
index 5d65e55..05b73cc 100644
--- a/pkg/analyzer/lib/src/error/best_practices_verifier.dart
+++ b/pkg/analyzer/lib/src/error/best_practices_verifier.dart
@@ -97,8 +97,8 @@
         _strictInference =
             (analysisOptions as AnalysisOptionsImpl).strictInference,
         _inheritanceManager = inheritanceManager,
-        _invalidAccessVerifier =
-            _InvalidAccessVerifier(_errorReporter, _currentLibrary),
+        _invalidAccessVerifier = _InvalidAccessVerifier(
+            _errorReporter, _currentLibrary, workspacePackage),
         _workspacePackage = workspacePackage {
     _inDeprecatedMember = _currentLibrary.hasDeprecated;
 
@@ -524,6 +524,7 @@
     if (importElement != null && importElement.isDeferred) {
       _checkForLoadLibraryFunction(node, importElement);
     }
+    _invalidAccessVerifier.verifyImport(node);
     super.visitImportDirective(node);
   }
 
@@ -674,6 +675,7 @@
   @override
   void visitSuperConstructorInvocation(SuperConstructorInvocation node) {
     _checkForDeprecatedMemberUse(node.staticElement, node);
+    _invalidAccessVerifier.verifySuperConstructorInvocation(node);
     super.visitSuperConstructorInvocation(node);
   }
 
@@ -1745,13 +1747,15 @@
 
   final ErrorReporter _errorReporter;
   final LibraryElement _library;
+  final WorkspacePackage _workspacePackage;
 
   bool _inTemplateSource;
   bool _inTestDirectory;
 
   ClassElement _enclosingClass;
 
-  _InvalidAccessVerifier(this._errorReporter, this._library) {
+  _InvalidAccessVerifier(
+      this._errorReporter, this._library, this._workspacePackage) {
     var path = _library.source.fullName;
     _inTemplateSource = path.contains(_templateExtension);
     _inTestDirectory = path.contains(_testDir) ||
@@ -1759,20 +1763,19 @@
         path.contains(_testingDir);
   }
 
-  /// Produces a hint if [identifier] is accessed from an invalid location. In
-  /// particular:
+  /// Produces a hint if [identifier] is accessed from an invalid location.
   ///
-  /// * if the given identifier is a protected closure, field or
-  ///   getter/setter, method closure or invocation accessed outside a subclass,
-  ///   or accessed outside the library wherein the identifier is declared, or
-  /// * if the given identifier is a closure, field, getter, setter, method
-  ///   closure or invocation which is annotated with `visibleForTemplate`, and
-  ///   is accessed outside of the defining library, and the current library
-  ///   does not have the suffix '.template' in its source path, or
-  /// * if the given identifier is a closure, field, getter, setter, method
-  ///   closure or invocation which is annotated with `visibleForTesting`, and
-  ///   is accessed outside of the defining library, and the current library
-  ///   does not have a directory named 'test' or 'testing' in its path.
+  /// In particular, a hint is produced in either of the two following cases:
+  ///
+  /// * The element associated with [identifier] is annotated with [internal],
+  ///   and is accessed from outside the package in which the element is
+  ///   declared.
+  /// * The element associated with [identifier] is annotated with [protected],
+  ///   [visibleForTesting], and/or [visibleForTemplate], and is accessed from a
+  ///   location which is invalid as per the rules of each such annotation.
+  ///   Conversely, if the element is annotated with more than one of these
+  ///   annotations, the access is valid (and no hint will be produced) if it
+  ///   conforms to the rules of at least one of the annotations.
   void verify(SimpleIdentifier identifier) {
     if (identifier.inDeclarationContext() || _inCommentReference(identifier)) {
       return;
@@ -1786,24 +1789,64 @@
     }
     AstNode grandparent = parent?.parent;
 
-    Element element;
-    String name;
-    AstNode node;
-
-    if (grandparent is ConstructorName) {
-      element = grandparent.staticElement;
-      name = grandparent.toSource();
-      node = grandparent;
-    } else {
-      element = identifier.staticElement;
-      name = identifier.name;
-      node = identifier;
-    }
+    var element = grandparent is ConstructorName
+        ? grandparent.staticElement
+        : identifier.staticElement;
 
     if (element == null || _inCurrentLibrary(element)) {
       return;
     }
 
+    _checkForInvalidInternalAccess(identifier, element);
+    _checkForOtherInvalidAccess(identifier, element);
+  }
+
+  void verifyImport(ImportDirective node) {
+    var element = node.uriElement;
+    if (_hasInternal(element) &&
+        !_isLibraryInWorkspacePackage(element.library)) {
+      _errorReporter.reportErrorForNode(HintCode.INVALID_USE_OF_INTERNAL_MEMBER,
+          node, [node.uri.stringValue]);
+    }
+  }
+
+  void verifySuperConstructorInvocation(SuperConstructorInvocation node) {
+    if (node.constructorName != null) {
+      // Named constructor calls are handled by [verify].
+      return;
+    }
+    var element = node.staticElement;
+    if (_hasInternal(element) &&
+        !_isLibraryInWorkspacePackage(element.library)) {
+      _errorReporter.reportErrorForNode(
+          HintCode.INVALID_USE_OF_INTERNAL_MEMBER, node, [element.name]);
+    }
+  }
+
+  void _checkForInvalidInternalAccess(
+      SimpleIdentifier identifier, Element element) {
+    if (_hasInternal(element) &&
+        !_isLibraryInWorkspacePackage(element.library)) {
+      String name;
+      AstNode node;
+
+      var grandparent = identifier.parent?.parent;
+
+      if (grandparent is ConstructorName) {
+        name = grandparent.toSource();
+        node = grandparent;
+      } else {
+        name = identifier.name;
+        node = identifier;
+      }
+
+      _errorReporter.reportErrorForNode(
+          HintCode.INVALID_USE_OF_INTERNAL_MEMBER, node, [name]);
+    }
+  }
+
+  void _checkForOtherInvalidAccess(
+      SimpleIdentifier identifier, Element element) {
     bool hasProtected = _hasProtected(element);
     if (hasProtected) {
       ClassElement definingClass = element.enclosingElement;
@@ -1827,8 +1870,22 @@
     }
 
     // At this point, [identifier] was not cleared as protected access, nor
-    // cleared as access for templates or testing. Report the appropriate
-    // violation(s).
+    // cleared as access for templates or testing. Report a violation for each
+    // annotation present.
+
+    String name;
+    AstNode node;
+
+    var grandparent = identifier.parent?.parent;
+
+    if (grandparent is ConstructorName) {
+      name = grandparent.toSource();
+      node = grandparent;
+    } else {
+      name = identifier.name;
+      node = identifier;
+    }
+
     Element definingClass = element.enclosingElement;
     if (hasProtected) {
       _errorReporter.reportErrorForNode(
@@ -1851,6 +1908,19 @@
     }
   }
 
+  bool _hasInternal(Element element) {
+    if (element == null) {
+      return false;
+    }
+    if (element.hasInternal) {
+      return true;
+    }
+    if (element is PropertyAccessorElement && element.variable.hasInternal) {
+      return true;
+    }
+    return false;
+  }
+
   bool _hasProtected(Element element) {
     if (element is PropertyAccessorElement &&
         element.enclosingElement is ClassElement &&
@@ -1912,6 +1982,15 @@
   bool _inExportDirective(SimpleIdentifier identifier) =>
       identifier.parent is Combinator &&
       identifier.parent.parent is ExportDirective;
+
+  bool _isLibraryInWorkspacePackage(LibraryElement library) {
+    if (_workspacePackage == null || library == null) {
+      // Better to not make a big claim that they _are_ in the same package,
+      // if we were unable to determine what package [_currentLibrary] is in.
+      return false;
+    }
+    return _workspacePackage.contains(library.source);
+  }
 }
 
 /// A visitor that determines, upon visiting a function body and/or a
diff --git a/pkg/analyzer/lib/src/generated/element_resolver.dart b/pkg/analyzer/lib/src/generated/element_resolver.dart
index d80064f..20e0732 100644
--- a/pkg/analyzer/lib/src/generated/element_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/element_resolver.dart
@@ -11,7 +11,6 @@
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/type_provider.dart';
 import 'package:analyzer/src/dart/resolver/method_invocation_resolver.dart';
-import 'package:analyzer/src/dart/resolver/property_element_resolver.dart';
 import 'package:analyzer/src/dart/resolver/scope.dart';
 import 'package:analyzer/src/dart/resolver/type_property_resolver.dart';
 import 'package:analyzer/src/error/codes.dart';
@@ -82,9 +81,6 @@
   /// The element for the library containing the compilation unit being visited.
   final LibraryElement _definingLibrary;
 
-  /// The type representing the type 'dynamic'.
-  DartType _dynamicType;
-
   /// Whether constant evaluation errors should be reported during resolution.
   @Deprecated('This field is no longer used')
   final bool reportConstEvaluationErrors;
@@ -102,7 +98,6 @@
           const MigratableAstInfoProvider()})
       : _definingLibrary = _resolver.definingLibrary,
         _typePropertyResolver = _resolver.typePropertyResolver {
-    _dynamicType = _typeProvider.dynamicType;
     _methodInvocationResolver = MethodInvocationResolver(
       _resolver,
       migratableAstInfoProvider,
@@ -375,34 +370,6 @@
   }
 
   @override
-  void visitIndexExpression(IndexExpression node) {
-    var hasRead = node.inGetterContext();
-    var hasWrite = node.inSetterContext();
-
-    var resolver = PropertyElementResolver(_resolver);
-    var result = resolver.resolveIndexExpression(
-      node: node,
-      hasRead: hasRead,
-      hasWrite: hasWrite,
-    );
-
-    if (hasRead && hasWrite) {
-      node.staticElement = result.writeElement;
-      node.auxiliaryElements = AuxiliaryElements(result.readElement);
-      _resolver.setReadElement(node, result.readElement);
-      _resolver.setWriteElement(node, result.writeElement);
-    } else if (hasRead) {
-      node.staticElement = result.readElement;
-      _resolver.setReadElement(node, result.readElement);
-    } else if (hasWrite) {
-      node.staticElement = result.writeElement;
-      _resolver.setWriteElement(node, result.writeElement);
-    }
-
-    InferenceContext.setType(node.index, result.indexContextType);
-  }
-
-  @override
   void visitInstanceCreationExpression(InstanceCreationExpression node) {
     ConstructorElement invokedConstructor = node.constructorName.staticElement;
     ArgumentList argumentList = node.argumentList;
@@ -439,160 +406,6 @@
   }
 
   @override
-  void visitPrefixedIdentifier(PrefixedIdentifier node) {
-    SimpleIdentifier prefix = node.prefix;
-    SimpleIdentifier identifier = node.identifier;
-    //
-    // First, check the "lib.loadLibrary" case
-    //
-    if (identifier.name == FunctionElement.LOAD_LIBRARY_NAME &&
-        _isDeferredPrefix(prefix)) {
-      LibraryElement importedLibrary = _getImportedLibrary(prefix);
-      var element = importedLibrary?.loadLibraryFunction;
-      element = _resolver.toLegacyElement(element);
-      identifier.staticElement = element;
-      return;
-    }
-    //
-    // Check to see whether the prefix is really a prefix.
-    //
-    Element prefixElement = prefix.staticElement;
-    if (prefixElement is PrefixElement) {
-      var lookupResult = prefixElement.scope.lookup2(identifier.name);
-
-      if (identifier.inGetterContext()) {
-        _resolver.setReadElement(
-          node,
-          _resolver.toLegacyElement(lookupResult.getter),
-        );
-      }
-
-      if (identifier.inSetterContext()) {
-        _resolver.setWriteElement(
-          node,
-          _resolver.toLegacyElement(lookupResult.setter),
-        );
-      }
-
-      var element = lookupResult.getter;
-      if (element == null && identifier.inSetterContext()) {
-        element = lookupResult.setter;
-      }
-      element = _resolver.toLegacyElement(element);
-      if (element == null && _resolver.nameScope.shouldIgnoreUndefined(node)) {
-        return;
-      }
-      if (element == null) {
-        AstNode parent = node.parent;
-        if (parent is Annotation) {
-          _errorReporter.reportErrorForNode(
-              CompileTimeErrorCode.UNDEFINED_ANNOTATION,
-              parent,
-              [identifier.name]);
-        } else {
-          _errorReporter.reportErrorForNode(
-              CompileTimeErrorCode.UNDEFINED_PREFIXED_NAME,
-              identifier,
-              [identifier.name, prefixElement.name]);
-        }
-        return;
-      }
-      Element accessor = element;
-      if (accessor is PropertyAccessorElement && identifier.inSetterContext()) {
-        PropertyInducingElement variable = accessor.variable;
-        if (variable != null) {
-          PropertyAccessorElement setter = variable.setter;
-          if (setter != null) {
-            element = setter;
-          }
-        }
-      }
-      // TODO(brianwilkerson) The prefix needs to be resolved to the element for
-      // the import that defines the prefix, not the prefix's element.
-      identifier.staticElement = element;
-      // Validate annotation element.
-      AstNode parent = node.parent;
-      if (parent is Annotation) {
-        _resolveAnnotationElement(parent);
-      }
-      return;
-    }
-    // May be annotation, resolve invocation of "const" constructor.
-    AstNode parent = node.parent;
-    if (parent is Annotation) {
-      _resolveAnnotationElement(parent);
-      return;
-    }
-    //
-    // Otherwise, the prefix is really an expression that happens to be a simple
-    // identifier and this is really equivalent to a property access node.
-    //
-    {
-      var hasRead = identifier.inGetterContext();
-      var hasWrite = identifier.inSetterContext();
-
-      var resolver = PropertyElementResolver(_resolver);
-      var result = resolver.resolvePrefixedIdentifier(
-        node: node,
-        hasRead: hasRead,
-        hasWrite: hasWrite,
-      );
-
-      if (hasRead) {
-        _resolver.setReadElement(node, result.readElement);
-      }
-
-      if (hasWrite) {
-        _resolver.setWriteElement(node, result.writeElement);
-      }
-
-      if (hasWrite) {
-        identifier.staticElement = result.writeElement;
-        if (hasRead) {
-          identifier.auxiliaryElements = AuxiliaryElements(
-            result.readElement,
-          );
-        }
-      } else if (hasRead) {
-        identifier.staticElement = result.readElement;
-      }
-    }
-  }
-
-  @override
-  void visitPropertyAccess(PropertyAccess node) {
-    var propertyName = node.propertyName;
-    var hasRead = propertyName.inGetterContext();
-    var hasWrite = propertyName.inSetterContext();
-
-    var resolver = PropertyElementResolver(_resolver);
-    var result = resolver.resolvePropertyAccess(
-      node: node,
-      hasRead: hasRead,
-      hasWrite: hasWrite,
-    );
-
-    if (hasRead) {
-      _resolver.setReadElement(node, result.readElement);
-    }
-
-    if (hasWrite) {
-      _resolver.setWriteElement(node, result.writeElement);
-    }
-
-    if (hasWrite) {
-      propertyName.staticElement = result.writeElement;
-      if (hasRead) {
-        propertyName.auxiliaryElements = AuxiliaryElements(
-          result.readElement,
-        );
-      }
-    } else if (hasRead) {
-      propertyName.staticElement = result.readElement;
-    }
-  }
-
-  @override
   void visitRedirectingConstructorInvocation(
       RedirectingConstructorInvocation node) {
     ClassElement enclosingClass = _resolver.enclosingClass;
@@ -727,13 +540,6 @@
     if (inGetterContext) {
       _resolver.setReadElement(node, getter);
     }
-
-    //
-    // Validate annotation element.
-    //
-    if (parent is Annotation) {
-      _resolveAnnotationElement(parent);
-    }
   }
 
   @override
@@ -799,7 +605,7 @@
   @override
   void visitSuperExpression(SuperExpression node) {
     var context = SuperContext.of(node);
-    if (context == SuperContext.static) {
+    if (context == SuperContext.annotation || context == SuperContext.static) {
       _errorReporter.reportErrorForNode(
           CompileTimeErrorCode.SUPER_IN_INVALID_CONTEXT, node);
     } else if (context == SuperContext.extension) {
@@ -824,41 +630,6 @@
     _resolveAnnotations(node.metadata);
   }
 
-  /// Assuming that the given [identifier] is a prefix for a deferred import,
-  /// return the library that is being imported.
-  LibraryElement _getImportedLibrary(SimpleIdentifier identifier) {
-    PrefixElement prefixElement = identifier.staticElement as PrefixElement;
-    List<ImportElement> imports =
-        prefixElement.enclosingElement.getImportsWithPrefix(prefixElement);
-    return imports[0].importedLibrary;
-  }
-
-  InterfaceType _instantiateAnnotationClass(ClassElement element) {
-    return element.instantiate(
-      typeArguments: List.filled(
-        element.typeParameters.length,
-        _dynamicType,
-      ),
-      nullabilitySuffix: _resolver.noneOrStarSuffix,
-    );
-  }
-
-  /// Return `true` if the given [expression] is a prefix for a deferred import.
-  bool _isDeferredPrefix(Expression expression) {
-    if (expression is SimpleIdentifier) {
-      Element element = expression.staticElement;
-      if (element is PrefixElement) {
-        List<ImportElement> imports =
-            element.enclosingElement.getImportsWithPrefix(element);
-        if (imports.length != 1) {
-          return false;
-        }
-        return imports[0].isDeferred;
-      }
-    }
-    return false;
-  }
-
   /// Return `true` if the given [node] can validly be resolved to a prefix:
   /// * it is the prefix in an import directive, or
   /// * it is the prefix in a prefixed identifier.
@@ -915,159 +686,6 @@
     }
   }
 
-  void _resolveAnnotationConstructorInvocationArguments(
-      Annotation annotation, ConstructorElement constructor) {
-    ArgumentList argumentList = annotation.arguments;
-    // error will be reported in ConstantVerifier
-    if (argumentList == null) {
-      return;
-    }
-    // resolve arguments to parameters
-    List<ParameterElement> parameters =
-        _resolveArgumentsToFunction(argumentList, constructor);
-    if (parameters != null) {
-      argumentList.correspondingStaticParameters = parameters;
-    }
-  }
-
-  /// Continues resolution of the given [annotation].
-  void _resolveAnnotationElement(Annotation annotation) {
-    SimpleIdentifier nameNode1;
-    SimpleIdentifier nameNode2;
-    {
-      Identifier annName = annotation.name;
-      if (annName is PrefixedIdentifier) {
-        nameNode1 = annName.prefix;
-        nameNode2 = annName.identifier;
-      } else {
-        nameNode1 = annName as SimpleIdentifier;
-        nameNode2 = null;
-      }
-    }
-    SimpleIdentifier nameNode3 = annotation.constructorName;
-    ConstructorElement constructor;
-    bool undefined = false;
-    //
-    // CONST or Class(args)
-    //
-    if (nameNode1 != null && nameNode2 == null && nameNode3 == null) {
-      Element element1 = nameNode1.staticElement;
-      // CONST
-      if (element1 is PropertyAccessorElement) {
-        _resolveAnnotationElementGetter(annotation, element1);
-        return;
-      }
-      // Class(args)
-      if (element1 is ClassElement) {
-        constructor = _instantiateAnnotationClass(element1)
-            .lookUpConstructor(null, _definingLibrary);
-        constructor = _resolver.toLegacyElement(constructor);
-      } else if (element1 == null) {
-        undefined = true;
-      }
-    }
-    //
-    // prefix.CONST or prefix.Class() or Class.CONST or Class.constructor(args)
-    //
-    if (nameNode1 != null && nameNode2 != null && nameNode3 == null) {
-      Element element1 = nameNode1.staticElement;
-      Element element2 = nameNode2.staticElement;
-      // Class.CONST - not resolved yet
-      if (element1 is ClassElement) {
-        element2 = element1.lookUpGetter(nameNode2.name, _definingLibrary);
-        element2 = _resolver.toLegacyElement(element2);
-      }
-      // prefix.CONST or Class.CONST
-      if (element2 is PropertyAccessorElement) {
-        nameNode2.staticElement = element2;
-        annotation.element = element2;
-        _resolveAnnotationElementGetter(annotation, element2);
-        return;
-      }
-      // prefix.Class()
-      if (element2 is ClassElement) {
-        constructor = element2.unnamedConstructor;
-        constructor = _resolver.toLegacyElement(constructor);
-      }
-      // Class.constructor(args)
-      if (element1 is ClassElement) {
-        constructor = _instantiateAnnotationClass(element1)
-            .lookUpConstructor(nameNode2.name, _definingLibrary);
-        constructor = _resolver.toLegacyElement(constructor);
-        nameNode2.staticElement = constructor;
-      }
-      if (element1 == null && element2 == null) {
-        undefined = true;
-      }
-    }
-    //
-    // prefix.Class.CONST or prefix.Class.constructor(args)
-    //
-    if (nameNode1 != null && nameNode2 != null && nameNode3 != null) {
-      Element element2 = nameNode2.staticElement;
-      // element2 should be ClassElement
-      if (element2 is ClassElement) {
-        String name3 = nameNode3.name;
-        // prefix.Class.CONST
-        PropertyAccessorElement getter =
-            element2.lookUpGetter(name3, _definingLibrary);
-        if (getter != null) {
-          getter = _resolver.toLegacyElement(getter);
-          nameNode3.staticElement = getter;
-          annotation.element = getter;
-          _resolveAnnotationElementGetter(annotation, getter);
-          return;
-        }
-        // prefix.Class.constructor(args)
-        constructor = _instantiateAnnotationClass(element2)
-            .lookUpConstructor(name3, _definingLibrary);
-        constructor = _resolver.toLegacyElement(constructor);
-        nameNode3.staticElement = constructor;
-      } else if (element2 == null) {
-        undefined = true;
-      }
-    }
-    // we need constructor
-    if (constructor == null) {
-      if (!undefined) {
-        // If the class was not found then we've already reported the error.
-        _errorReporter.reportErrorForNode(
-            CompileTimeErrorCode.INVALID_ANNOTATION, annotation);
-      }
-      return;
-    }
-    // record element
-    annotation.element = constructor;
-    // resolve arguments
-    _resolveAnnotationConstructorInvocationArguments(annotation, constructor);
-  }
-
-  void _resolveAnnotationElementGetter(
-      Annotation annotation, PropertyAccessorElement accessorElement) {
-    // accessor should be synthetic
-    if (!accessorElement.isSynthetic) {
-      _errorReporter.reportErrorForNode(
-          CompileTimeErrorCode.INVALID_ANNOTATION_GETTER, annotation);
-      return;
-    }
-    // variable should be constant
-    VariableElement variableElement = accessorElement.variable;
-    if (!variableElement.isConst) {
-      _errorReporter.reportErrorForNode(
-          CompileTimeErrorCode.INVALID_ANNOTATION, annotation);
-      return;
-    }
-    // no arguments
-    if (annotation.arguments != null) {
-      _errorReporter.reportErrorForNode(
-          CompileTimeErrorCode.ANNOTATION_WITH_NON_CLASS,
-          annotation.name,
-          [annotation.name]);
-    }
-    // OK
-    return;
-  }
-
   /// Given an [argumentList] and the [executableElement] that will be invoked
   /// using those argument, compute the list of parameters that correspond to
   /// the list of arguments. An error will be reported if any of the arguments
diff --git a/pkg/analyzer/lib/src/generated/parser.dart b/pkg/analyzer/lib/src/generated/parser.dart
index 208d851..89c2ca2 100644
--- a/pkg/analyzer/lib/src/generated/parser.dart
+++ b/pkg/analyzer/lib/src/generated/parser.dart
@@ -145,8 +145,7 @@
 
   /// A flag indicating whether the analyzer [Parser] factory method
   /// will return a fasta based parser or an analyzer based parser.
-  static const bool useFasta =
-      bool.fromEnvironment("useFastaParser", defaultValue: true);
+  static const bool useFasta = true;
 
   /// The source being parsed.
   final Source _source;
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 07ea52c..3650e5b 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -24,6 +24,7 @@
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/type_provider.dart';
 import 'package:analyzer/src/dart/element/type_system.dart';
+import 'package:analyzer/src/dart/resolver/annotation_resolver.dart';
 import 'package:analyzer/src/dart/resolver/assignment_expression_resolver.dart';
 import 'package:analyzer/src/dart/resolver/binary_expression_resolver.dart';
 import 'package:analyzer/src/dart/resolver/body_inference_context.dart';
@@ -37,6 +38,8 @@
 import 'package:analyzer/src/dart/resolver/method_invocation_resolver.dart';
 import 'package:analyzer/src/dart/resolver/postfix_expression_resolver.dart';
 import 'package:analyzer/src/dart/resolver/prefix_expression_resolver.dart';
+import 'package:analyzer/src/dart/resolver/prefixed_identifier_resolver.dart';
+import 'package:analyzer/src/dart/resolver/property_element_resolver.dart';
 import 'package:analyzer/src/dart/resolver/scope.dart';
 import 'package:analyzer/src/dart/resolver/type_property_resolver.dart';
 import 'package:analyzer/src/dart/resolver/typed_literal_resolver.dart';
@@ -175,6 +178,7 @@
   FunctionExpressionResolver _functionExpressionResolver;
   ForResolver _forResolver;
   PostfixExpressionResolver _postfixExpressionResolver;
+  PrefixedIdentifierResolver _prefixedIdentifierResolver;
   PrefixExpressionResolver _prefixExpressionResolver;
   VariableDeclarationResolver _variableDeclarationResolver;
   YieldStatementResolver _yieldStatementResolver;
@@ -350,6 +354,7 @@
       resolver: this,
       flowAnalysis: _flowAnalysis,
     );
+    _prefixedIdentifierResolver = PrefixedIdentifierResolver(this);
     _prefixExpressionResolver = PrefixExpressionResolver(
       resolver: this,
       flowAnalysis: _flowAnalysis,
@@ -444,7 +449,10 @@
     }
   }
 
-  void checkReadOfNotAssignedLocalVariable(SimpleIdentifier node) {
+  void checkReadOfNotAssignedLocalVariable(
+    SimpleIdentifier node,
+    Element element,
+  ) {
     if (_flowAnalysis?.flow == null) {
       return;
     }
@@ -453,7 +461,6 @@
       return;
     }
 
-    var element = node.staticElement;
     if (element is VariableElement) {
       var assigned = _flowAnalysis.isDefinitelyAssigned(node, element);
       var unassigned = _flowAnalysis.isDefinitelyUnassigned(node, element);
@@ -580,6 +587,59 @@
     _thisType = enclosingClass?.thisType;
   }
 
+  /// Resolve LHS [node] of an assignment, an explicit [AssignmentExpression],
+  /// or implicit [PrefixExpression] or [PostfixExpression].
+  PropertyElementResolverResult resolveForWrite({
+    @required AstNode node,
+    @required bool hasRead,
+  }) {
+    if (node is IndexExpression) {
+      node.target?.accept(this);
+      startNullAwareIndexExpression(node);
+
+      var resolver = PropertyElementResolver(this);
+      var result = resolver.resolveIndexExpression(
+        node: node,
+        hasRead: hasRead,
+        hasWrite: true,
+      );
+
+      InferenceContext.setType(node.index, result.indexContextType);
+      node.index.accept(this);
+
+      return result;
+    } else if (node is PrefixedIdentifier) {
+      node.prefix?.accept(this);
+
+      var resolver = PropertyElementResolver(this);
+      return resolver.resolvePrefixedIdentifier(
+        node: node,
+        hasRead: hasRead,
+        hasWrite: true,
+      );
+    } else if (node is PropertyAccess) {
+      node.target?.accept(this);
+      startNullAwarePropertyAccess(node);
+
+      var resolver = PropertyElementResolver(this);
+      return resolver.resolvePropertyAccess(
+        node: node,
+        hasRead: hasRead,
+        hasWrite: true,
+      );
+    } else if (node is SimpleIdentifier) {
+      var resolver = PropertyElementResolver(this);
+      return resolver.resolveSimpleIdentifier(
+        node: node,
+        hasRead: hasRead,
+        hasWrite: true,
+      );
+    } else {
+      node.accept(this);
+      return PropertyElementResolverResult();
+    }
+  }
+
   /// Visit the given [comment] if it is not `null`.
   void safelyVisitComment(Comment comment) {
     if (comment != null) {
@@ -587,6 +647,53 @@
     }
   }
 
+  /// TODO(scheglov) This is mostly necessary for backward compatibility.
+  /// Although we also use `staticElement` for `getType(left)` below.
+  void setAssignmentBackwardCompatibility({
+    @required CompoundAssignmentExpression assignment,
+    @required AstNode left,
+    @required bool hasRead,
+  }) {
+    if (left is IndexExpression) {
+      if (hasRead) {
+        left.staticElement = assignment.writeElement;
+        left.auxiliaryElements = AuxiliaryElements(assignment.readElement);
+      } else {
+        left.staticElement = assignment.writeElement;
+      }
+      inferenceHelper.recordStaticType(left, assignment.writeType);
+      return;
+    }
+
+    SimpleIdentifier leftIdentifier;
+    if (left is PrefixedIdentifier) {
+      leftIdentifier = left.identifier;
+      inferenceHelper.recordStaticType(left, assignment.writeType);
+    } else if (left is PropertyAccess) {
+      leftIdentifier = left.propertyName;
+      inferenceHelper.recordStaticType(left, assignment.writeType);
+    } else if (left is SimpleIdentifier) {
+      leftIdentifier = left;
+    } else {
+      return;
+    }
+
+    if (hasRead) {
+      var readElement = assignment.readElement;
+      if (readElement is PropertyAccessorElement) {
+        leftIdentifier.auxiliaryElements = AuxiliaryElements(readElement);
+      }
+    }
+
+    leftIdentifier.staticElement = assignment.writeElement;
+    if (assignment.readElement is VariableElement) {
+      var leftType = localVariableTypeProvider.getType(leftIdentifier);
+      inferenceHelper.recordStaticType(leftIdentifier, leftType);
+    } else {
+      inferenceHelper.recordStaticType(leftIdentifier, assignment.writeType);
+    }
+  }
+
   void setReadElement(Expression node, Element element) {
     DartType readType = DynamicTypeImpl.instance;
     if (node is IndexExpression) {
@@ -711,22 +818,7 @@
         identical(parent, _enclosingMixinDeclaration)) {
       return;
     }
-    node.name?.accept(this);
-    node.constructorName?.accept(this);
-    Element element = node.element;
-    if (element is ExecutableElement) {
-      InferenceContext.setType(node.arguments, element.type);
-    }
-    node.arguments?.accept(this);
-    node.accept(elementResolver);
-    node.accept(typeAnalyzer);
-    ElementAnnotationImpl elementAnnotationImpl = node.elementAnnotation;
-    if (elementAnnotationImpl == null) {
-      // Analyzer ignores annotations on "part of" directives.
-      assert(parent is PartOfDirective);
-    } else {
-      elementAnnotationImpl.annotationAst = _createCloner().cloneNode(node);
-    }
+    AnnotationResolver(this).resolve(node);
   }
 
   @override
@@ -1472,9 +1564,31 @@
   void visitIndexExpression(IndexExpression node) {
     node.target?.accept(this);
     startNullAwareIndexExpression(node);
-    node.accept(elementResolver);
+
+    var resolver = PropertyElementResolver(this);
+    var result = resolver.resolveIndexExpression(
+      node: node,
+      hasRead: true,
+      hasWrite: false,
+    );
+
+    var element = result.readElement;
+    node.staticElement = element;
+
+    InferenceContext.setType(node.index, result.indexContextType);
     node.index?.accept(this);
-    node.accept(typeAnalyzer);
+
+    DartType type;
+    if (identical(node.realTarget.staticType, NeverTypeImpl.instance)) {
+      type = NeverTypeImpl.instance;
+    } else if (element is MethodElement) {
+      type = element.returnType;
+    } else {
+      type = DynamicTypeImpl.instance;
+    }
+    inferenceHelper.recordStaticType(node, type);
+
+    nullShortingTermination(node);
   }
 
   @override
@@ -1632,13 +1746,7 @@
 
   @override
   void visitPrefixedIdentifier(PrefixedIdentifier node) {
-    //
-    // We visit the prefix, but do not visit the identifier because it needs to
-    // be visited in the context of the prefix.
-    //
-    node.prefix?.accept(this);
-    node.accept(elementResolver);
-    node.accept(typeAnalyzer);
+    _prefixedIdentifierResolver.resolve(node);
   }
 
   @override
@@ -1648,15 +1756,36 @@
 
   @override
   void visitPropertyAccess(PropertyAccess node) {
-    //
-    // We visit the target, but do not visit the property name because it needs
-    // to be visited in the context of the property access node.
-    //
-    var target = node.target;
-    target?.accept(this);
+    node.target?.accept(this);
     startNullAwarePropertyAccess(node);
-    node.accept(elementResolver);
-    node.accept(typeAnalyzer);
+
+    var resolver = PropertyElementResolver(this);
+    var result = resolver.resolvePropertyAccess(
+      node: node,
+      hasRead: true,
+      hasWrite: false,
+    );
+
+    var element = result.readElement;
+
+    var propertyName = node.propertyName;
+    propertyName.staticElement = element;
+
+    DartType type;
+    if (element is MethodElement) {
+      type = element.type;
+    } else if (element is PropertyAccessorElement && element.isGetter) {
+      type = element.returnType;
+    } else {
+      type = DynamicTypeImpl.instance;
+    }
+
+    type = inferenceHelper.inferTearOff(node, propertyName, type);
+
+    inferenceHelper.recordStaticType(propertyName, type);
+    inferenceHelper.recordStaticType(node, type);
+
+    nullShortingTermination(node);
   }
 
   @override
@@ -1707,7 +1836,7 @@
       return;
     }
 
-    checkReadOfNotAssignedLocalVariable(node);
+    checkReadOfNotAssignedLocalVariable(node, node.staticElement);
 
     super.visitSimpleIdentifier(node);
   }
@@ -1862,8 +1991,19 @@
   void visitVariableDeclaration(VariableDeclaration node) {
     _variableDeclarationResolver.resolve(node);
 
+    var declaredElement = node.declaredElement;
     if (node.parent.parent is ForParts) {
-      _define(node.declaredElement);
+      _define(declaredElement);
+    }
+
+    var initializer = node.initializer;
+    var parent = node.parent;
+    TypeAnnotation declaredType = (parent as VariableDeclarationList).type;
+    if (declaredType == null && initializer != null) {
+      var initializerStaticType = initializer.staticType;
+      if (initializerStaticType is TypeParameterType) {
+        _flowAnalysis?.flow?.promote(declaredElement, initializerStaticType);
+      }
     }
   }
 
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index 3f662eb..610860c 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -15,6 +15,7 @@
 import 'package:analyzer/src/dart/element/type_provider.dart';
 import 'package:analyzer/src/dart/element/type_system.dart';
 import 'package:analyzer/src/dart/resolver/flow_analysis_visitor.dart';
+import 'package:analyzer/src/dart/resolver/invocation_inference_helper.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/generated/migration.dart';
 import 'package:analyzer/src/generated/resolver.dart';
@@ -64,6 +65,8 @@
     _localVariableTypeProvider = _resolver.localVariableTypeProvider;
   }
 
+  InvocationInferenceHelper get _inferenceHelper => _resolver.inferenceHelper;
+
   /// Is `true` if the library being analyzed is non-nullable by default.
   bool get _isNonNullableByDefault =>
       _featureSet.isEnabled(Feature.non_nullable);
@@ -215,32 +218,6 @@
   @override
   void visitFunctionExpression(FunctionExpression node) {}
 
-  /// The Dart Language Specification, 12.29: <blockquote>An assignable expression of the form
-  /// <i>e<sub>1</sub>[e<sub>2</sub>]</i> is evaluated as a method invocation of the operator method
-  /// <i>[]</i> on <i>e<sub>1</sub></i> with argument <i>e<sub>2</sub></i>.</blockquote>
-  @override
-  void visitIndexExpression(IndexExpression node) {
-    if (identical(node.realTarget.staticType, NeverTypeImpl.instance)) {
-      recordStaticType(node, NeverTypeImpl.instance);
-    } else {
-      DartType type;
-      if (node.inSetterContext()) {
-        var parameters = node.staticElement?.parameters;
-        if (parameters?.length == 2) {
-          type = parameters[1].type;
-        }
-      } else {
-        type = node.staticElement?.returnType;
-      }
-
-      type ??= _dynamicType;
-
-      recordStaticType(node, type);
-    }
-
-    _resolver.nullShortingTermination(node);
-  }
-
   /// The Dart Language Specification, 12.11.1: <blockquote>The static type of a new expression of
   /// either the form <i>new T.id(a<sub>1</sub>, &hellip;, a<sub>n</sub>)</i> or the form <i>new
   /// T(a<sub>1</sub>, &hellip;, a<sub>n</sub>)</i> is <i>T</i>.</blockquote>
@@ -316,123 +293,6 @@
     recordStaticType(node, _getStaticType(expression));
   }
 
-  /// See [visitSimpleIdentifier].
-  @override
-  void visitPrefixedIdentifier(PrefixedIdentifier node) {
-    SimpleIdentifier prefixedIdentifier = node.identifier;
-    Element staticElement = prefixedIdentifier.staticElement;
-
-    if (staticElement is ExtensionElement) {
-      _setExtensionIdentifierType(node);
-      return;
-    }
-
-    if (identical(node.prefix.staticType, NeverTypeImpl.instance)) {
-      recordStaticType(prefixedIdentifier, NeverTypeImpl.instance);
-      recordStaticType(node, NeverTypeImpl.instance);
-      return;
-    }
-
-    DartType staticType = _dynamicType;
-    if (staticElement is ClassElement) {
-      if (_isExpressionIdentifier(node)) {
-        var type = _nonNullable(_typeProvider.typeType);
-        node.staticType = type;
-        node.identifier.staticType = type;
-      }
-      return;
-    } else if (staticElement is DynamicElementImpl) {
-      var type = _nonNullable(_typeProvider.typeType);
-      node.staticType = type;
-      node.identifier.staticType = type;
-      return;
-    } else if (staticElement is FunctionTypeAliasElement) {
-      if (node.parent is TypeName) {
-        // no type
-      } else {
-        var type = _nonNullable(_typeProvider.typeType);
-        node.staticType = type;
-        node.identifier.staticType = type;
-      }
-      return;
-    } else if (staticElement is MethodElement) {
-      staticType = staticElement.type;
-    } else if (staticElement is PropertyAccessorElement) {
-      staticType = _getTypeOfProperty(staticElement);
-    } else if (staticElement is ExecutableElement) {
-      staticType = staticElement.type;
-    } else if (staticElement is VariableElement) {
-      staticType = staticElement.type;
-    }
-
-    staticType = _inferTearOff(node, node.identifier, staticType);
-    if (!_inferObjectAccess(node, staticType, prefixedIdentifier)) {
-      recordStaticType(prefixedIdentifier, staticType);
-      recordStaticType(node, staticType);
-    }
-  }
-
-  /// The Dart Language Specification, 12.13: <blockquote> Property extraction allows for a member of
-  /// an object to be concisely extracted from the object. If <i>o</i> is an object, and if <i>m</i>
-  /// is the name of a method member of <i>o</i>, then
-  /// * <i>o.m</i> is defined to be equivalent to: <i>(r<sub>1</sub>, &hellip;, r<sub>n</sub>,
-  /// {p<sub>1</sub> : d<sub>1</sub>, &hellip;, p<sub>k</sub> : d<sub>k</sub>}){return
-  /// o.m(r<sub>1</sub>, &hellip;, r<sub>n</sub>, p<sub>1</sub>: p<sub>1</sub>, &hellip;,
-  /// p<sub>k</sub>: p<sub>k</sub>);}</i> if <i>m</i> has required parameters <i>r<sub>1</sub>,
-  /// &hellip;, r<sub>n</sub></i>, and named parameters <i>p<sub>1</sub> &hellip; p<sub>k</sub></i>
-  /// with defaults <i>d<sub>1</sub>, &hellip;, d<sub>k</sub></i>.
-  /// * <i>(r<sub>1</sub>, &hellip;, r<sub>n</sub>, [p<sub>1</sub> = d<sub>1</sub>, &hellip;,
-  /// p<sub>k</sub> = d<sub>k</sub>]){return o.m(r<sub>1</sub>, &hellip;, r<sub>n</sub>,
-  /// p<sub>1</sub>, &hellip;, p<sub>k</sub>);}</i> if <i>m</i> has required parameters
-  /// <i>r<sub>1</sub>, &hellip;, r<sub>n</sub></i>, and optional positional parameters
-  /// <i>p<sub>1</sub> &hellip; p<sub>k</sub></i> with defaults <i>d<sub>1</sub>, &hellip;,
-  /// d<sub>k</sub></i>.
-  /// Otherwise, if <i>m</i> is the name of a getter member of <i>o</i> (declared implicitly or
-  /// explicitly) then <i>o.m</i> evaluates to the result of invoking the getter. </blockquote>
-  ///
-  /// The Dart Language Specification, 12.17: <blockquote> ... a getter invocation <i>i</i> of the
-  /// form <i>e.m</i> ...
-  ///
-  /// Let <i>T</i> be the static type of <i>e</i>. It is a static type warning if <i>T</i> does not
-  /// have a getter named <i>m</i>.
-  ///
-  /// The static type of <i>i</i> is the declared return type of <i>T.m</i>, if <i>T.m</i> exists;
-  /// otherwise the static type of <i>i</i> is dynamic.
-  ///
-  /// ... a getter invocation <i>i</i> of the form <i>C.m</i> ...
-  ///
-  /// It is a static warning if there is no class <i>C</i> in the enclosing lexical scope of
-  /// <i>i</i>, or if <i>C</i> does not declare, implicitly or explicitly, a getter named <i>m</i>.
-  ///
-  /// The static type of <i>i</i> is the declared return type of <i>C.m</i> if it exists or dynamic
-  /// otherwise.
-  ///
-  /// ... a top-level getter invocation <i>i</i> of the form <i>m</i>, where <i>m</i> is an
-  /// identifier ...
-  ///
-  /// The static type of <i>i</i> is the declared return type of <i>m</i>.</blockquote>
-  @override
-  void visitPropertyAccess(PropertyAccess node) {
-    SimpleIdentifier propertyName = node.propertyName;
-    Element staticElement = propertyName.staticElement;
-    DartType staticType = _dynamicType;
-    if (staticElement is MethodElement) {
-      staticType = staticElement.type;
-    } else if (staticElement is PropertyAccessorElement) {
-      staticType = _getTypeOfProperty(staticElement);
-    } else {
-      // TODO(brianwilkerson) Report this internal error.
-    }
-
-    staticType = _inferTearOff(node, node.propertyName, staticType);
-
-    if (!_inferObjectAccess(node, staticType, propertyName)) {
-      recordStaticType(propertyName, staticType);
-      recordStaticType(node, staticType);
-      _resolver.nullShortingTermination(node);
-    }
-  }
-
   /// The Dart Language Specification, 12.9: <blockquote>The static type of a rethrow expression is
   /// bottom.</blockquote>
   @override
@@ -520,7 +380,7 @@
     } else {
       staticType = _dynamicType;
     }
-    staticType = _inferTearOff(node, node, staticType);
+    staticType = _inferenceHelper.inferTearOff(node, node, staticType);
     recordStaticType(node, staticType);
   }
 
@@ -738,63 +598,6 @@
     }
   }
 
-  /// Given a property access [node] with static type [nodeType],
-  /// and [id] is the property name being accessed, infer a type for the
-  /// access itself and its constituent components if the access is to one of the
-  /// methods or getters of the built in 'Object' type, and if the result type is
-  /// a sealed type. Returns true if inference succeeded.
-  bool _inferObjectAccess(
-      Expression node, DartType nodeType, SimpleIdentifier id) {
-    // If we have an access like `libraryPrefix.hashCode` don't infer it.
-    if (node is PrefixedIdentifier &&
-        node.prefix.staticElement is PrefixElement) {
-      return false;
-    }
-    // Search for Object accesses.
-    String name = id.name;
-    PropertyAccessorElement inferredElement =
-        _typeProvider.objectType.element.getGetter(name);
-    if (inferredElement == null || inferredElement.isStatic) {
-      return false;
-    }
-    inferredElement = _resolver.toLegacyElement(inferredElement);
-    DartType inferredType = inferredElement.returnType;
-    if (nodeType != null &&
-        nodeType.isDynamic &&
-        inferredType is InterfaceType &&
-        _typeProvider.nonSubtypableClasses.contains(inferredType.element)) {
-      recordStaticType(id, inferredType);
-      recordStaticType(node, inferredType);
-      return true;
-    }
-    return false;
-  }
-
-  /// Given an uninstantiated generic function type, referenced by the
-  /// [identifier] in the tear-off [expression], try to infer the instantiated
-  /// generic function type from the surrounding context.
-  DartType _inferTearOff(
-    Expression expression,
-    SimpleIdentifier identifier,
-    DartType tearOffType,
-  ) {
-    var context = InferenceContext.getContext(expression);
-    if (context is FunctionType && tearOffType is FunctionType) {
-      var typeArguments = _typeSystem.inferFunctionTypeInstantiation(
-        context,
-        tearOffType,
-        errorReporter: _resolver.errorReporter,
-        errorNode: expression,
-      );
-      (identifier as SimpleIdentifierImpl).tearOffTypeArgumentTypes =
-          typeArguments;
-      if (typeArguments.isNotEmpty) {
-        return tearOffType.instantiate(typeArguments);
-      }
-    }
-    return tearOffType;
-  }
-
   /// Return `true` if the given [node] is not a type literal.
   bool _isExpressionIdentifier(Identifier node) {
     var parent = node.parent;
diff --git a/pkg/analyzer/lib/src/test_utilities/platform.dart b/pkg/analyzer/lib/src/test_utilities/platform.dart
new file mode 100644
index 0000000..11507ee
--- /dev/null
+++ b/pkg/analyzer/lib/src/test_utilities/platform.dart
@@ -0,0 +1,22 @@
+// 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.
+
+import 'dart:io';
+
+/// The EOL character to be used for source code in tests.
+final platformEol = Platform.isWindows ? '\r\n' : '\n';
+
+/// Normalizes content to use platform-specific newlines to ensure that
+/// when running on Windows \r\n is used even though source files are checked
+/// out using \n.
+String normalizeNewlinesForPlatform(String input) {
+  // Skip normalising for other platforms, as the gitattributes for the SDK
+  // will ensure all files are \n.
+  if (!Platform.isWindows) {
+    return input;
+  }
+
+  final newlinePattern = RegExp(r'\r?\n'); // either \r\n or \n
+  return input.replaceAll(newlinePattern, platformEol);
+}
diff --git a/pkg/analyzer/test/generated/element_resolver_test.dart b/pkg/analyzer/test/generated/element_resolver_test.dart
index f9ae380..35a067a 100644
--- a/pkg/analyzer/test/generated/element_resolver_test.dart
+++ b/pkg/analyzer/test/generated/element_resolver_test.dart
@@ -370,48 +370,6 @@
     _createResolver();
   }
 
-  test_lookUpMethodInInterfaces() async {
-    InterfaceType intType = _typeProvider.intType;
-    //
-    // abstract class A { int operator[](int index); }
-    //
-    ClassElementImpl classA = ElementFactory.classElement2("A");
-    _encloseElement(classA);
-    MethodElement operator =
-        ElementFactory.methodElement("[]", intType, [intType]);
-    classA.methods = <MethodElement>[operator];
-    //
-    // class B implements A {}
-    //
-    ClassElementImpl classB = ElementFactory.classElement2("B");
-    _encloseElement(classB);
-    classB.interfaces = <InterfaceType>[interfaceTypeStar(classA)];
-    //
-    // class C extends Object with B {}
-    //
-    ClassElementImpl classC = ElementFactory.classElement2("C");
-    _encloseElement(classC);
-    classC.mixins = <InterfaceType>[interfaceTypeStar(classB)];
-    //
-    // class D extends C {}
-    //
-    ClassElementImpl classD =
-        ElementFactory.classElement("D", interfaceTypeStar(classC));
-    _encloseElement(classD);
-    //
-    // D a;
-    // a[i];
-    //
-    SimpleIdentifier array = AstTestFactory.identifier3("a");
-    array.staticType = interfaceTypeStar(classD);
-    IndexExpression expression = AstTestFactory.indexExpression(
-      target: array,
-      index: AstTestFactory.identifier3("i"),
-    );
-    expect(_resolveIndexExpression(expression), same(operator));
-    _listener.assertNoErrors();
-  }
-
   test_visitBreakStatement_withLabel() async {
     // loop: while (true) {
     //   break loop;
@@ -706,161 +664,6 @@
     _listener.assertNoErrors();
   }
 
-  test_visitPrefixedIdentifier_nonDynamic() async {
-    ClassElementImpl classA = ElementFactory.classElement2("A");
-    _encloseElement(classA);
-    String getterName = "b";
-    PropertyAccessorElement getter =
-        ElementFactory.getterElement(getterName, false, _typeProvider.intType);
-    classA.accessors = <PropertyAccessorElement>[getter];
-    SimpleIdentifier target = AstTestFactory.identifier3("a");
-    VariableElementImpl variable = ElementFactory.localVariableElement(target);
-    variable.type = interfaceTypeStar(classA);
-    target.staticElement = variable;
-    target.staticType = interfaceTypeStar(classA);
-    PrefixedIdentifier identifier = AstTestFactory.identifier(
-        target, AstTestFactory.identifier3(getterName));
-    _resolveNode(identifier);
-    expect(identifier.staticElement, same(getter));
-    expect(identifier.identifier.staticElement, same(getter));
-    _listener.assertNoErrors();
-  }
-
-  test_visitPrefixedIdentifier_staticClassMember_getter() async {
-    ClassElementImpl classA = ElementFactory.classElement2("A");
-    _encloseElement(classA);
-    // set accessors
-    String propName = "b";
-    PropertyAccessorElement getter =
-        ElementFactory.getterElement(propName, true, _typeProvider.intType);
-    PropertyAccessorElement setter =
-        ElementFactory.setterElement(propName, true, _typeProvider.intType);
-    classA.accessors = <PropertyAccessorElement>[getter, setter];
-    // prepare "A.b"
-    SimpleIdentifier target = AstTestFactory.identifier3("A");
-    target.staticElement = classA;
-    target.staticType = interfaceTypeStar(classA);
-    PrefixedIdentifier identifier =
-        AstTestFactory.identifier(target, AstTestFactory.identifier3(propName));
-    // resolve
-    _resolveNode(identifier);
-    expect(identifier.staticElement, same(getter));
-    expect(identifier.identifier.staticElement, same(getter));
-    _listener.assertNoErrors();
-  }
-
-  test_visitPrefixedIdentifier_staticClassMember_method() async {
-    ClassElementImpl classA = ElementFactory.classElement2("A");
-    _encloseElement(classA);
-    // set methods
-    String propName = "m";
-    var method = ElementFactory.methodElement("m", _typeProvider.intType);
-    method.isStatic = true;
-    classA.methods = <MethodElement>[method];
-    // prepare "A.m"
-    SimpleIdentifier target = AstTestFactory.identifier3("A");
-    target.staticElement = classA;
-    target.staticType = interfaceTypeStar(classA);
-    PrefixedIdentifier identifier =
-        AstTestFactory.identifier(target, AstTestFactory.identifier3(propName));
-    AstTestFactory.expressionStatement(identifier);
-    // resolve
-    _resolveNode(identifier);
-    expect(identifier.staticElement, same(method));
-    expect(identifier.identifier.staticElement, same(method));
-    _listener.assertNoErrors();
-  }
-
-  test_visitPrefixedIdentifier_staticClassMember_setter() async {
-    ClassElementImpl classA = ElementFactory.classElement2("A");
-    _encloseElement(classA);
-    // set accessors
-    String propName = "b";
-    PropertyAccessorElement getter =
-        ElementFactory.getterElement(propName, true, _typeProvider.intType);
-    PropertyAccessorElement setter =
-        ElementFactory.setterElement(propName, true, _typeProvider.intType);
-    classA.accessors = <PropertyAccessorElement>[getter, setter];
-    // prepare "A.b = null"
-    SimpleIdentifier target = AstTestFactory.identifier3("A");
-    target.staticElement = classA;
-    target.staticType = interfaceTypeStar(classA);
-    PrefixedIdentifier identifier =
-        AstTestFactory.identifier(target, AstTestFactory.identifier3(propName));
-    AstTestFactory.assignmentExpression(
-        identifier, TokenType.EQ, AstTestFactory.nullLiteral());
-    // resolve
-    _resolveNode(identifier);
-    expect(identifier.staticElement, same(setter));
-    expect(identifier.identifier.staticElement, same(setter));
-    _listener.assertNoErrors();
-  }
-
-  test_visitPropertyAccess_getter_identifier() async {
-    ClassElementImpl classA = ElementFactory.classElement2("A");
-    _encloseElement(classA);
-    String getterName = "b";
-    PropertyAccessorElement getter =
-        ElementFactory.getterElement(getterName, false, _typeProvider.intType);
-    classA.accessors = <PropertyAccessorElement>[getter];
-    SimpleIdentifier target = AstTestFactory.identifier3("a");
-    target.staticType = interfaceTypeStar(classA);
-    PropertyAccess access = AstTestFactory.propertyAccess2(target, getterName);
-    _resolveNode(access);
-    expect(access.propertyName.staticElement, same(getter));
-    _listener.assertNoErrors();
-  }
-
-  test_visitPropertyAccess_getter_super() async {
-    //
-    // class A {
-    //  int get b;
-    // }
-    // class B {
-    //   ... super.m ...
-    // }
-    //
-    ClassElementImpl classA = ElementFactory.classElement2("A");
-    _encloseElement(classA);
-    String getterName = "b";
-    PropertyAccessorElement getter =
-        ElementFactory.getterElement(getterName, false, _typeProvider.intType);
-    classA.accessors = <PropertyAccessorElement>[getter];
-    SuperExpression target = AstTestFactory.superExpression();
-    var classB = ElementFactory.classElement("B", interfaceTypeStar(classA));
-    _encloseElement(classB);
-    target.staticType = interfaceTypeStar(classB);
-    PropertyAccess access = AstTestFactory.propertyAccess2(target, getterName);
-    AstTestFactory.methodDeclaration2(
-        null,
-        null,
-        null,
-        null,
-        AstTestFactory.identifier3("m"),
-        AstTestFactory.formalParameterList(),
-        AstTestFactory.expressionFunctionBody(access));
-    _resolveNode(access);
-    expect(access.propertyName.staticElement, same(getter));
-    _listener.assertNoErrors();
-  }
-
-  test_visitPropertyAccess_setter_this() async {
-    ClassElementImpl classA = ElementFactory.classElement2("A");
-    _encloseElement(classA);
-    String setterName = "b";
-    PropertyAccessorElement setter =
-        ElementFactory.setterElement(setterName, false, _typeProvider.intType);
-    classA.accessors = <PropertyAccessorElement>[setter];
-    ThisExpression target = AstTestFactory.thisExpression();
-    target.staticType = interfaceTypeStar(classA);
-    PropertyAccess access = AstTestFactory.propertyAccess2(target, setterName);
-    AstTestFactory.assignmentExpression(
-        access, TokenType.EQ, AstTestFactory.integer(0));
-    _resolveNode(access);
-    expect(access.propertyName.staticElement, same(setter));
-    _listener.assertNoErrors();
-  }
-
   test_visitSimpleIdentifier_classScope() async {
     InterfaceType doubleType = _typeProvider.doubleType;
     String fieldName = 'nan';
@@ -1039,19 +842,6 @@
     }
   }
 
-  /// Return the element associated with the given expression after the resolver
-  /// has resolved the expression.
-  ///
-  /// @param node the expression to be resolved
-  /// @param definedElements the elements that are to be defined in the scope in
-  ///          which the element is being resolved
-  /// @return the element to which the expression was resolved
-  Element _resolveIndexExpression(IndexExpression node,
-      [List<Element> definedElements]) {
-    _resolveNode(node, definedElements);
-    return node.staticElement;
-  }
-
   /// Return the element associated with the given identifier after the resolver
   /// has resolved the identifier.
   ///
diff --git a/pkg/analyzer/test/generated/static_type_analyzer_test.dart b/pkg/analyzer/test/generated/static_type_analyzer_test.dart
index 5d380c9..408930a 100644
--- a/pkg/analyzer/test/generated/static_type_analyzer_test.dart
+++ b/pkg/analyzer/test/generated/static_type_analyzer_test.dart
@@ -588,59 +588,6 @@
     _listener.assertNoErrors();
   }
 
-  void test_visitPrefixedIdentifier_getter() {
-    DartType boolType = _typeProvider.boolType;
-    PropertyAccessorElementImpl getter =
-        ElementFactory.getterElement("b", false, boolType);
-    PrefixedIdentifier node = AstTestFactory.identifier5("a", "b");
-    node.identifier.staticElement = getter;
-    expect(_analyze(node), same(boolType));
-    _listener.assertNoErrors();
-  }
-
-  void test_visitPrefixedIdentifier_setter() {
-    DartType boolType = _typeProvider.boolType;
-    FieldElementImpl field =
-        ElementFactory.fieldElement("b", false, false, false, boolType);
-    PropertyAccessorElement setter = field.setter;
-    PrefixedIdentifier node = AstTestFactory.identifier5("a", "b");
-    node.identifier.staticElement = setter;
-    expect(_analyze(node), same(boolType));
-    _listener.assertNoErrors();
-  }
-
-  void test_visitPrefixedIdentifier_variable() {
-    VariableElementImpl variable = ElementFactory.localVariableElement2("b");
-    variable.type = _typeProvider.boolType;
-    PrefixedIdentifier node = AstTestFactory.identifier5("a", "b");
-    node.identifier.staticElement = variable;
-    expect(_analyze(node), same(_typeProvider.boolType));
-    _listener.assertNoErrors();
-  }
-
-  void test_visitPropertyAccess_static_getter() {
-    DartType boolType = _typeProvider.boolType;
-    PropertyAccessorElementImpl getter =
-        ElementFactory.getterElement("b", false, boolType);
-    PropertyAccess node =
-        AstTestFactory.propertyAccess2(AstTestFactory.identifier3("a"), "b");
-    node.propertyName.staticElement = getter;
-    expect(_analyze(node), same(boolType));
-    _listener.assertNoErrors();
-  }
-
-  void test_visitPropertyAccess_static_setter() {
-    DartType boolType = _typeProvider.boolType;
-    FieldElementImpl field =
-        ElementFactory.fieldElement("b", false, false, false, boolType);
-    PropertyAccessorElement setter = field.setter;
-    PropertyAccess node =
-        AstTestFactory.propertyAccess2(AstTestFactory.identifier3("a"), "b");
-    node.propertyName.staticElement = setter;
-    expect(_analyze(node), same(boolType));
-    _listener.assertNoErrors();
-  }
-
   void test_visitSimpleStringLiteral() {
     // "a"
     Expression node = _resolvedString("a");
diff --git a/pkg/analyzer/test/src/dart/element/type_constraint_gatherer_test.dart b/pkg/analyzer/test/src/dart/element/type_constraint_gatherer_test.dart
index 87109c8b..63715f5 100644
--- a/pkg/analyzer/test/src/dart/element/type_constraint_gatherer_test.dart
+++ b/pkg/analyzer/test/src/dart/element/type_constraint_gatherer_test.dart
@@ -841,6 +841,29 @@
     _checkMatch([T], numStar, T_star, true, ['num <: T <: _']);
   }
 
+  /// If `Q` is a legacy type `Q0*` then the match holds under constraint
+  /// set `C`:
+  ///   If `P` is `dynamic` or `void` and `P` is a subtype match for `Q0`
+  ///   under constraint set `C`.
+  test_left_top_right_legacy() {
+    var U = typeParameter('U', bound: objectNone);
+    var U_star = typeParameterTypeStar(U);
+
+    _checkMatch([U], dynamicNone, U_star, false, ['dynamic <: U <: _']);
+    _checkMatch([U], voidNone, U_star, false, ['void <: U <: _']);
+  }
+
+  /// If `Q` is `Q0?` the match holds under constraint set `C`:
+  ///   Or if `P` is `dynamic` or `void` and `Object` is a subtype match
+  ///   for `Q0` under constraint set `C`.
+  test_left_top_right_nullable() {
+    var U = typeParameter('U', bound: objectNone);
+    var U_question = typeParameterTypeQuestion(U);
+
+    _checkMatch([U], dynamicNone, U_question, false, ['Object <: U <: _']);
+    _checkMatch([U], voidNone, U_question, false, ['Object <: U <: _']);
+  }
+
   /// If `P` is a type variable `X` in `L`, then the match holds:
   ///   Under constraint `_ <: X <: Q`.
   test_left_typeParameter() {
diff --git a/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart b/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
index f502c38..f096933 100644
--- a/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
+++ b/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/src/dart/error/syntactic_errors.dart';
+import 'package:analyzer/src/dart/micro/libraries_log.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/lint/registry.dart';
 import 'package:matcher/matcher.dart';
@@ -24,6 +25,10 @@
   String bPath;
   String cPath;
 
+  String get _asyncLibraryPath => futureElement.library.source.fullName;
+
+  String get _coreLibraryPath => intElement.library.source.fullName;
+
   @override
   void setUp() {
     super.setUp();
@@ -32,6 +37,57 @@
     cPath = convertPath('/workspace/dart/test/lib/c.dart');
   }
 
+  test_changeFile_log() async {
+    newFile(aPath, content: r'''
+class A {}
+''');
+
+    newFile(bPath, content: r'''
+import 'a.dart';
+A a;
+B b;
+''');
+
+    result = await resolveFile(bPath);
+    assertErrorsInResolvedUnit(result, [
+      error(CompileTimeErrorCode.UNDEFINED_CLASS, 22, 1),
+    ]);
+
+    newFile(aPath, content: r'''
+class A {}
+class B {}
+''');
+    fileResolver.changeFile(aPath);
+
+    result = await resolveFile(bPath);
+    assertErrorsInResolvedUnit(result, []);
+
+    // The failure of this check will be reported badly.
+    expect(fileResolver.librariesLogEntries, [
+      predicate((LoadLibrariesForTargetLogEntry entry) {
+        expect(entry.target.path, bPath);
+        var loadedPathSet = entry.loaded.map((f) => f.path).toSet();
+        expect(loadedPathSet, contains(aPath));
+        expect(loadedPathSet, contains(bPath));
+        expect(loadedPathSet, contains(_asyncLibraryPath));
+        expect(loadedPathSet, contains(_coreLibraryPath));
+        return true;
+      }),
+      predicate((ChangeFileLoadEntry entry) {
+        expect(entry.target, aPath);
+        var removedPathSet = entry.removed.map((f) => f.path).toSet();
+        expect(removedPathSet, {aPath, bPath});
+        return true;
+      }),
+      predicate((LoadLibrariesForTargetLogEntry entry) {
+        expect(entry.target.path, bPath);
+        var loadedPathSet = entry.loaded.map((f) => f.path).toSet();
+        expect(loadedPathSet, {aPath, bPath});
+        return true;
+      }),
+    ]);
+  }
+
   test_changeFile_refreshedFiles() async {
     newFile(aPath, content: r'''
 class A {}
diff --git a/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart b/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
index 80975a0..0f36155 100644
--- a/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
@@ -2600,4 +2600,34 @@
 
     assertType(findNode.cascade('A()'), 'A');
   }
+
+  test_typeArgumentTypes_generic_inferred_leftTop_dynamic() async {
+    await assertNoErrorsInCode('''
+void foo<T extends Object>(T? value) {}
+
+void f(dynamic o) {
+  foo(o);
+}
+''');
+
+    assertTypeArgumentTypes(
+      findNode.methodInvocation('foo(o)'),
+      ['Object'],
+    );
+  }
+
+  test_typeArgumentTypes_generic_inferred_leftTop_void() async {
+    await assertNoErrorsInCode('''
+void foo<T extends Object>(List<T?> value) {}
+
+void f(List<void> o) {
+  foo(o);
+}
+''');
+
+    assertTypeArgumentTypes(
+      findNode.methodInvocation('foo(o)'),
+      ['Object'],
+    );
+  }
 }
diff --git a/pkg/analyzer/test/src/dart/resolution/postfix_expression_test.dart b/pkg/analyzer/test/src/dart/resolution/postfix_expression_test.dart
index 3cfa0ac..c4838ab 100644
--- a/pkg/analyzer/test/src/dart/resolution/postfix_expression_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/postfix_expression_test.dart
@@ -141,7 +141,27 @@
     );
   }
 
-  test_inc_notLValue_typeLiteral_typeParameter() async {
+  test_inc_notLValue_simpleIdentifier_typeLiteral() async {
+    await assertErrorsInCode(r'''
+void f() {
+  int++;
+}
+''', [
+      error(CompileTimeErrorCode.ASSIGNMENT_TO_TYPE, 13, 3),
+    ]);
+
+    assertPostfixExpression(
+      findNode.postfix('int++'),
+      readElement: intElement,
+      readType: 'dynamic',
+      writeElement: intElement,
+      writeType: 'dynamic',
+      element: null,
+      type: 'dynamic',
+    );
+  }
+
+  test_inc_notLValue_simpleIdentifier_typeLiteral_typeParameter() async {
     await assertErrorsInCode(r'''
 void f<T>() {
   T++;
@@ -153,7 +173,7 @@
     var postfix = findNode.postfix('T++');
     assertPostfixExpression(
       postfix,
-      readElement: null,
+      readElement: findElement.typeParameter('T'),
       readType: 'dynamic',
       writeElement: findElement.typeParameter('T'),
       writeType: 'dynamic',
@@ -165,7 +185,7 @@
       postfix.operand,
       readElement: findElement.typeParameter('T'),
       writeElement: findElement.typeParameter('T'),
-      type: 'Type',
+      type: 'dynamic',
     );
   }
 
@@ -474,26 +494,6 @@
       type: 'num',
     );
   }
-
-  test_inc_simpleIdentifier_typeLiteral() async {
-    await assertErrorsInCode(r'''
-void f() {
-  int++;
-}
-''', [
-      error(CompileTimeErrorCode.ASSIGNMENT_TO_TYPE, 13, 3),
-    ]);
-
-    assertPostfixExpression(
-      findNode.postfix('int++'),
-      readElement: null,
-      readType: 'dynamic',
-      writeElement: intElement,
-      writeType: 'dynamic',
-      element: null,
-      type: 'dynamic',
-    );
-  }
 }
 
 @reflectiveTest
diff --git a/pkg/analyzer/test/src/dart/resolution/prefix_expression_test.dart b/pkg/analyzer/test/src/dart/resolution/prefix_expression_test.dart
index 14ddc4ca..b6b4dec 100644
--- a/pkg/analyzer/test/src/dart/resolution/prefix_expression_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/prefix_expression_test.dart
@@ -215,6 +215,26 @@
     );
   }
 
+  test_plusPlus_notLValue_simpleIdentifier_typeLiteral() async {
+    await assertErrorsInCode(r'''
+void f() {
+  ++int;
+}
+''', [
+      error(CompileTimeErrorCode.ASSIGNMENT_TO_TYPE, 15, 3),
+    ]);
+
+    assertPrefixExpression(
+      findNode.prefix('++int'),
+      readElement: intElement,
+      readType: 'dynamic',
+      writeElement: intElement,
+      writeType: 'dynamic',
+      element: null,
+      type: 'dynamic',
+    );
+  }
+
   test_plusPlus_prefixedIdentifier_instance() async {
     await assertNoErrorsInCode(r'''
 class A {
@@ -580,26 +600,6 @@
     );
   }
 
-  test_plusPlus_simpleIdentifier_typeLiteral() async {
-    await assertErrorsInCode(r'''
-void f() {
-  ++int;
-}
-''', [
-      error(CompileTimeErrorCode.ASSIGNMENT_TO_TYPE, 15, 3),
-    ]);
-
-    assertPrefixExpression(
-      findNode.prefix('++int'),
-      readElement: null,
-      readType: 'dynamic',
-      writeElement: intElement,
-      writeType: 'dynamic',
-      element: null,
-      type: 'dynamic',
-    );
-  }
-
   /// Verify that we get all necessary types when building the dependencies
   /// graph during top-level inference.
   test_plusPlus_topLevelInference() async {
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_export_of_internal_element_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_export_of_internal_element_test.dart
index 40ce958..3ffe641 100644
--- a/pkg/analyzer/test/src/diagnostics/invalid_export_of_internal_element_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/invalid_export_of_internal_element_test.dart
@@ -302,6 +302,7 @@
     ]);
   }
 
+  @override
   void test_internalIsLibSrc() async {
     newFile(testPackageImplementationFilePath, content: r'''
 import 'package:meta/meta.dart';
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_use_of_internal_member_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_use_of_internal_member_test.dart
new file mode 100644
index 0000000..c2757f1
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/invalid_use_of_internal_member_test.dart
@@ -0,0 +1,529 @@
+// 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.
+
+import 'package:analyzer/src/error/codes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/context_collection_resolution.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(InvalidUseOfInternalMemberTest);
+  });
+}
+
+@reflectiveTest
+class InvalidUseOfInternalMemberTest extends PubPackageResolutionTest {
+  String get fooPackageRootPath => '$workspaceRootPath/foo';
+
+  @override
+  String get testPackageRootPath => '/home/my';
+
+  @override
+  void setUp() {
+    super.setUp();
+    writeTestPackagePubspecYamlFile(PubspecYamlFileConfig());
+    writeTestPackageConfig(
+        PackageConfigFileBuilder()
+          ..add(name: 'foo', rootPath: fooPackageRootPath),
+        meta: true);
+  }
+
+  test_insidePackage() async {
+    newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+@internal
+class A {}
+''');
+    newFile('$fooPackageRootPath/lib/a.dart', content: '''
+import 'src/a.dart';
+
+A a = A();
+''');
+    await resolveFile2('$fooPackageRootPath/lib/a.dart');
+
+    assertNoErrorsInResult();
+  }
+
+  test_outsidePackage_class() async {
+    newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+@internal
+class A {}
+''');
+
+    await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+A a = A();
+''', [
+      error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 34, 1),
+    ]);
+  }
+
+  test_outsidePackage_constructor_named() async {
+    newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+class C {
+  @internal
+  C.named();
+}
+''');
+
+    await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+C a = C.named();
+''', [
+      error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 40, 7),
+    ]);
+  }
+
+  test_outsidePackage_constructor_unnamed() async {
+    newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+class C {
+  @internal
+  C();
+}
+''');
+
+    await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+C a = C();
+''', [
+      error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 40, 1),
+    ]);
+  }
+
+  test_outsidePackage_enum() async {
+    newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+@internal
+enum E {one}
+''');
+
+    await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+void f(E value) {}
+''', [
+      error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 41, 1),
+    ]);
+  }
+
+  test_outsidePackage_enumValue() async {
+    newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+enum E {@internal one}
+''');
+
+    await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+E f() => E.one;
+''', [
+      error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 45, 3),
+    ]);
+  }
+
+  test_outsidePackage_extensionMethod() async {
+    newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+extension E on String {
+  @internal
+  int f() => 1;
+}
+''');
+
+    await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+int a = 'hello'.f();
+''', [
+      error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 50, 1),
+    ]);
+  }
+
+  test_outsidePackage_function() async {
+    newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+@internal
+int a() => 1;
+''');
+
+    await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+int b = a() + 1;
+''', [
+      error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 42, 1),
+    ]);
+  }
+
+  test_outsidePackage_function_generic() async {
+    newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+@internal
+int a<T>() => 1;
+''');
+
+    await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+int b = a<void>() + 1;
+''', [
+      error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 42, 1),
+    ]);
+  }
+
+  test_outsidePackage_function_generic_tearoff() async {
+    newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+@internal
+int a<T>() => 1;
+''');
+
+    await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+int Function() b = a;
+''', [
+      error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 53, 1),
+    ]);
+  }
+
+  test_outsidePackage_function_tearoff() async {
+    newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+@internal
+int a() => 1;
+''');
+
+    await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+int Function() b = a;
+''', [
+      error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 53, 1),
+    ]);
+  }
+
+  test_outsidePackage_inCommentReference() async {
+    newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+@internal
+int get a => 1;
+''');
+
+    await assertNoErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+/// This is quite similar to [a].
+int b = 1;
+''');
+  }
+
+  test_outsidePackage_library() async {
+    newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+@internal
+library a;
+import 'package:meta/meta.dart';
+''');
+
+    await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+''', [
+      error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 0, 32),
+      error(HintCode.UNUSED_IMPORT, 7, 24),
+    ]);
+  }
+
+  test_outsidePackage_method() async {
+    newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+class C {
+  @internal
+  int m() => 1;
+}
+''');
+
+    await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+int a = C().m();
+''', [
+      error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 46, 1),
+    ]);
+  }
+
+  test_outsidePackage_method_generic() async {
+    newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+class C {
+  @internal
+  int m<T>() => 1;
+}
+''');
+
+    await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+int a = C().m<void>();
+''', [
+      error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 46, 1),
+    ]);
+  }
+
+  test_outsidePackage_method_subclassed() async {
+    newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+class C {
+  @internal int f() => 1;
+}
+
+class D extends C {}
+''');
+
+    await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+int a = D().f();
+''', [
+      error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 46, 1),
+    ]);
+  }
+
+  test_outsidePackage_method_subclassed_overridden() async {
+    newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+class C {
+  @internal int f() => 1;
+}
+
+class D extends C {
+  int f() => 2;
+}
+''');
+
+    await assertNoErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+int a = D().f();
+''');
+  }
+
+  test_outsidePackage_method_tearoff() async {
+    newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+class C {
+  @internal
+  int m() => 1;
+}
+''');
+
+    await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+int Function() a = C().m;
+''', [
+      error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 57, 1),
+    ]);
+  }
+
+  test_outsidePackage_methodParameter_named() async {
+    newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+class C {
+  int m({@internal int a = 0}) => 1;
+}
+''');
+
+    await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+int a = C().m(a: 5);
+''', [
+      error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 48, 1),
+    ]);
+  }
+
+  @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/28066')
+  test_outsidePackage_methodParameter_positional() async {
+    newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+class C {
+  int m([@internal int a = 0]) => 1;
+}
+''');
+
+    await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+int a = C().m(5);
+''', [
+      error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 48, 1),
+    ]);
+  }
+
+  test_outsidePackage_mixin() async {
+    newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+@internal
+mixin A {}
+''');
+
+    await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+class C with A {}
+''', [
+      error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 47, 1),
+    ]);
+  }
+
+  test_outsidePackage_pairedWithProtected() async {
+    newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+class C {
+  @internal
+  @protected
+  void f() {}
+}
+''');
+
+    await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+class D extends C {
+  void g() => f();
+}
+''', [
+      error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 68, 1),
+    ]);
+  }
+
+  test_outsidePackage_redirectingFactoryConstructor() async {
+    newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+import 'package:test/test.dart';
+class D implements C {
+  @internal D();
+}
+''');
+
+    await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+class C {
+  factory C() = D;
+}
+''', [
+      error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 60, 1),
+    ]);
+  }
+
+  test_outsidePackage_superConstructor() async {
+    newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+class C {
+  @internal C();
+}
+''');
+
+    await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+class D extends C {
+  D() : super();
+}
+''', [
+      error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 62, 7),
+    ]);
+  }
+
+  test_outsidePackage_superConstructor_named() async {
+    newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+class C {
+  @internal C.named();
+}
+''');
+
+    await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+class D extends C {
+  D() : super.named();
+}
+''', [
+      error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 68, 5),
+    ]);
+  }
+
+  test_outsidePackage_topLevelGetter() async {
+    newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+@internal
+int get a => 1;
+''');
+
+    await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+int b = a + 1;
+''', [
+      error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 42, 1),
+    ]);
+  }
+
+  test_outsidePackage_typedef() async {
+    newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+@internal
+typedef t = void Function();
+''');
+
+    await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+t func = () {};
+''', [
+      error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 34, 1),
+    ]);
+  }
+
+  @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/28066')
+  test_outsidePackage_typedefParameter() async {
+    newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+typedef T = void Function({@internal int a = 1});
+''');
+
+    await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+void f(T t) => t(a: 5);
+''', [
+      error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 42, 1),
+    ]);
+  }
+
+  test_outsidePackage_variable() async {
+    newFile('$fooPackageRootPath/lib/src/a.dart', content: '''
+import 'package:meta/meta.dart';
+@internal
+int a = 1;
+''');
+
+    await assertErrorsInCode('''
+import 'package:foo/src/a.dart';
+
+int b = a + 1;
+''', [
+      error(HintCode.INVALID_USE_OF_INTERNAL_MEMBER, 42, 1),
+    ]);
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart
index 08a65a1..0711ccb 100644
--- a/pkg/analyzer/test/src/diagnostics/test_all.dart
+++ b/pkg/analyzer/test/src/diagnostics/test_all.dart
@@ -324,6 +324,8 @@
 import 'invalid_uri_test.dart' as invalid_uri;
 import 'invalid_use_of_covariant_in_extension_test.dart'
     as invalid_use_of_covariant_in_extension;
+import 'invalid_use_of_internal_member_test.dart'
+    as invalid_use_of_internal_member;
 import 'invalid_use_of_protected_member_test.dart'
     as invalid_use_of_protected_member;
 import 'invalid_use_of_visible_for_template_member_test.dart'
@@ -861,6 +863,7 @@
     invalid_type_argument_in_const_set.main();
     invalid_uri.main();
     invalid_use_of_covariant_in_extension.main();
+    invalid_use_of_internal_member.main();
     invalid_use_of_protected_member.main();
     invalid_use_of_visible_for_template_member.main();
     invalid_use_of_visible_for_testing_member.main();
diff --git a/pkg/analyzer/test/src/diagnostics/undefined_annotation_test.dart b/pkg/analyzer/test/src/diagnostics/undefined_annotation_test.dart
index 779d2d2..711ac51 100644
--- a/pkg/analyzer/test/src/diagnostics/undefined_annotation_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/undefined_annotation_test.dart
@@ -15,6 +15,16 @@
 
 @reflectiveTest
 class UndefinedAnnotationTest extends PubPackageResolutionTest {
+  test_identifier1_localVariable_const() async {
+    await assertNoErrorsInCode(r'''
+main() {
+  const a = 0;
+  g(@a x) {}
+  g(0);
+}
+''');
+  }
+
   test_unresolved_identifier() async {
     await assertErrorsInCode(r'''
 @unresolved
diff --git a/pkg/analyzer_cli/lib/src/context_cache.dart b/pkg/analyzer_cli/lib/src/context_cache.dart
index bdbe19a..276ac43 100644
--- a/pkg/analyzer_cli/lib/src/context_cache.dart
+++ b/pkg/analyzer_cli/lib/src/context_cache.dart
@@ -111,7 +111,6 @@
 
     _buildContextFeatureSet(contextOptions);
     contextOptions.hint = !clOptions.disableHints;
-    contextOptions.useFastaParser = clOptions.useFastaParser;
     return contextOptions;
   }
 
diff --git a/pkg/analyzer_cli/lib/src/options.dart b/pkg/analyzer_cli/lib/src/options.dart
index e54f8ae..cff668d 100644
--- a/pkg/analyzer_cli/lib/src/options.dart
+++ b/pkg/analyzer_cli/lib/src/options.dart
@@ -104,9 +104,6 @@
   /// (Or null if not enabled.)
   final String perfReport;
 
-  /// Whether to enable parsing via the Fasta parser.
-  final bool useFastaParser;
-
   /// Batch mode (for unit testing)
   final bool batchMode;
 
@@ -177,7 +174,6 @@
         log = cast(args['log']),
         machineFormat = args['format'] == 'machine',
         perfReport = cast(args['x-perf-report']),
-        useFastaParser = cast(args['use-fasta-parser']),
         batchMode = cast(args['batch']),
         showPackageWarnings = cast(args['show-package-warnings']) ||
             cast(args['package-warnings']) ||
@@ -443,14 +439,6 @@
           defaultsTo: false,
           negatable: false,
           hide: true)
-      // TODO(brianwilkerson) Remove the following option after we're sure that
-      // it's no longer being used.
-      ..addFlag('enable-assert-initializers',
-          help:
-              'Enable parsing of asserts in constructor initializers (deprecated).',
-          defaultsTo: null,
-          negatable: false,
-          hide: hide)
       ..addFlag('use-analysis-driver-memory-byte-store',
           help: 'Use memory byte store, not the file system cache.',
           defaultsTo: false,
@@ -477,15 +465,6 @@
               'of "libraryUri".',
           splitCommas: false,
           hide: hide)
-      ..addFlag('use-fasta-parser',
-          help: 'Whether to enable parsing via the Fasta parser.',
-          defaultsTo: true,
-          hide: hide)
-      ..addFlag('preview-dart-2',
-          help: 'Enable the Dart 2.0 preview.',
-          defaultsTo: true,
-          hide: hide,
-          negatable: true)
       ..addFlag('train-snapshot',
           help: 'Analyze the given source for the purposes of training a '
               'dartanalyzer snapshot.',
diff --git a/pkg/analyzer_cli/test/driver_test.dart b/pkg/analyzer_cli/test/driver_test.dart
index 8d0c27a..126856d 100644
--- a/pkg/analyzer_cli/test/driver_test.dart
+++ b/pkg/analyzer_cli/test/driver_test.dart
@@ -27,12 +27,9 @@
     defineReflectiveTests(BuildModeTest);
     defineReflectiveTests(BuildModeSummaryDependenciesTest);
     defineReflectiveTests(ExitCodesTest);
-    defineReflectiveTests(ExitCodesTest_PreviewDart2);
     defineReflectiveTests(LinterTest);
-    defineReflectiveTests(LinterTest_PreviewDart2);
     defineReflectiveTests(NonDartFilesTest);
     defineReflectiveTests(OptionsTest);
-    defineReflectiveTests(OptionsTest_PreviewDart2);
   }, name: 'Driver');
 }
 
@@ -93,8 +90,6 @@
 
   AnalysisOptions get analysisOptions => driver.analysisDriver.analysisOptions;
 
-  bool get usePreviewDart2 => false;
-
   /// Normalize text with bullets.
   String bulletToDash(StringSink item) => '$item'.replaceAll('•', '-');
 
@@ -127,9 +122,6 @@
       ];
     }
     cmd..addAll(sources.map(_adjustFileSpec))..addAll(args);
-    if (usePreviewDart2) {
-      cmd.insert(0, '--preview-dart-2');
-    }
 
     await driver.start(cmd);
   }
@@ -772,12 +764,6 @@
     });
   }
 
-  Future<void> test_enableAssertInitializer() async {
-    await drive('data/file_with_assert_initializers.dart',
-        args: ['--enable-assert-initializers']);
-    expect(exitCode, 0);
-  }
-
   Future<void> test_fatalErrors() async {
     await drive('data/file_with_error.dart');
     expect(exitCode, 3);
@@ -836,12 +822,6 @@
 }
 
 @reflectiveTest
-class ExitCodesTest_PreviewDart2 extends ExitCodesTest {
-  @override
-  bool get usePreviewDart2 => true;
-}
-
-@reflectiveTest
 class LinterTest extends BaseTest {
   String get optionsFileName => AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE;
 
@@ -938,12 +918,6 @@
 }
 
 @reflectiveTest
-class LinterTest_PreviewDart2 extends LinterTest {
-  @override
-  bool get usePreviewDart2 => true;
-}
-
-@reflectiveTest
 class NonDartFilesTest extends BaseTest {
   Future<void> test_analysisOptionsYaml() async {
     await withTempDirAsync((tempDir) async {
@@ -1133,12 +1107,6 @@
   }
 }
 
-@reflectiveTest
-class OptionsTest_PreviewDart2 extends OptionsTest {
-  @override
-  bool get usePreviewDart2 => true;
-}
-
 class TestSource implements Source {
   TestSource();
 
diff --git a/pkg/analyzer_cli/test/options_test.dart b/pkg/analyzer_cli/test/options_test.dart
index 188a92f..12ff74c 100644
--- a/pkg/analyzer_cli/test/options_test.dart
+++ b/pkg/analyzer_cli/test/options_test.dart
@@ -257,11 +257,6 @@
         expect(failureMessage, equals('Invalid Dart SDK path: &&&&&'));
       });
 
-      test('--use-fasta-parser', () {
-        var options = parse(['--use-fasta-parser', 'foo.dart']);
-        expect(options.useFastaParser, isTrue);
-      });
-
       test('--train-snapshot', () {
         var options = parse(['--train-snapshot', 'foo.dart']);
         expect(options.trainSnapshot, isTrue);
diff --git a/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart b/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart
index 3f3db93..61305c7 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/change_builder/change_builder_dart.dart
@@ -309,6 +309,29 @@
   }
 
   @override
+  void writeImportedName(List<Uri> uris, String name) {
+    assert(uris.isNotEmpty);
+    var imports = <ImportElement>[];
+    for (var uri in uris) {
+      imports.addAll(dartFileEditBuilder._getImportsForUri(uri));
+    }
+    var import = _getBestImportForName(imports, name);
+    if (import == null) {
+      var library = dartFileEditBuilder._importLibrary(uris[0]);
+      if (library.prefix != null) {
+        write(library.prefix);
+        write('.');
+      }
+    } else {
+      if (import.prefix != null) {
+        write(import.prefix.displayName);
+        write('.');
+      }
+    }
+    write(name);
+  }
+
+  @override
   void writeLocalVariableDeclaration(String name,
       {void Function() initializerWriter,
       bool isConst = false,
@@ -940,6 +963,33 @@
     return name;
   }
 
+  /// Given a list of [imports] that do, or can, make the [name] visible in
+  /// scope, return the one that will lead to the cleanest code.
+  ImportElement _getBestImportForName(
+      List<ImportElement> imports, String name) {
+    if (imports.isEmpty) {
+      return null;
+    } else if (imports.length == 1) {
+      return imports[0];
+    }
+    imports.sort((first, second) {
+      // Prefer imports that make the name visible.
+      var firstDefinesName = first.namespace.definedNames.containsKey(name);
+      var secondDefinesName = second.namespace.definedNames.containsKey(name);
+      if (firstDefinesName != secondDefinesName) {
+        return firstDefinesName ? -1 : 1;
+      }
+      // Prefer imports without prefixes.
+      var firstHasPrefix = first.prefix != null;
+      var secondHasPrefix = second.prefix != null;
+      if (firstHasPrefix != secondHasPrefix) {
+        return firstHasPrefix ? 1 : -1;
+      }
+      return 0;
+    });
+    return imports[0];
+  }
+
   /// Returns all variants of names by removing leading words one by one.
   List<String> _getCamelWordCombinations(String name) {
     var result = <String>[];
@@ -1100,24 +1150,41 @@
   /// If a [methodBeingCopied] is provided, then the type parameters of that
   /// method will be duplicated in the copy and will therefore be visible.
   ///
+  /// If [required] it `true`, then the type will be written even if it would
+  /// normally be omitted, such as with `dynamic`.
+  ///
   /// Causes any libraries whose elements are used by the generated code, to be
   /// imported.
-  bool _writeType(DartType type, {ExecutableElement methodBeingCopied}) {
+  bool _writeType(DartType type,
+      {ExecutableElement methodBeingCopied, bool required = false}) {
     type = _getVisibleType(type, methodBeingCopied: methodBeingCopied);
 
     // If not a useful type, don't write it.
-    if (type == null || type.isDynamic || type.isBottom) {
+    if (type == null) {
       return false;
     }
-
-    var element = type.element;
-
+    if (type.isDynamic) {
+      if (required) {
+        write('dynamic');
+        return true;
+      }
+      return false;
+    }
+    if (type.isBottom) {
+      var library = dartFileEditBuilder.resolvedUnit.libraryElement;
+      if (library.isNonNullableByDefault) {
+        write('Never');
+        return true;
+      }
+      return false;
+    }
     // The type `void` does not have an element.
     if (type is VoidType) {
       write('void');
       return true;
     }
 
+    var element = type.element;
     // Typedef(s) are represented as GenericFunctionTypeElement(s).
     if (element is GenericFunctionTypeElement &&
         element.typeParameters.isEmpty &&
@@ -1143,9 +1210,6 @@
     // Write the simple name.
     var name = element.displayName;
     write(name);
-    if (type.nullabilitySuffix == NullabilitySuffix.question) {
-      write('?');
-    }
 
     // Write type arguments.
     if (type is ParameterizedType) {
@@ -1167,12 +1231,17 @@
           if (i != 0) {
             write(', ');
           }
-          _writeType(argument, methodBeingCopied: methodBeingCopied);
+          _writeType(argument,
+              required: true, methodBeingCopied: methodBeingCopied);
         }
         write('>');
       }
     }
 
+    if (type.nullabilitySuffix == NullabilitySuffix.question) {
+      write('?');
+    }
+
     return true;
   }
 }
@@ -1535,6 +1604,15 @@
     return null;
   }
 
+  Iterable<ImportElement> _getImportsForUri(Uri uri) sync* {
+    for (var import in resolvedUnit.libraryElement.imports) {
+      var importUri = import.importedLibrary.source.uri;
+      if (importUri == uri) {
+        yield import;
+      }
+    }
+  }
+
   /// Computes the best URI to import [uri] into the target library.
   String _getLibraryUriText(Uri uri) {
     if (uri.scheme == 'file') {
diff --git a/pkg/analyzer_plugin/lib/utilities/change_builder/change_builder_dart.dart b/pkg/analyzer_plugin/lib/utilities/change_builder/change_builder_dart.dart
index fef21a1..1b513a2 100644
--- a/pkg/analyzer_plugin/lib/utilities/change_builder/change_builder_dart.dart
+++ b/pkg/analyzer_plugin/lib/utilities/change_builder/change_builder_dart.dart
@@ -148,6 +148,10 @@
       DartType returnType,
       String returnTypeGroupName});
 
+  /// Write the given [name], possibly with a prefix, assuming that the name can
+  /// be imported from any of the given [uris].
+  void writeImportedName(List<Uri> uris, String name);
+
   /// Write the code for a declaration of a local variable with the given
   /// [name]. If an [initializerWriter] is provided, it will be invoked to write
   /// the content of the initializer. (The equal sign separating the variable
diff --git a/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart b/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart
index 764a691..4a5ae22 100644
--- a/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart
+++ b/pkg/analyzer_plugin/test/src/utilities/change_builder/change_builder_dart_test.dart
@@ -538,6 +538,65 @@
     expect(position.offset, equals(20));
   }
 
+  Future<void> test_writeImportedName_hasImport_first() async {
+    // addSource(convertPath('/home/test/lib/foo.dart'), '');
+    var path = convertPath('/home/test/lib/test.dart');
+    addSource(path, '''
+import 'foo.dart';
+''');
+
+    var builder = newBuilder();
+    await builder.addDartFileEdit(path, (builder) {
+      builder.addInsertion(0, (builder) {
+        builder.writeImportedName([
+          Uri.parse('package:test/foo.dart'),
+          Uri.parse('package:test/bar.dart')
+        ], 'Foo');
+      });
+    });
+    var edit = getEdit(builder);
+    expect(edit.replacement, equalsIgnoringWhitespace('Foo'));
+  }
+
+  Future<void> test_writeImportedName_hasImport_second() async {
+    var path = convertPath('/home/test/lib/test.dart');
+    addSource(path, '''
+import 'bar.dart';
+''');
+
+    var builder = newBuilder();
+    await builder.addDartFileEdit(path, (builder) {
+      builder.addInsertion(0, (builder) {
+        builder.writeImportedName([
+          Uri.parse('package:test/foo.dart'),
+          Uri.parse('package:test/bar.dart')
+        ], 'Foo');
+      });
+    });
+    var edit = getEdit(builder);
+    expect(edit.replacement, equalsIgnoringWhitespace('Foo'));
+  }
+
+  Future<void> test_writeImportedName_needsImport() async {
+    var path = convertPath('/home/test/lib/test.dart');
+    addSource(path, '');
+
+    var builder = newBuilder();
+    await builder.addDartFileEdit(path, (builder) {
+      builder.addInsertion(0, (builder) {
+        builder.writeImportedName([
+          Uri.parse('package:test/foo.dart'),
+          Uri.parse('package:test/bar.dart')
+        ], 'Foo');
+      });
+    });
+    var edits = getEdits(builder);
+    expect(edits, hasLength(2));
+    expect(edits[0].replacement,
+        equalsIgnoringWhitespace("import 'package:test/foo.dart';\n"));
+    expect(edits[1].replacement, equalsIgnoringWhitespace('Foo'));
+  }
+
   Future<void> test_writeLocalVariableDeclaration_noType_initializer() async {
     var path = convertPath('/home/test/lib/test.dart');
     var content = '''
diff --git a/pkg/analyzer_plugin/tool/spec/common_types_spec.html b/pkg/analyzer_plugin/tool/spec/common_types_spec.html
index c49dce7..0144da8 100644
--- a/pkg/analyzer_plugin/tool/spec/common_types_spec.html
+++ b/pkg/analyzer_plugin/tool/spec/common_types_spec.html
@@ -6,7 +6,7 @@
 </head>
 <body>
 <h1>Common Types</h1>
-<version>1.2.0</version>
+<version>1.2.1</version>
 <p>
   This document contains a specification of the types that are common between
   the analysis server wire protocol and the analysis server plugin wire
diff --git a/pkg/compiler/lib/src/commandline_options.dart b/pkg/compiler/lib/src/commandline_options.dart
index d76446b..ace1d4c 100644
--- a/pkg/compiler/lib/src/commandline_options.dart
+++ b/pkg/compiler/lib/src/commandline_options.dart
@@ -23,6 +23,7 @@
   static const String enableCheckedMode = '--enable-checked-mode';
   static const String enableAsserts = '--enable-asserts';
   static const String enableNullAssertions = '--null-assertions';
+  static const String enableNativeNullAssertions = '--native-null-assertions';
   static const String enableDiagnosticColors = '--enable-diagnostic-colors';
   static const String experimentalTrackAllocations =
       '--experimental-track-allocations';
diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart
index 2922b61..5eeb420 100644
--- a/pkg/compiler/lib/src/dart2js.dart
+++ b/pkg/compiler/lib/src/dart2js.dart
@@ -444,6 +444,7 @@
         (_) => setCheckedMode(Flags.enableCheckedMode)),
     new OptionHandler(Flags.enableAsserts, passThrough),
     new OptionHandler(Flags.enableNullAssertions, passThrough),
+    new OptionHandler(Flags.enableNativeNullAssertions, passThrough),
     new OptionHandler(Flags.trustTypeAnnotations, setTrustTypeAnnotations),
     new OptionHandler(Flags.trustPrimitives, passThrough),
     new OptionHandler(Flags.trustJSInteropTypeAnnotations, passThrough),
diff --git a/pkg/compiler/lib/src/kernel/dart2js_target.dart b/pkg/compiler/lib/src/kernel/dart2js_target.dart
index f56563a..c93e774 100644
--- a/pkg/compiler/lib/src/kernel/dart2js_target.dart
+++ b/pkg/compiler/lib/src/kernel/dart2js_target.dart
@@ -69,6 +69,9 @@
   bool get supportsLateFields => false;
 
   @override
+  bool get supportsLateLoweringSentinel => false;
+
+  @override
   bool get useStaticFieldLowering => false;
 
   // TODO(johnniwinther,sigmund): Remove this when js-interop handles getter
diff --git a/pkg/compiler/lib/src/options.dart b/pkg/compiler/lib/src/options.dart
index 110e36e..368ee30 100644
--- a/pkg/compiler/lib/src/options.dart
+++ b/pkg/compiler/lib/src/options.dart
@@ -253,8 +253,8 @@
   bool enableNullAssertions = false;
 
   /// Whether to generate code asserting that non-nullable return values of
-  /// `@Native` methods are checked for being non-null.
-  bool enableNativeReturnNullAssertions = false;
+  /// `@Native` methods or `JS()` invocations are checked for being non-null.
+  bool enableNativeNullAssertions = false;
 
   /// Whether to generate a source-map file together with the output program.
   bool generateSourceMap = true;
@@ -484,6 +484,8 @@
           _hasOption(options, Flags.enableAsserts)
       ..enableNullAssertions = _hasOption(options, Flags.enableCheckedMode) ||
           _hasOption(options, Flags.enableNullAssertions)
+      ..enableNativeNullAssertions =
+          _hasOption(options, Flags.enableNativeNullAssertions)
       ..experimentalTrackAllocations =
           _hasOption(options, Flags.experimentalTrackAllocations)
       ..experimentalAllocationsPath = _extractStringOption(
@@ -634,11 +636,6 @@
     if (_deferClassTypes) deferClassTypes = true;
     if (_noDeferClassTypes) deferClassTypes = false;
 
-    if (enableNullAssertions) {
-      // TODO(sra): Add a command-line flag to control this independently.
-      enableNativeReturnNullAssertions = true;
-    }
-
     if (_newDeferredSplit) newDeferredSplit = true;
     if (_noNewDeferredSplit) newDeferredSplit = false;
   }
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index e2738fd..a43c369 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -1547,7 +1547,7 @@
           sourceInformation: null));
       HInstruction value = pop();
       // TODO(johnniwinther): Provide source information.
-      if (options.enableNativeReturnNullAssertions) {
+      if (options.enableNativeNullAssertions) {
         if (_isNonNullableByDefault(functionNode)) {
           DartType type = _getDartTypeIfValid(functionNode.returnType);
           if (dartTypes.isNonNullableIfSound(type)) {
@@ -4728,6 +4728,41 @@
       // It is acceptable for the type parameter to be broader than the
       // specified type.
     }
+
+    _maybeAddNullCheckOnJS(invocation);
+  }
+
+  /// If [invocation] is a `JS()` invocation in a web library and the static
+  /// type is non-nullable, add a check to make sure it isn't null.
+  void _maybeAddNullCheckOnJS(ir.StaticInvocation invocation) {
+    if (options.enableNativeNullAssertions &&
+        _isInWebLibrary(invocation) &&
+        closedWorld.dartTypes
+            .isNonNullableIfSound(_getStaticType(invocation).type)) {
+      HInstruction code = pop();
+      push(new HNullCheck(
+          code, _abstractValueDomain.excludeNull(code.instructionType),
+          sticky: true));
+    }
+  }
+
+  /// Returns true if [node] belongs to dart:html and related libraries.
+  bool _isInWebLibrary(ir.TreeNode node) {
+    if (node == null) return false;
+    bool isWebLibrary(Uri importUri) =>
+        importUri.scheme == 'dart' &&
+            (importUri.path == 'html' ||
+                importUri.path == 'svg' ||
+                importUri.path == 'indexed_db' ||
+                importUri.path == 'web_audio' ||
+                importUri.path == 'web_gl' ||
+                importUri.path == 'web_sql' ||
+                importUri.path == 'html_common') ||
+        // Mock web library path for testing.
+        importUri.path
+            .contains('native_null_assertions/js_invocations_in_web_library');
+    if (node is ir.Library) return isWebLibrary(node.importUri);
+    return _isInWebLibrary(node.parent);
   }
 
   void _handleJsStringConcat(ir.StaticInvocation invocation) {
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
index ced7369..3718f17d 100644
--- a/pkg/compiler/lib/src/ssa/optimize.dart
+++ b/pkg/compiler/lib/src/ssa/optimize.dart
@@ -925,7 +925,7 @@
 
   HInstruction maybeAddNativeReturnNullCheck(
       HInstruction node, HInstruction replacement, FunctionEntity method) {
-    if (_options.enableNativeReturnNullAssertions) {
+    if (_options.enableNativeNullAssertions) {
       if (method.library.isNonNullableByDefault) {
         FunctionType type =
             _closedWorld.elementEnvironment.getFunctionType(method);
diff --git a/pkg/dart_internal/pubspec.yaml b/pkg/dart_internal/pubspec.yaml
index 757bdf3..191de63 100644
--- a/pkg/dart_internal/pubspec.yaml
+++ b/pkg/dart_internal/pubspec.yaml
@@ -1,5 +1,5 @@
 name: dart_internal
-version: 0.1.11-nullsafety
+version: 0.1.12-nullsafety
 author: "Dart Team <misc@dartlang.org>"
 homepage: http://www.dartlang.org
 repository: https://github.com/dart-lang/sdk/tree/master/pkg/dart_internal
@@ -18,4 +18,4 @@
 environment:
   # Restrict the upper bound so that we can remove support for this in a later
   # version of the SDK without it being a breaking change.
-  sdk: ">=2.10.0-0.0 <2.10.0"
+  sdk: ">=2.10.0-0 <2.11.0"
diff --git a/pkg/dev_compiler/lib/src/kernel/expression_compiler.dart b/pkg/dev_compiler/lib/src/kernel/expression_compiler.dart
index 47d0805..e57a2fb 100644
--- a/pkg/dev_compiler/lib/src/kernel/expression_compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/expression_compiler.dart
@@ -3,7 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'dart:async';
-import 'dart:io';
 
 import 'package:_fe_analyzer_shared/src/messages/diagnostic_message.dart'
     show DiagnosticMessage, DiagnosticMessageHandler;
@@ -206,24 +205,29 @@
 class ExpressionCompiler {
   static final String debugProcedureName = '\$dartEval';
 
-  final bool verbose;
+  final CompilerContext _context;
+  final CompilerOptions _options;
+  final List<String> errors;
   final IncrementalCompiler _compiler;
   final ProgramCompiler _kernel2jsCompiler;
   final Component _component;
-  final List<String> errors;
+
   DiagnosticMessageHandler onDiagnostic;
 
   void _log(String message) {
-    if (verbose) {
-      // writing to stdout breaks communication to
-      // frontend server, which is done on stdin/stdout,
-      // so we use stderr here instead
-      stderr.writeln(message);
+    if (_options.verbose) {
+      _context.options.ticker.logMs(message);
     }
   }
 
-  ExpressionCompiler(this._compiler, this._kernel2jsCompiler, this._component,
-      {this.verbose, this.onDiagnostic, this.errors});
+  ExpressionCompiler(
+    this._options,
+    this.errors,
+    this._compiler,
+    this._kernel2jsCompiler,
+    this._component,
+  )   : onDiagnostic = _options.onDiagnostic,
+        _context = _compiler.context;
 
   /// Compiles [expression] in [libraryUri] at [line]:[column] to JavaScript
   /// in [moduleName].
@@ -256,11 +260,11 @@
       String expression) async {
     // 1. find dart scope where debugger is paused
 
-    _log('ExpressionCompiler: compiling:  $expression in $moduleName');
+    _log('Compiling expression in $moduleName:\n$expression');
 
     var dartScope = await _findScopeAt(Uri.parse(libraryUri), line, column);
     if (dartScope == null) {
-      _log('ExpressionCompiler: scope not found at $libraryUri:$line:$column');
+      _log('Scope not found at $libraryUri:$line:$column');
       return null;
     }
 
@@ -280,8 +284,7 @@
     var localJsScope =
         dartScope.definitions.keys.map((variable) => jsScope[variable]);
 
-    _log('ExpressionCompiler: dart scope: $dartScope');
-    _log('ExpressionCompiler: substituted local JsScope: $localJsScope');
+    _log('Performed scope substitutions for expression');
 
     // 3. compile dart expression to JS
 
@@ -289,7 +292,7 @@
         await _compileExpression(dartScope, jsModules, moduleName, expression);
 
     if (jsExpression == null) {
-      _log('ExpressionCompiler: failed to compile $expression, $jsExpression');
+      _log('Failed to compile expression in $moduleName:\n$expression');
       return null;
     }
 
@@ -323,7 +326,8 @@
 error.name + ": " + error.message;
 }''';
 
-    _log('ExpressionCompiler: compiled $expression to $callExpression');
+    _log(
+        'Compiled expression in $moduleName:\n$expression to \n$callExpression');
     return callExpression;
   }
 
@@ -350,6 +354,7 @@
       return null;
     }
 
+    _log('Detected expression compilation scope');
     return scope;
   }
 
@@ -362,6 +367,8 @@
 
         return library.library;
       }
+
+      _log('Loaded library for expression');
       return null;
     });
   }
@@ -415,8 +422,6 @@
       Map<String, String> modules,
       String currentModule,
       String expression) async {
-    // 1. Compile expression to kernel AST
-
     var procedure = await _compiler.compileExpression(
         expression,
         scope.definitions,
@@ -426,6 +431,8 @@
         scope.cls?.name,
         scope.procedure.isStatic);
 
+    _log('Compiled expression to kernel');
+
     // TODO: make this code clear and assumptions enforceable
     // https://github.com/dart-lang/sdk/issues/43273
     //
@@ -438,14 +445,12 @@
       return null;
     }
 
-    _log('ExpressionCompiler: Kernel: ${procedure.leakingDebugToString()}');
-
-    // 2. compile kernel AST to JS ast
-
     var jsFun = _kernel2jsCompiler.emitFunctionIncremental(
         scope.library, scope.cls, procedure.function, '$debugProcedureName');
 
-    // 3. apply temporary workarounds for what ideally
+    _log('Generated JavaScript for expression');
+
+    // apply temporary workarounds for what ideally
     // needs to be done in the compiler
 
     // get private fields accessed by the evaluated expression
@@ -478,10 +483,6 @@
       }
     }
 
-    _log('ExpressionCompiler: privateFields: $privateFields');
-    _log('ExpressionCompiler: currentLibraries: $currentLibraries');
-    _log('ExpressionCompiler: currentModules: $currentModules');
-
     var body = js_ast.Block([
       // require modules used in evaluated expression
       ...currentModules.keys.map((String variable) =>
@@ -495,15 +496,15 @@
     ]);
 
     var jsFunModified = js_ast.Fun(jsFun.params, body);
-    _log('ExpressionCompiler: JS AST: $jsFunModified');
 
-    // 4. print JS ast to string for evaluation
+    // print JS ast to string for evaluation
 
     var context = js_ast.SimpleJavaScriptPrintingContext();
     var opts =
         js_ast.JavaScriptPrintingOptions(allowKeywordsInProperties: true);
 
     jsFunModified.accept(js_ast.Printer(opts, context));
+    _log('Performed JavaScript adjustments for expression');
 
     return context.getText();
   }
diff --git a/pkg/dev_compiler/lib/src/kernel/expression_compiler_worker.dart b/pkg/dev_compiler/lib/src/kernel/expression_compiler_worker.dart
index 9cb61dc..85aa859 100644
--- a/pkg/dev_compiler/lib/src/kernel/expression_compiler_worker.dart
+++ b/pkg/dev_compiler/lib/src/kernel/expression_compiler_worker.dart
@@ -103,10 +103,11 @@
   final _componentForModuleName = <String, Component>{};
   final _componentModuleNames = <Component, String>{};
   final ProcessedOptions _processedOptions;
+  final CompilerOptions _compilerOptions;
   final Component _sdkComponent;
 
-  ExpressionCompilerWorker._(this._processedOptions, this._sdkComponent,
-      this.requestStream, this.sendResponse);
+  ExpressionCompilerWorker._(this._processedOptions, this._compilerOptions,
+      this._sdkComponent, this.requestStream, this.sendResponse);
 
   static Future<ExpressionCompilerWorker> createFromArgs(
     List<String> args, {
@@ -172,7 +173,7 @@
     void Function(Map<String, dynamic>)
         sendResponse, // Defaults to write to stdout
   }) async {
-    var options = CompilerOptions()
+    var compilerOptions = CompilerOptions()
       ..compileSdk = false
       ..sdkRoot = sdkRoot
       ..sdkSummary = sdkSummary
@@ -192,15 +193,15 @@
         .cast<Map<String, dynamic>>();
     sendResponse ??= (Map<String, dynamic> response) =>
         stdout.writeln(json.encode(response));
-    var processedOpts = ProcessedOptions(options: options);
+    var processedOptions = ProcessedOptions(options: compilerOptions);
 
-    var sdkComponent = await CompilerContext(processedOpts)
+    var sdkComponent = await CompilerContext(processedOptions)
         .runInContext<Component>((CompilerContext c) async {
-      return processedOpts.loadSdkSummary(null);
+      return processedOptions.loadSdkSummary(null);
     });
 
-    return ExpressionCompilerWorker._(
-        processedOpts, sdkComponent, requestStream, sendResponse)
+    return ExpressionCompilerWorker._(processedOptions, compilerOptions,
+        sdkComponent, requestStream, sendResponse)
       .._update(sdkComponent, dartSdkModule);
   }
 
@@ -238,6 +239,8 @@
   /// Handles a `CompileExpression` request.
   Future<Map<String, dynamic>> _compileExpression(
       CompileExpressionRequest request) async {
+    _processedOptions.ticker.logMs('Compiling expression to JavaScript');
+
     var libraryUri = Uri.parse(request.libraryUri);
     if (libraryUri.scheme == 'dart') {
       // compiling expressions inside the SDK currently fails because
@@ -264,16 +267,18 @@
         uriToSource: originalComponent.uriToSource,
       );
     }
+    _processedOptions.ticker.logMs('Collected dependencies for expression');
 
     errors.clear();
     warnings.clear();
 
     var incrementalCompiler = IncrementalCompiler.forExpressionCompilationOnly(
-        CompilerContext(_processedOptions), component);
+        CompilerContext(_processedOptions), component, /*resetTicker*/ false);
 
     var finalComponent =
         await incrementalCompiler.computeDelta(entryPoints: [libraryUri]);
     finalComponent.computeCanonicalNames();
+    _processedOptions.ticker.logMs('Computed delta for expression');
 
     if (errors.isNotEmpty) {
       return {
@@ -294,13 +299,15 @@
       coreTypes: incrementalCompiler.getCoreTypes(),
     );
 
+    compiler.emitModule(finalComponent);
+    _processedOptions.ticker.logMs('Emitted module for expression');
+
     var expressionCompiler = ExpressionCompiler(
+      _compilerOptions,
+      errors,
       incrementalCompiler,
       compiler,
       finalComponent,
-      verbose: _processedOptions.verbose,
-      onDiagnostic: _onDiagnosticHandler(errors, warnings),
-      errors: errors,
     );
 
     var compiledProcedure = await expressionCompiler.compileExpressionToJs(
@@ -312,6 +319,8 @@
         request.moduleName,
         request.expression);
 
+    _processedOptions.ticker.logMs('Compiled expression to JavaScript');
+
     return {
       'errors': errors,
       'warnings': warnings,
@@ -347,6 +356,9 @@
 
   /// Loads in the specified dill files and invalidates any existing ones.
   Future<Map<String, dynamic>> _updateDeps(UpdateDepsRequest request) async {
+    _processedOptions.ticker
+        .logMs('Updating dependencies for expression evaluation');
+
     for (var input in request.inputs) {
       var file =
           _processedOptions.fileSystem.entityForUri(Uri.parse(input.path));
@@ -356,6 +368,9 @@
           alwaysCreateNewNamedNodes: true);
       _update(component, input.moduleName);
     }
+
+    _processedOptions.ticker
+        .logMs('Updated dependencies for expression evaluation');
     return {'succeeded': true};
   }
 
diff --git a/pkg/dev_compiler/lib/src/kernel/target.dart b/pkg/dev_compiler/lib/src/kernel/target.dart
index d2fc5e5..a005aae 100644
--- a/pkg/dev_compiler/lib/src/kernel/target.dart
+++ b/pkg/dev_compiler/lib/src/kernel/target.dart
@@ -35,6 +35,9 @@
   bool get supportsLateFields => false;
 
   @override
+  bool get supportsLateLoweringSentinel => false;
+
+  @override
   bool get useStaticFieldLowering => false;
 
   // TODO(johnniwinther,sigmund): Remove this when js-interop handles getter
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_test.dart
index 7374f49..4e4068e 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_test.dart
@@ -140,10 +140,13 @@
     kernel2jsCompiler.emitModule(component);
 
     // create expression compiler
-    var evaluator = ExpressionCompiler(compiler, kernel2jsCompiler, component,
-        verbose: setup.options.verbose,
-        onDiagnostic: setup.options.onDiagnostic,
-        errors: setup.errors);
+    var evaluator = ExpressionCompiler(
+      setup.options,
+      setup.errors,
+      compiler,
+      kernel2jsCompiler,
+      component,
+    );
 
     // collect all module names and paths
     var moduleInfo = _collectModules(component);
diff --git a/pkg/front_end/lib/src/api_prototype/experimental_flags_generated.dart b/pkg/front_end/lib/src/api_prototype/experimental_flags_generated.dart
index 80a1d09..ba34ca2 100644
--- a/pkg/front_end/lib/src/api_prototype/experimental_flags_generated.dart
+++ b/pkg/front_end/lib/src/api_prototype/experimental_flags_generated.dart
@@ -24,17 +24,17 @@
 }
 
 const Version enableAlternativeInvalidationStrategyVersion =
-    const Version(2, 10);
+    const Version(2, 11);
 const Version enableConstantUpdate2018Version = const Version(2, 0);
 const Version enableControlFlowCollectionsVersion = const Version(2, 0);
 const Version enableExtensionMethodsVersion = const Version(2, 6);
-const Version enableNonNullableVersion = const Version(2, 10);
-const Version enableNonfunctionTypeAliasesVersion = const Version(2, 10);
+const Version enableNonNullableVersion = const Version(2, 11);
+const Version enableNonfunctionTypeAliasesVersion = const Version(2, 11);
 const Version enableSetLiteralsVersion = const Version(2, 0);
 const Version enableSpreadCollectionsVersion = const Version(2, 0);
-const Version enableTripleShiftVersion = const Version(2, 10);
-const Version enableValueClassVersion = const Version(2, 10);
-const Version enableVarianceVersion = const Version(2, 10);
+const Version enableTripleShiftVersion = const Version(2, 11);
+const Version enableValueClassVersion = const Version(2, 11);
+const Version enableVarianceVersion = const Version(2, 11);
 
 ExperimentalFlag parseExperimentalFlag(String flag) {
   switch (flag) {
@@ -93,31 +93,31 @@
 };
 
 const Map<ExperimentalFlag, Version> experimentEnabledVersion = {
-  ExperimentalFlag.alternativeInvalidationStrategy: const Version(2, 10),
+  ExperimentalFlag.alternativeInvalidationStrategy: const Version(2, 11),
   ExperimentalFlag.constantUpdate2018: const Version(2, 0),
   ExperimentalFlag.controlFlowCollections: const Version(2, 0),
   ExperimentalFlag.extensionMethods: const Version(2, 6),
-  ExperimentalFlag.nonNullable: const Version(2, 10),
-  ExperimentalFlag.nonfunctionTypeAliases: const Version(2, 10),
+  ExperimentalFlag.nonNullable: const Version(2, 11),
+  ExperimentalFlag.nonfunctionTypeAliases: const Version(2, 11),
   ExperimentalFlag.setLiterals: const Version(2, 0),
   ExperimentalFlag.spreadCollections: const Version(2, 0),
-  ExperimentalFlag.tripleShift: const Version(2, 10),
-  ExperimentalFlag.valueClass: const Version(2, 10),
-  ExperimentalFlag.variance: const Version(2, 10),
+  ExperimentalFlag.tripleShift: const Version(2, 11),
+  ExperimentalFlag.valueClass: const Version(2, 11),
+  ExperimentalFlag.variance: const Version(2, 11),
 };
 
 const Map<ExperimentalFlag, Version> experimentReleasedVersion = {
-  ExperimentalFlag.alternativeInvalidationStrategy: const Version(2, 10),
+  ExperimentalFlag.alternativeInvalidationStrategy: const Version(2, 11),
   ExperimentalFlag.constantUpdate2018: const Version(2, 0),
   ExperimentalFlag.controlFlowCollections: const Version(2, 0),
   ExperimentalFlag.extensionMethods: const Version(2, 6),
   ExperimentalFlag.nonNullable: const Version(2, 10),
-  ExperimentalFlag.nonfunctionTypeAliases: const Version(2, 10),
+  ExperimentalFlag.nonfunctionTypeAliases: const Version(2, 11),
   ExperimentalFlag.setLiterals: const Version(2, 0),
   ExperimentalFlag.spreadCollections: const Version(2, 0),
-  ExperimentalFlag.tripleShift: const Version(2, 10),
-  ExperimentalFlag.valueClass: const Version(2, 10),
-  ExperimentalFlag.variance: const Version(2, 10),
+  ExperimentalFlag.tripleShift: const Version(2, 11),
+  ExperimentalFlag.valueClass: const Version(2, 11),
+  ExperimentalFlag.variance: const Version(2, 11),
 };
 
 const AllowedExperimentalFlags defaultAllowedExperimentalFlags =
@@ -184,6 +184,9 @@
   "meta": {
     ExperimentalFlag.nonNullable,
   },
+  "native_stack_traces": {
+    ExperimentalFlag.nonNullable,
+  },
   "path": {
     ExperimentalFlag.nonNullable,
   },
diff --git a/pkg/front_end/lib/src/base/command_line_options.dart b/pkg/front_end/lib/src/base/command_line_options.dart
index f288ff5..776fc11 100644
--- a/pkg/front_end/lib/src/base/command_line_options.dart
+++ b/pkg/front_end/lib/src/base/command_line_options.dart
@@ -9,6 +9,8 @@
   static const String nnbdWeakMode = "--nnbd-weak";
 
   static const String forceLateLowering = "--force-late-lowering";
+  static const String forceLateLoweringSentinel =
+      "--force-late-lowering-sentinel";
   static const String forceStaticFieldLowering =
       "--force-static-field-lowering";
   static const String forceNoExplicitGetterCalls =
diff --git a/pkg/front_end/lib/src/fasta/builder/field_builder.dart b/pkg/front_end/lib/src/fasta/builder/field_builder.dart
index 928ef74..f3bf41e 100644
--- a/pkg/front_end/lib/src/fasta/builder/field_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/field_builder.dart
@@ -10,8 +10,6 @@
 import 'package:kernel/core_types.dart';
 import 'package:kernel/src/legacy_erasure.dart';
 
-import '../../base/nnbd_mode.dart';
-
 import '../constant_context.dart' show ConstantContext;
 
 import '../fasta_codes.dart' show messageInternalProblemAlreadyInitialized;
@@ -126,7 +124,8 @@
     Uri fileUri = libraryBuilder?.fileUri;
     // If in mixed mode, late lowerings cannot use `null` as a sentinel on
     // non-nullable fields since they can be assigned from legacy code.
-    bool forceUseIsSetField = libraryBuilder.loader.nnbdMode != NnbdMode.Strong;
+    late_lowering.IsSetStrategy isSetStrategy =
+        late_lowering.computeIsSetStrategy(libraryBuilder);
     if (isAbstract || isExternal) {
       _fieldEncoding = new AbstractOrExternalFieldEncoding(fileUri, charOffset,
           charEndOffset, getterReferenceFrom, setterReferenceFrom,
@@ -149,7 +148,7 @@
               getterReferenceFrom,
               setterReferenceFrom,
               isCovariant,
-              forceUseIsSetField);
+              isSetStrategy);
         } else {
           _fieldEncoding = new LateFieldWithInitializerEncoding(
               name,
@@ -161,7 +160,7 @@
               getterReferenceFrom,
               setterReferenceFrom,
               isCovariant,
-              forceUseIsSetField);
+              isSetStrategy);
         }
       } else {
         if (isFinal) {
@@ -175,7 +174,7 @@
               getterReferenceFrom,
               setterReferenceFrom,
               isCovariant,
-              forceUseIsSetField);
+              isSetStrategy);
         } else {
           _fieldEncoding = new LateFieldWithoutInitializerEncoding(
               name,
@@ -187,7 +186,7 @@
               getterReferenceFrom,
               setterReferenceFrom,
               isCovariant,
-              forceUseIsSetField);
+              isSetStrategy);
         }
       }
     } else if (libraryBuilder.isNonNullableByDefault &&
@@ -206,7 +205,7 @@
             getterReferenceFrom,
             setterReferenceFrom,
             isCovariant,
-            forceUseIsSetField);
+            isSetStrategy);
       } else {
         _fieldEncoding = new LateFieldWithInitializerEncoding(
             name,
@@ -218,7 +217,7 @@
             getterReferenceFrom,
             setterReferenceFrom,
             isCovariant,
-            forceUseIsSetField);
+            isSetStrategy);
       }
     } else {
       assert(lateIsSetReferenceFrom == null);
@@ -730,7 +729,8 @@
   //
   // This is used to force use isSet fields in mixed mode encoding since
   // we cannot trust non-nullable fields to be initialized with non-null values.
-  bool _forceUseIsSetField;
+  late_lowering.IsSetStrategy _isSetStrategy;
+  late_lowering.IsSetEncoding _isSetEncoding;
 
   // If `true`, the is-set field was register before the type was known to be
   // nullable or non-nullable. In this case we do not try to remove it from
@@ -751,22 +751,31 @@
       Procedure getterReferenceFrom,
       Procedure setterReferenceFrom,
       bool isCovariant,
-      bool forceUseIsSetField)
+      late_lowering.IsSetStrategy isSetStrategy)
       : fileOffset = charOffset,
-        _forceUseIsSetField = forceUseIsSetField,
-        _forceIncludeIsSetField = forceUseIsSetField {
+        _isSetStrategy = isSetStrategy,
+        _forceIncludeIsSetField =
+            isSetStrategy == late_lowering.IsSetStrategy.forceUseIsSetField {
     _field =
         new Field(null, fileUri: fileUri, reference: referenceFrom?.reference)
           ..fileOffset = charOffset
           ..fileEndOffset = charEndOffset
           ..isNonNullableByDefault = true
           ..isInternalImplementation = true;
-    _lateIsSetField = new Field(null,
-        fileUri: fileUri, reference: lateIsSetReferenceFrom?.reference)
-      ..fileOffset = charOffset
-      ..fileEndOffset = charEndOffset
-      ..isNonNullableByDefault = true
-      ..isInternalImplementation = true;
+    switch (_isSetStrategy) {
+      case late_lowering.IsSetStrategy.useSentinelOrNull:
+        // [_lateIsSetField] is never needed.
+        break;
+      case late_lowering.IsSetStrategy.forceUseIsSetField:
+      case late_lowering.IsSetStrategy.useIsSetFieldOrNull:
+        _lateIsSetField = new Field(null,
+            fileUri: fileUri, reference: lateIsSetReferenceFrom?.reference)
+          ..fileOffset = charOffset
+          ..fileEndOffset = charEndOffset
+          ..isNonNullableByDefault = true
+          ..isInternalImplementation = true;
+        break;
+    }
     _lateGetter = new Procedure(
         null, ProcedureKind.Getter, new FunctionNode(null),
         fileUri: fileUri, reference: getterReferenceFrom?.reference)
@@ -776,6 +785,12 @@
         isCovariant: isCovariant);
   }
 
+  late_lowering.IsSetEncoding get isSetEncoding {
+    assert(_type != null, "Type has not been computed for field $name.");
+    return _isSetEncoding ??=
+        late_lowering.computeIsSetEncoding(_type, _isSetStrategy);
+  }
+
   @override
   void completeSignature(CoreTypes coreTypes) {
     if (_lateIsSetField != null) {
@@ -786,7 +801,15 @@
   @override
   void createBodies(CoreTypes coreTypes, Expression initializer) {
     assert(_type != null, "Type has not been computed for field $name.");
-    _field.initializer = new NullLiteral()..parent = _field;
+    if (isSetEncoding == late_lowering.IsSetEncoding.useSentinel) {
+      _field.initializer = new StaticInvocation(coreTypes.createSentinelMethod,
+          new Arguments([], types: [_type])..fileOffset = fileOffset)
+        ..parent = _field;
+    } else {
+      _field.initializer = new NullLiteral()
+        ..fileOffset = fileOffset
+        ..parent = _field;
+    }
     if (_lateIsSetField != null) {
       _lateIsSetField.initializer = new BoolLiteral(false)
         ..fileOffset = fileOffset
@@ -1073,7 +1096,7 @@
             _createFieldSet(_field, value),
         createIsSetWrite: (Expression value) =>
             _createFieldSet(_lateIsSetField, value),
-        useIsSetField: _forceUseIsSetField || type.isPotentiallyNullable);
+        isSetEncoding: isSetEncoding);
   }
 }
 
@@ -1086,7 +1109,7 @@
         coreTypes, fileOffset, name, type, 'Field',
         createVariableRead: _createFieldRead,
         createIsSetRead: () => _createFieldGet(_lateIsSetField),
-        useIsSetField: _forceUseIsSetField || type.isPotentiallyNullable);
+        isSetEncoding: isSetEncoding);
   }
 }
 
@@ -1102,7 +1125,7 @@
       Procedure getterReferenceFrom,
       Procedure setterReferenceFrom,
       bool isCovariant,
-      bool forceUseIsSetField)
+      late_lowering.IsSetStrategy isSetStrategy)
       : super(
             name,
             fileUri,
@@ -1113,7 +1136,7 @@
             getterReferenceFrom,
             setterReferenceFrom,
             isCovariant,
-            forceUseIsSetField);
+            isSetStrategy);
 }
 
 class LateFieldWithInitializerEncoding extends AbstractLateFieldEncoding
@@ -1128,7 +1151,7 @@
       Procedure getterReferenceFrom,
       Procedure setterReferenceFrom,
       bool isCovariant,
-      bool forceUseIsSetField)
+      late_lowering.IsSetStrategy isSetStrategy)
       : super(
             name,
             fileUri,
@@ -1139,7 +1162,7 @@
             getterReferenceFrom,
             setterReferenceFrom,
             isCovariant,
-            forceUseIsSetField);
+            isSetStrategy);
 
   @override
   Statement _createGetterBody(
@@ -1153,7 +1176,7 @@
         createIsSetRead: () => _createFieldGet(_lateIsSetField),
         createIsSetWrite: (Expression value) =>
             _createFieldSet(_lateIsSetField, value),
-        useIsSetField: _forceUseIsSetField || type.isPotentiallyNullable);
+        isSetEncoding: isSetEncoding);
   }
 }
 
@@ -1169,7 +1192,7 @@
       Procedure getterReferenceFrom,
       Procedure setterReferenceFrom,
       bool isCovariant,
-      bool forceUseIsSetField)
+      late_lowering.IsSetStrategy isSetStrategy)
       : super(
             name,
             fileUri,
@@ -1180,7 +1203,7 @@
             getterReferenceFrom,
             setterReferenceFrom,
             isCovariant,
-            forceUseIsSetField);
+            isSetStrategy);
 
   @override
   Statement _createSetterBody(
@@ -1195,7 +1218,7 @@
         createIsSetRead: () => _createFieldGet(_lateIsSetField),
         createIsSetWrite: (Expression value) =>
             _createFieldSet(_lateIsSetField, value),
-        useIsSetField: _forceUseIsSetField || type.isPotentiallyNullable);
+        isSetEncoding: isSetEncoding);
   }
 }
 
@@ -1210,7 +1233,7 @@
       Procedure getterReferenceFrom,
       Procedure setterReferenceFrom,
       bool isCovariant,
-      bool forceUseIsSetField)
+      late_lowering.IsSetStrategy isSetStrategy)
       : super(
             name,
             fileUri,
@@ -1221,7 +1244,7 @@
             getterReferenceFrom,
             setterReferenceFrom,
             isCovariant,
-            forceUseIsSetField);
+            isSetStrategy);
   @override
   Statement _createGetterBody(
       CoreTypes coreTypes, String name, Expression initializer) {
@@ -1233,7 +1256,8 @@
             _createFieldSet(_field, value),
         createIsSetRead: () => _createFieldGet(_lateIsSetField),
         createIsSetWrite: (Expression value) =>
-            _createFieldSet(_lateIsSetField, value));
+            _createFieldSet(_lateIsSetField, value),
+        isSetEncoding: isSetEncoding);
   }
 
   @override
@@ -1420,8 +1444,9 @@
       ..fileEndOffset = charEndOffset
       ..isNonNullableByDefault = isNonNullableByDefault;
     if (!isFinal) {
-      VariableDeclaration parameter = new VariableDeclaration(null)
-        ..isCovariant = isCovariant;
+      VariableDeclaration parameter =
+          new VariableDeclaration("#externalFieldValue")
+            ..isCovariant = isCovariant;
       _setter = new Procedure(
           null,
           ProcedureKind.Setter,
diff --git a/pkg/front_end/lib/src/fasta/incremental_compiler.dart b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
index 2c22a93..c1dd176 100644
--- a/pkg/front_end/lib/src/fasta/incremental_compiler.dart
+++ b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
@@ -125,7 +125,7 @@
   final CompilerContext context;
 
   final Ticker ticker;
-
+  final bool resetTicker;
   final bool outlineOnly;
   bool trackNeededDillLibraries = false;
   Set<Library> neededDillLibraries;
@@ -160,6 +160,7 @@
       this.context, this.componentToInitializeFrom,
       [bool outlineOnly, this.incrementalSerializer])
       : ticker = context.options.ticker,
+        resetTicker = true,
         initializeFromDillUri = null,
         this.outlineOnly = outlineOnly ?? false,
         this.initializedForExpressionCompilationOnly = false {
@@ -171,6 +172,7 @@
       bool outlineOnly,
       this.incrementalSerializer])
       : ticker = context.options.ticker,
+        resetTicker = true,
         componentToInitializeFrom = null,
         this.outlineOnly = outlineOnly ?? false,
         this.initializedForExpressionCompilationOnly = false {
@@ -178,8 +180,10 @@
   }
 
   IncrementalCompiler.forExpressionCompilationOnly(
-      this.context, this.componentToInitializeFrom)
+      this.context, this.componentToInitializeFrom,
+      [bool resetTicker])
       : ticker = context.options.ticker,
+        this.resetTicker = resetTicker ?? true,
         initializeFromDillUri = null,
         this.outlineOnly = false,
         this.incrementalSerializer = null,
@@ -201,7 +205,9 @@
   @override
   Future<Component> computeDelta(
       {List<Uri> entryPoints, bool fullComponent: false}) async {
-    ticker.reset();
+    if (resetTicker) {
+      ticker.reset();
+    }
     entryPoints ??= context.options.inputs;
     return context.runInContext<Component>((CompilerContext c) async {
       if (computeDeltaRunOnce && initializedForExpressionCompilationOnly) {
@@ -1570,6 +1576,7 @@
     return await context.runInContext((_) async {
       LibraryBuilder libraryBuilder =
           userCode.loader.read(libraryUri, -1, accessor: userCode.loader.first);
+      ticker.logMs("Loaded library $libraryUri");
 
       Class cls;
       if (className != null) {
@@ -1597,6 +1604,7 @@
         nameOrigin: libraryBuilder.library,
       );
       debugLibrary.setLanguageVersion(libraryBuilder.library.languageVersion);
+      ticker.logMs("Created debug library");
 
       if (libraryBuilder is DillLibraryBuilder) {
         for (LibraryDependency dependency
@@ -1629,6 +1637,7 @@
         }
 
         debugLibrary.addImportsToScope();
+        ticker.logMs("Added imports");
       }
 
       HybridFileSystem hfs = userCode.fileSystem;
@@ -1662,6 +1671,7 @@
       // Make sure the library has a canonical name.
       Component c = new Component(libraries: [debugLibrary.library]);
       c.computeCanonicalNames();
+      ticker.logMs("Built debug library");
 
       userCode.runProcedureTransformations(procedure);
 
diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
index 713947d..7cc2d4d 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -2419,7 +2419,9 @@
                   .withArguments(token.lexeme),
               token.charOffset,
               token.length);
-        } else if (isFinal && !isLate) {
+        } else if (!libraryBuilder.isNonNullableByDefault &&
+            isFinal &&
+            !isLate) {
           initializer = buildProblem(
               fasta.templateFinalFieldWithoutInitializer
                   .withArguments(token.lexeme),
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 31d4186..b053283 100644
--- a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
@@ -15,7 +15,6 @@
         InstrumentationValueForMember,
         InstrumentationValueForType,
         InstrumentationValueForTypeArgs;
-import '../../base/nnbd_mode.dart';
 import '../fasta_codes.dart';
 import '../names.dart';
 import '../problems.dart' show unhandled;
@@ -5629,6 +5628,7 @@
         node.isImplicitlyTyped ? const UnknownType() : node.type;
     DartType inferredType;
     ExpressionInferenceResult initializerResult;
+    inferrer.flowAnalysis.declare(node, node.initializer != null);
     if (node.initializer != null) {
       initializerResult = inferrer.inferExpression(node.initializer,
           declaredType, !inferrer.isTopLevel || node.isImplicitlyTyped,
@@ -5648,12 +5648,15 @@
       node.type = inferredType;
     }
     if (initializerResult != null) {
+      DartType initializerType = initializerResult.inferredType;
+      if (node.isImplicitlyTyped && initializerType is TypeParameterType) {
+        inferrer.flowAnalysis.promote(node, initializerType);
+      }
       Expression initializer = inferrer.ensureAssignableResult(
           node.type, initializerResult,
           fileOffset: node.fileOffset, isVoidAllowed: node.type is VoidType);
       node.initializer = initializer..parent = node;
     }
-    inferrer.flowAnalysis.declare(node, node.initializer != null);
     if (!inferrer.isTopLevel) {
       SourceLibraryBuilder library = inferrer.library;
       if (node.isImplicitlyTyped) {
@@ -5669,12 +5672,11 @@
       List<Statement> result = <Statement>[];
       result.add(node);
 
+      late_lowering.IsSetEncoding isSetEncoding =
+          late_lowering.computeIsSetEncoding(
+              node.type, late_lowering.computeIsSetStrategy(inferrer.library));
       VariableDeclaration isSetVariable;
-      if (node.type.isPotentiallyNullable ||
-          // We cannot trust that non-nullable locals are not initialized to
-          // `null` in mixed mode, so we use an `isSet` variable here.
-          (inferrer.isNonNullableByDefault &&
-              inferrer.nnbdMode != NnbdMode.Strong)) {
+      if (isSetEncoding == late_lowering.IsSetEncoding.useIsSetField) {
         isSetVariable = new VariableDeclaration(
             '${late_lowering.lateLocalPrefix}'
             '${node.name}'
@@ -5717,7 +5719,7 @@
                       'Local',
                       createVariableRead: createVariableRead,
                       createIsSetRead: createIsSetRead,
-                      useIsSetField: isSetVariable != null)
+                      isSetEncoding: isSetEncoding)
                   : late_lowering.createGetterWithInitializer(
                       inferrer.coreTypes,
                       fileOffset,
@@ -5728,7 +5730,7 @@
                       createVariableWrite: createVariableWrite,
                       createIsSetRead: createIsSetRead,
                       createIsSetWrite: createIsSetWrite,
-                      useIsSetField: isSetVariable != null),
+                      isSetEncoding: isSetEncoding),
               returnType: node.type))
         ..fileOffset = fileOffset;
       getVariable.type =
@@ -5763,13 +5765,13 @@
                             createVariableWrite: createVariableWrite,
                             createIsSetRead: createIsSetRead,
                             createIsSetWrite: createIsSetWrite,
-                            useIsSetField: isSetVariable != null)
+                            isSetEncoding: isSetEncoding)
                         : late_lowering.createSetterBody(inferrer.coreTypes,
                             fileOffset, node.name, setterParameter, node.type,
                             shouldReturnValue: true,
                             createVariableWrite: createVariableWrite,
                             createIsSetWrite: createIsSetWrite,
-                            useIsSetField: isSetVariable != null)
+                            isSetEncoding: isSetEncoding)
                       ..fileOffset = fileOffset,
                     positionalParameters: <VariableDeclaration>[
                       setterParameter
@@ -5784,8 +5786,15 @@
       }
       node.isLate = false;
       node.lateType = node.type;
+      if (isSetEncoding == late_lowering.IsSetEncoding.useSentinel) {
+        node.initializer = new StaticInvocation(
+            inferrer.coreTypes.createSentinelMethod,
+            new Arguments([], types: [node.type])..fileOffset = fileOffset)
+          ..parent = node;
+      } else {
+        node.initializer = null;
+      }
       node.type = inferrer.computeNullable(node.type);
-      node.initializer = null;
 
       return new StatementInferenceResult.multiple(node.fileOffset, result);
     }
@@ -5865,16 +5874,26 @@
                       node.variable.name.length));
             }
           } else {
-            if (isUnassigned &&
-                declaredOrInferredType.isPotentiallyNonNullable) {
-              return new ExpressionInferenceResult(
-                  resultType,
-                  inferrer.helper.wrapInProblem(
-                      resultExpression,
-                      templateNonNullableNotAssignedError
-                          .withArguments(node.variable.name),
-                      node.fileOffset,
-                      node.variable.name.length));
+            if (isUnassigned) {
+              if (variable.isFinal) {
+                return new ExpressionInferenceResult(
+                    resultType,
+                    inferrer.helper.wrapInProblem(
+                        resultExpression,
+                        templateFinalNotAssignedError
+                            .withArguments(node.variable.name),
+                        node.fileOffset,
+                        node.variable.name.length));
+              } else if (declaredOrInferredType.isPotentiallyNonNullable) {
+                return new ExpressionInferenceResult(
+                    resultType,
+                    inferrer.helper.wrapInProblem(
+                        resultExpression,
+                        templateNonNullableNotAssignedError
+                            .withArguments(node.variable.name),
+                        node.fileOffset,
+                        node.variable.name.length));
+              }
             }
           }
         }
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
index ab208ce..53d5493 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
@@ -963,9 +963,12 @@
     for (FieldBuilder fieldBuilder in uninitializedFields) {
       if (initializedFields == null ||
           !initializedFields.contains(fieldBuilder)) {
+        bool uninitializedFinalOrNonNullableFieldIsError =
+            cls.enclosingLibrary.isNonNullableByDefault ||
+                (cls.constructors.isNotEmpty || cls.isMixinDeclaration);
         if (!fieldBuilder.isLate) {
           if (fieldBuilder.isFinal &&
-              (cls.constructors.isNotEmpty || cls.isMixinDeclaration)) {
+              uninitializedFinalOrNonNullableFieldIsError) {
             String uri = '${fieldBuilder.library.importUri}';
             String file = fieldBuilder.fileUri.pathSegments.last;
             if (uri == 'dart:html' ||
@@ -984,7 +987,7 @@
             }
           } else if (fieldBuilder.fieldType is! InvalidType &&
               fieldBuilder.fieldType.isPotentiallyNonNullable &&
-              (cls.constructors.isNotEmpty || cls.isMixinDeclaration)) {
+              uninitializedFinalOrNonNullableFieldIsError) {
             SourceLibraryBuilder library = builder.library;
             if (library.isNonNullableByDefault) {
               library.addProblem(
@@ -1035,9 +1038,15 @@
                   templateFieldNonNullableNotInitializedByConstructorError
                       .withArguments(fieldBuilder.name, fieldBuilder.field.type,
                           library.isNonNullableByDefault),
-                  fieldBuilder.charOffset,
-                  fieldBuilder.name.length,
-                  fieldBuilder.fileUri);
+                  constructorBuilder.charOffset,
+                  noLength,
+                  constructorBuilder.fileUri,
+                  context: [
+                    templateMissingImplementationCause
+                        .withArguments(fieldBuilder.name)
+                        .withLocation(fieldBuilder.fileUri,
+                            fieldBuilder.charOffset, fieldBuilder.name.length)
+                  ]);
             }
           }
         }
diff --git a/pkg/front_end/lib/src/fasta/kernel/late_lowering.dart b/pkg/front_end/lib/src/fasta/kernel/late_lowering.dart
index 6fc6f43..3458ee9 100644
--- a/pkg/front_end/lib/src/fasta/kernel/late_lowering.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/late_lowering.dart
@@ -5,6 +5,8 @@
 import 'package:kernel/ast.dart' hide MapEntry;
 import 'package:kernel/core_types.dart';
 
+import '../../base/nnbd_mode.dart';
+import '../source/source_library_builder.dart';
 import '../names.dart';
 
 const String lateFieldPrefix = '_#';
@@ -27,66 +29,94 @@
     Expression createVariableWrite(Expression value),
     Expression createIsSetRead(),
     Expression createIsSetWrite(Expression value),
-    bool useIsSetField}) {
-  assert(useIsSetField != null);
-  if (useIsSetField) {
-    // Generate:
-    //
-    //    if (!_#isSet#field) {
-    //      _#field = <init>;
-    //      _#isSet#field = true
-    //    }
-    //    return _#field;
-    return new Block(<Statement>[
-      new IfStatement(
-          new Not(createIsSetRead()..fileOffset = fileOffset)
-            ..fileOffset = fileOffset,
-          new Block(<Statement>[
-            new ExpressionStatement(
-                createVariableWrite(initializer)..fileOffset = fileOffset)
+    IsSetEncoding isSetEncoding}) {
+  assert(isSetEncoding != null);
+  switch (isSetEncoding) {
+    case IsSetEncoding.useIsSetField:
+      // Generate:
+      //
+      //    if (!_#isSet#field) {
+      //      _#field = <init>;
+      //      _#isSet#field = true
+      //    }
+      //    return _#field;
+      return new Block(<Statement>[
+        new IfStatement(
+            new Not(createIsSetRead()..fileOffset = fileOffset)
               ..fileOffset = fileOffset,
-            new ExpressionStatement(
-                createIsSetWrite(new BoolLiteral(true)..fileOffset = fileOffset)
-                  ..fileOffset = fileOffset)
-              ..fileOffset = fileOffset,
-          ]),
-          null)
-        ..fileOffset = fileOffset,
-      new ReturnStatement(
-          // If [type] is a type variable with undetermined nullability we need
-          // to create a read of the field that is promoted to the type variable
-          // type.
-          createVariableRead(needsPromotion: type.isPotentiallyNonNullable))
-        ..fileOffset = fileOffset
-    ])
-      ..fileOffset = fileOffset;
-  } else {
-    // Generate:
-    //
-    //    return let # = _#field in # == null ? _#field = <init> : #;
-    VariableDeclaration variable = new VariableDeclaration.forValue(
-        createVariableRead(needsPromotion: false)..fileOffset = fileOffset,
-        type: type.withDeclaredNullability(Nullability.nullable))
-      ..fileOffset = fileOffset;
-    return new ReturnStatement(
-        new Let(
-            variable,
-            new ConditionalExpression(
-                new MethodInvocation(
-                    new VariableGet(variable)..fileOffset = fileOffset,
-                    equalsName,
-                    new Arguments(<Expression>[
-                      new NullLiteral()..fileOffset = fileOffset
-                    ])
-                      ..fileOffset = fileOffset)
-                  ..fileOffset = fileOffset,
-                createVariableWrite(initializer)..fileOffset = fileOffset,
-                new VariableGet(variable, type)..fileOffset = fileOffset,
-                type)
-              ..fileOffset = fileOffset)
-          ..fileOffset = fileOffset)
-      ..fileOffset = fileOffset;
+            new Block(<Statement>[
+              new ExpressionStatement(
+                  createVariableWrite(initializer)..fileOffset = fileOffset)
+                ..fileOffset = fileOffset,
+              new ExpressionStatement(
+                  createIsSetWrite(
+                      new BoolLiteral(true)..fileOffset = fileOffset)
+                    ..fileOffset = fileOffset)
+                ..fileOffset = fileOffset,
+            ]),
+            null)
+          ..fileOffset = fileOffset,
+        new ReturnStatement(
+            // If [type] is a type variable with undetermined nullability we
+            // need to create a read of the field that is promoted to the type
+            // variable type.
+            createVariableRead(needsPromotion: type.isPotentiallyNonNullable))
+          ..fileOffset = fileOffset
+      ])
+        ..fileOffset = fileOffset;
+    case IsSetEncoding.useSentinel:
+      // Generate:
+      //
+      //    return let # = _#field in isSentinel(#) ? _#field = <init> : #;
+      VariableDeclaration variable = new VariableDeclaration.forValue(
+          createVariableRead(needsPromotion: false)..fileOffset = fileOffset,
+          type: type.withDeclaredNullability(Nullability.nullable))
+        ..fileOffset = fileOffset;
+      return new ReturnStatement(
+          new Let(
+              variable,
+              new ConditionalExpression(
+                  new StaticInvocation(
+                      coreTypes.isSentinelMethod,
+                      new Arguments(<Expression>[
+                        new VariableGet(variable)..fileOffset = fileOffset
+                      ])
+                        ..fileOffset = fileOffset)
+                    ..fileOffset = fileOffset,
+                  createVariableWrite(initializer)..fileOffset = fileOffset,
+                  new VariableGet(variable, type)..fileOffset = fileOffset,
+                  type)
+                ..fileOffset = fileOffset)
+            ..fileOffset = fileOffset)
+        ..fileOffset = fileOffset;
+    case IsSetEncoding.useNull:
+      // Generate:
+      //
+      //    return let # = _#field in # == null ? _#field = <init> : #;
+      VariableDeclaration variable = new VariableDeclaration.forValue(
+          createVariableRead(needsPromotion: false)..fileOffset = fileOffset,
+          type: type.withDeclaredNullability(Nullability.nullable))
+        ..fileOffset = fileOffset;
+      return new ReturnStatement(
+          new Let(
+              variable,
+              new ConditionalExpression(
+                  new MethodInvocation(
+                      new VariableGet(variable)..fileOffset = fileOffset,
+                      equalsName,
+                      new Arguments(<Expression>[
+                        new NullLiteral()..fileOffset = fileOffset
+                      ])
+                        ..fileOffset = fileOffset)
+                    ..fileOffset = fileOffset,
+                  createVariableWrite(initializer)..fileOffset = fileOffset,
+                  new VariableGet(variable, type)..fileOffset = fileOffset,
+                  type)
+                ..fileOffset = fileOffset)
+            ..fileOffset = fileOffset)
+        ..fileOffset = fileOffset;
   }
+  throw new UnsupportedError("Unexpected IsSetEncoding $isSetEncoding");
 }
 
 /// Creates the body for the synthesized getter used to encode the lowering
@@ -106,7 +136,8 @@
     {Expression createVariableRead({bool needsPromotion}),
     Expression createVariableWrite(Expression value),
     Expression createIsSetRead(),
-    Expression createIsSetWrite(Expression value)}) {
+    Expression createIsSetWrite(Expression value),
+    IsSetEncoding isSetEncoding}) {
   Expression exception = new Throw(new ConstructorInvocation(
       coreTypes.lateInitializationErrorConstructor,
       new Arguments(<Expression>[
@@ -121,93 +152,141 @@
   VariableDeclaration temp =
       new VariableDeclaration.forValue(initializer, type: type)
         ..fileOffset = fileOffset;
-  if (type.isPotentiallyNullable) {
-    // Generate:
-    //
-    //    if (!_#isSet#field) {
-    //      var temp = <init>;
-    //      if (_#isSet#field) throw '...'
-    //      _#field = temp;
-    //      _#isSet#field = true
-    //    }
-    //    return _#field;
-    return new Block(<Statement>[
-      new IfStatement(
-          new Not(createIsSetRead()..fileOffset = fileOffset)
-            ..fileOffset = fileOffset,
-          new Block(<Statement>[
-            temp,
-            new IfStatement(
-                createIsSetRead()..fileOffset = fileOffset,
-                new ExpressionStatement(exception)..fileOffset = fileOffset,
-                null)
+  switch (isSetEncoding) {
+    case IsSetEncoding.useIsSetField:
+      // Generate:
+      //
+      //    if (!_#isSet#field) {
+      //      var temp = <init>;
+      //      if (_#isSet#field) throw '...'
+      //      _#field = temp;
+      //      _#isSet#field = true
+      //    }
+      //    return _#field;
+      return new Block(<Statement>[
+        new IfStatement(
+            new Not(createIsSetRead()..fileOffset = fileOffset)
               ..fileOffset = fileOffset,
-            new ExpressionStatement(
-                createVariableWrite(
-                    new VariableGet(temp)..fileOffset = fileOffset)
-                  ..fileOffset = fileOffset)
-              ..fileOffset = fileOffset,
-            new ExpressionStatement(
-                createIsSetWrite(new BoolLiteral(true)..fileOffset = fileOffset)
-                  ..fileOffset = fileOffset)
-              ..fileOffset = fileOffset,
-          ]),
-          null)
-        ..fileOffset = fileOffset,
-      new ReturnStatement(
-          // If [type] is a type variable with undetermined nullability we need
-          // to create a read of the field that is promoted to the type variable
-          // type.
-          createVariableRead(needsPromotion: type.isPotentiallyNonNullable))
-        ..fileOffset = fileOffset
-    ])
-      ..fileOffset = fileOffset;
-  } else {
-    // Generate:
-    //
-    //    return let #1 = _#field in #1 == null
-    //        ? let #2 = <init> in _#field == null ? _#field = #2 : throw '...'
-    //        : #1;
-    VariableDeclaration variable = new VariableDeclaration.forValue(
-        createVariableRead(needsPromotion: false)..fileOffset = fileOffset,
-        type: type.withDeclaredNullability(Nullability.nullable))
-      ..fileOffset = fileOffset;
-    return new ReturnStatement(
-        new Let(
-            variable,
-            new ConditionalExpression(
-                new MethodInvocation(
-                    new VariableGet(variable)..fileOffset = fileOffset,
-                    equalsName,
-                    new Arguments(<Expression>[
-                      new NullLiteral()..fileOffset = fileOffset
-                    ])
-                      ..fileOffset = fileOffset)
-                  ..fileOffset = fileOffset,
-                new Let(
-                    temp,
-                    new ConditionalExpression(
-                        new MethodInvocation(
-                            createVariableRead(needsPromotion: false)
-                              ..fileOffset = fileOffset,
-                            equalsName,
-                            new Arguments(<Expression>[
-                              new NullLiteral()..fileOffset = fileOffset
-                            ])
-                              ..fileOffset = fileOffset)
-                          ..fileOffset = fileOffset,
-                        createVariableWrite(
-                            new VariableGet(temp)..fileOffset = fileOffset)
-                          ..fileOffset = fileOffset,
-                        exception,
-                        type)
-                      ..fileOffset = fileOffset),
-                new VariableGet(variable, type)..fileOffset = fileOffset,
-                type)
-              ..fileOffset = fileOffset)
-          ..fileOffset = fileOffset)
-      ..fileOffset = fileOffset;
+            new Block(<Statement>[
+              temp,
+              new IfStatement(
+                  createIsSetRead()..fileOffset = fileOffset,
+                  new ExpressionStatement(exception)..fileOffset = fileOffset,
+                  null)
+                ..fileOffset = fileOffset,
+              new ExpressionStatement(
+                  createVariableWrite(
+                      new VariableGet(temp)..fileOffset = fileOffset)
+                    ..fileOffset = fileOffset)
+                ..fileOffset = fileOffset,
+              new ExpressionStatement(
+                  createIsSetWrite(
+                      new BoolLiteral(true)..fileOffset = fileOffset)
+                    ..fileOffset = fileOffset)
+                ..fileOffset = fileOffset,
+            ]),
+            null)
+          ..fileOffset = fileOffset,
+        new ReturnStatement(
+            // If [type] is a type variable with undetermined nullability we
+            // need to create a read of the field that is promoted to the type
+            // variable type.
+            createVariableRead(needsPromotion: type.isPotentiallyNonNullable))
+          ..fileOffset = fileOffset
+      ])
+        ..fileOffset = fileOffset;
+    case IsSetEncoding.useSentinel:
+      // Generate:
+      //
+      //    return let #1 = _#field in isSentinel(#1)
+      //        ? let #2 = <init> in isSentinel(_#field)
+      //            ? _#field = #2 : throw '...'
+      //        : #1;
+      VariableDeclaration variable = new VariableDeclaration.forValue(
+          createVariableRead(needsPromotion: false)..fileOffset = fileOffset,
+          type: type)
+        ..fileOffset = fileOffset;
+      return new ReturnStatement(
+          new Let(
+              variable,
+              new ConditionalExpression(
+                  new StaticInvocation(
+                      coreTypes.isSentinelMethod,
+                      new Arguments(<Expression>[
+                        new VariableGet(variable)..fileOffset = fileOffset
+                      ])
+                        ..fileOffset = fileOffset)
+                    ..fileOffset = fileOffset,
+                  new Let(
+                      temp,
+                      new ConditionalExpression(
+                          new StaticInvocation(
+                              coreTypes.isSentinelMethod,
+                              new Arguments(<Expression>[
+                                createVariableRead(needsPromotion: false)
+                                  ..fileOffset = fileOffset
+                              ])
+                                ..fileOffset = fileOffset)
+                            ..fileOffset = fileOffset,
+                          createVariableWrite(
+                              new VariableGet(temp)..fileOffset = fileOffset)
+                            ..fileOffset = fileOffset,
+                          exception,
+                          type)
+                        ..fileOffset = fileOffset),
+                  new VariableGet(variable)..fileOffset = fileOffset,
+                  type)
+                ..fileOffset = fileOffset)
+            ..fileOffset = fileOffset)
+        ..fileOffset = fileOffset;
+    case IsSetEncoding.useNull:
+      // Generate:
+      //
+      //    return let #1 = _#field in #1 == null
+      //        ? let #2 = <init> in _#field == null
+      //            ? _#field = #2 : throw '...'
+      //        : #1;
+      VariableDeclaration variable = new VariableDeclaration.forValue(
+          createVariableRead(needsPromotion: false)..fileOffset = fileOffset,
+          type: type.withDeclaredNullability(Nullability.nullable))
+        ..fileOffset = fileOffset;
+      return new ReturnStatement(
+          new Let(
+              variable,
+              new ConditionalExpression(
+                  new MethodInvocation(
+                      new VariableGet(variable)..fileOffset = fileOffset,
+                      equalsName,
+                      new Arguments(<Expression>[
+                        new NullLiteral()..fileOffset = fileOffset
+                      ])
+                        ..fileOffset = fileOffset)
+                    ..fileOffset = fileOffset,
+                  new Let(
+                      temp,
+                      new ConditionalExpression(
+                          new MethodInvocation(
+                              createVariableRead(needsPromotion: false)
+                                ..fileOffset = fileOffset,
+                              equalsName,
+                              new Arguments(<Expression>[
+                                new NullLiteral()..fileOffset = fileOffset
+                              ])
+                                ..fileOffset = fileOffset)
+                            ..fileOffset = fileOffset,
+                          createVariableWrite(
+                              new VariableGet(temp)..fileOffset = fileOffset)
+                            ..fileOffset = fileOffset,
+                          exception,
+                          type)
+                        ..fileOffset = fileOffset),
+                  new VariableGet(variable, type)..fileOffset = fileOffset,
+                  type)
+                ..fileOffset = fileOffset)
+            ..fileOffset = fileOffset)
+        ..fileOffset = fileOffset;
   }
+  throw new UnsupportedError("Unexpected IsSetEncoding $isSetEncoding");
 }
 
 /// Creates the body for the synthesized getter used to encode the lowering
@@ -216,8 +295,8 @@
     int fileOffset, String name, DartType type, String variableKindName,
     {Expression createVariableRead({bool needsPromotion}),
     Expression createIsSetRead(),
-    bool useIsSetField}) {
-  assert(useIsSetField != null);
+    IsSetEncoding isSetEncoding}) {
+  assert(isSetEncoding != null);
   Expression exception = new Throw(new ConstructorInvocation(
       coreTypes.lateInitializationErrorConstructor,
       new Arguments(<Expression>[
@@ -228,46 +307,73 @@
         ..fileOffset = fileOffset)
     ..fileOffset = fileOffset)
     ..fileOffset = fileOffset;
-  if (useIsSetField) {
-    // Generate:
-    //
-    //    return _#isSet#field ? _#field : throw '...';
-    return new ReturnStatement(
-        new ConditionalExpression(
-            createIsSetRead()..fileOffset = fileOffset,
-            createVariableRead(needsPromotion: type.isPotentiallyNonNullable)
-              ..fileOffset = fileOffset,
-            exception,
-            type)
-          ..fileOffset = fileOffset)
-      ..fileOffset = fileOffset;
-  } else {
-    // Generate:
-    //
-    //    return let # = _#field in # == null ? throw '...' : #;
-    VariableDeclaration variable = new VariableDeclaration.forValue(
-        createVariableRead()..fileOffset = fileOffset,
-        type: type.withDeclaredNullability(Nullability.nullable))
-      ..fileOffset = fileOffset;
-    return new ReturnStatement(
-        new Let(
-            variable,
-            new ConditionalExpression(
-                new MethodInvocation(
-                    new VariableGet(variable)..fileOffset = fileOffset,
-                    equalsName,
-                    new Arguments(<Expression>[
-                      new NullLiteral()..fileOffset = fileOffset
-                    ])
-                      ..fileOffset = fileOffset)
-                  ..fileOffset = fileOffset,
-                exception,
-                new VariableGet(variable, type)..fileOffset = fileOffset,
-                type)
-              ..fileOffset = fileOffset)
-          ..fileOffset = fileOffset)
-      ..fileOffset = fileOffset;
+  switch (isSetEncoding) {
+    case IsSetEncoding.useIsSetField:
+      // Generate:
+      //
+      //    return _#isSet#field ? _#field : throw '...';
+      return new ReturnStatement(
+          new ConditionalExpression(
+              createIsSetRead()..fileOffset = fileOffset,
+              createVariableRead(needsPromotion: type.isPotentiallyNonNullable)
+                ..fileOffset = fileOffset,
+              exception,
+              type)
+            ..fileOffset = fileOffset)
+        ..fileOffset = fileOffset;
+    case IsSetEncoding.useSentinel:
+      // Generate:
+      //
+      //    return let # = _#field in isSentinel(#) ? throw '...' : #;
+      VariableDeclaration variable = new VariableDeclaration.forValue(
+          createVariableRead()..fileOffset = fileOffset,
+          type: type.withDeclaredNullability(Nullability.nullable))
+        ..fileOffset = fileOffset;
+      return new ReturnStatement(
+          new Let(
+              variable,
+              new ConditionalExpression(
+                  new StaticInvocation(
+                      coreTypes.isSentinelMethod,
+                      new Arguments(<Expression>[
+                        new VariableGet(variable)..fileOffset = fileOffset
+                      ])
+                        ..fileOffset = fileOffset)
+                    ..fileOffset = fileOffset,
+                  exception,
+                  new VariableGet(variable, type)..fileOffset = fileOffset,
+                  type)
+                ..fileOffset = fileOffset)
+            ..fileOffset = fileOffset)
+        ..fileOffset = fileOffset;
+    case IsSetEncoding.useNull:
+      // Generate:
+      //
+      //    return let # = _#field in # == null ? throw '...' : #;
+      VariableDeclaration variable = new VariableDeclaration.forValue(
+          createVariableRead()..fileOffset = fileOffset,
+          type: type.withDeclaredNullability(Nullability.nullable))
+        ..fileOffset = fileOffset;
+      return new ReturnStatement(
+          new Let(
+              variable,
+              new ConditionalExpression(
+                  new MethodInvocation(
+                      new VariableGet(variable)..fileOffset = fileOffset,
+                      equalsName,
+                      new Arguments(<Expression>[
+                        new NullLiteral()..fileOffset = fileOffset
+                      ])
+                        ..fileOffset = fileOffset)
+                    ..fileOffset = fileOffset,
+                  exception,
+                  new VariableGet(variable, type)..fileOffset = fileOffset,
+                  type)
+                ..fileOffset = fileOffset)
+            ..fileOffset = fileOffset)
+        ..fileOffset = fileOffset;
   }
+  throw new UnsupportedError("Unexpected IsSetEncoding $isSetEncoding");
 }
 
 /// Creates the body for the synthesized setter used to encode the lowering
@@ -277,8 +383,8 @@
     {bool shouldReturnValue,
     Expression createVariableWrite(Expression value),
     Expression createIsSetWrite(Expression value),
-    bool useIsSetField}) {
-  assert(useIsSetField != null);
+    IsSetEncoding isSetEncoding}) {
+  assert(isSetEncoding != null);
   Statement createReturn(Expression value) {
     if (shouldReturnValue) {
       return new ReturnStatement(value)..fileOffset = fileOffset;
@@ -291,27 +397,30 @@
       createVariableWrite(new VariableGet(parameter)..fileOffset = fileOffset)
         ..fileOffset = fileOffset);
 
-  if (useIsSetField) {
-    // Generate:
-    //
-    //    _#isSet#field = true;
-    //    return _#field = parameter
-    //
-    return new Block([
-      new ExpressionStatement(
-          createIsSetWrite(new BoolLiteral(true)..fileOffset = fileOffset)
-            ..fileOffset = fileOffset)
-        ..fileOffset = fileOffset,
-      assignment
-    ])
-      ..fileOffset = fileOffset;
-  } else {
-    // Generate:
-    //
-    //    return _#field = parameter
-    //
-    return assignment;
+  switch (isSetEncoding) {
+    case IsSetEncoding.useIsSetField:
+      // Generate:
+      //
+      //    _#isSet#field = true;
+      //    return _#field = parameter
+      //
+      return new Block([
+        new ExpressionStatement(
+            createIsSetWrite(new BoolLiteral(true)..fileOffset = fileOffset)
+              ..fileOffset = fileOffset)
+          ..fileOffset = fileOffset,
+        assignment
+      ])
+        ..fileOffset = fileOffset;
+    case IsSetEncoding.useSentinel:
+    case IsSetEncoding.useNull:
+      // Generate:
+      //
+      //    return _#field = parameter
+      //
+      return assignment;
   }
+  throw new UnsupportedError("Unexpected IsSetEncoding $isSetEncoding");
 }
 
 /// Creates the body for the synthesized setter used to encode the lowering
@@ -328,8 +437,8 @@
     Expression createVariableWrite(Expression value),
     Expression createIsSetRead(),
     Expression createIsSetWrite(Expression value),
-    bool useIsSetField}) {
-  assert(useIsSetField != null);
+    IsSetEncoding isSetEncoding}) {
+  assert(isSetEncoding != null);
   Expression exception = new Throw(new ConstructorInvocation(
       coreTypes.lateInitializationErrorConstructor,
       new Arguments(<Expression>[
@@ -349,49 +458,132 @@
     }
   }
 
-  if (useIsSetField) {
-    // Generate:
-    //
-    //    if (_#isSet#field) {
-    //      throw '...';
-    //    } else
-    //      _#isSet#field = true;
-    //      return _#field = parameter
-    //    }
-    return new IfStatement(
-        createIsSetRead()..fileOffset = fileOffset,
+  switch (isSetEncoding) {
+    case IsSetEncoding.useIsSetField:
+      // Generate:
+      //
+      //    if (_#isSet#field) {
+      //      throw '...';
+      //    } else
+      //      _#isSet#field = true;
+      //      return _#field = parameter
+      //    }
+      return new IfStatement(
+          createIsSetRead()..fileOffset = fileOffset,
+          new ExpressionStatement(exception)..fileOffset = fileOffset,
+          new Block([
+            new ExpressionStatement(
+                createIsSetWrite(new BoolLiteral(true)..fileOffset = fileOffset)
+                  ..fileOffset = fileOffset)
+              ..fileOffset = fileOffset,
+            createReturn(createVariableWrite(
+                new VariableGet(parameter)..fileOffset = fileOffset)
+              ..fileOffset = fileOffset)
+          ])
+            ..fileOffset = fileOffset)
+        ..fileOffset = fileOffset;
+    case IsSetEncoding.useSentinel:
+      // Generate:
+      //
+      //    if (isSentinel(_#field)) {
+      //      return _#field = parameter;
+      //    } else {
+      //      throw '...';
+      //    }
+      return new IfStatement(
+        new StaticInvocation(
+            coreTypes.isSentinelMethod,
+            new Arguments(
+                <Expression>[createVariableRead()..fileOffset = fileOffset])
+              ..fileOffset = fileOffset)
+          ..fileOffset = fileOffset,
+        createReturn(createVariableWrite(
+            new VariableGet(parameter)..fileOffset = fileOffset)
+          ..fileOffset = fileOffset),
         new ExpressionStatement(exception)..fileOffset = fileOffset,
-        new Block([
-          new ExpressionStatement(
-              createIsSetWrite(new BoolLiteral(true)..fileOffset = fileOffset)
-                ..fileOffset = fileOffset)
-            ..fileOffset = fileOffset,
-          createReturn(createVariableWrite(
-              new VariableGet(parameter)..fileOffset = fileOffset)
-            ..fileOffset = fileOffset)
-        ])
-          ..fileOffset = fileOffset)
-      ..fileOffset = fileOffset;
-  } else {
-    // Generate:
-    //
-    //    if (_#field == null) {
-    //      return _#field = parameter;
-    //    } else {
-    //      throw '...';
-    //    }
-    return new IfStatement(
-      new MethodInvocation(
-          createVariableRead()..fileOffset = fileOffset,
-          equalsName,
-          new Arguments(
-              <Expression>[new NullLiteral()..fileOffset = fileOffset])
-            ..fileOffset = fileOffset)
-        ..fileOffset = fileOffset,
-      createReturn(createVariableWrite(
-          new VariableGet(parameter)..fileOffset = fileOffset)
-        ..fileOffset = fileOffset),
-      new ExpressionStatement(exception)..fileOffset = fileOffset,
-    )..fileOffset = fileOffset;
+      )..fileOffset = fileOffset;
+    case IsSetEncoding.useNull:
+      // Generate:
+      //
+      //    if (_#field == null) {
+      //      return _#field = parameter;
+      //    } else {
+      //      throw '...';
+      //    }
+      return new IfStatement(
+        new MethodInvocation(
+            createVariableRead()..fileOffset = fileOffset,
+            equalsName,
+            new Arguments(
+                <Expression>[new NullLiteral()..fileOffset = fileOffset])
+              ..fileOffset = fileOffset)
+          ..fileOffset = fileOffset,
+        createReturn(createVariableWrite(
+            new VariableGet(parameter)..fileOffset = fileOffset)
+          ..fileOffset = fileOffset),
+        new ExpressionStatement(exception)..fileOffset = fileOffset,
+      )..fileOffset = fileOffset;
   }
+  throw new UnsupportedError("Unexpected IsSetEncoding $isSetEncoding");
+}
+
+/// Strategies for encoding whether a late field/local has been initialized.
+enum IsSetEncoding {
+  /// Use a boolean `isSet` field/local.
+  useIsSetField,
+
+  /// Use `null` as sentinel value to signal an uninitialized field/locals.
+  useNull,
+
+  /// Use `createSentinel`and `isSentinel` from `dart:_internal` to generate
+  /// and check a sentinel value to signal an uninitialized field/local.
+  useSentinel,
+}
+
+/// Strategies for encoding of late fields and locals.
+enum IsSetStrategy {
+  /// Always is use an `isSet` field/local to track whether the field/local has
+  /// been initialized.
+  forceUseIsSetField,
+
+  /// For potentially nullable fields/locals use an `isSet` field/local to track
+  /// whether the field/local has been initialized. Otherwise use `null` as
+  /// sentinel value to signal an uninitialized field/local.
+  ///
+  /// This strategy can only be used with sound null safety mode. In weak mode
+  /// non-nullable can be assigned `null` from legacy code and therefore `null`
+  /// doesn't work as a sentinel.
+  useIsSetFieldOrNull,
+
+  /// For potentially nullable fields/locals use `createSentinel`and
+  /// `isSentinel` from `dart:_internal` to generate and check a sentinel value
+  /// to signal an uninitialized field/local. Otherwise use `null` as
+  /// sentinel value to signal an uninitialized field/local.
+  useSentinelOrNull,
+}
+
+IsSetStrategy computeIsSetStrategy(SourceLibraryBuilder libraryBuilder) {
+  IsSetStrategy isSetStrategy = IsSetStrategy.useIsSetFieldOrNull;
+  if (libraryBuilder.loader.target.backendTarget.supportsLateLoweringSentinel) {
+    isSetStrategy = IsSetStrategy.useSentinelOrNull;
+  } else if (libraryBuilder.loader.nnbdMode != NnbdMode.Strong) {
+    isSetStrategy = IsSetStrategy.forceUseIsSetField;
+  }
+  return isSetStrategy;
+}
+
+IsSetEncoding computeIsSetEncoding(DartType type, IsSetStrategy isSetStrategy) {
+  switch (isSetStrategy) {
+    case IsSetStrategy.forceUseIsSetField:
+      return IsSetEncoding.useIsSetField;
+    case IsSetStrategy.useIsSetFieldOrNull:
+      return type.isPotentiallyNullable
+          ? IsSetEncoding.useIsSetField
+          : IsSetEncoding.useNull;
+    case IsSetStrategy.useSentinelOrNull:
+      return type.isPotentiallyNullable
+          ? IsSetEncoding.useSentinel
+          : IsSetEncoding.useNull;
+  }
+  throw new UnsupportedError("Unexpected IsSetStrategy $isSetStrategy");
 }
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 a75173f..0fc4c97 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
@@ -37,8 +37,6 @@
 
 import '../kernel/forest.dart';
 
-import '../kernel/internal_ast.dart' show VariableDeclarationImpl;
-
 import '../kernel/kernel_builder.dart'
     show ClassHierarchyBuilder, ImplicitFieldType;
 
@@ -284,14 +282,6 @@
   }
 
   @override
-  bool isLocalVariableWithoutDeclaredType(VariableDeclaration variable) {
-    return variable is VariableDeclarationImpl &&
-        variable.parent is Statement &&
-        variable.isImplicitlyTyped &&
-        !variable.hasDeclaredInitializer;
-  }
-
-  @override
   bool isNever(DartType type) {
     return typeEnvironment.coreTypes.isBottom(type);
   }
diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status
index 3844240..2db105d 100644
--- a/pkg/front_end/messages.status
+++ b/pkg/front_end/messages.status
@@ -334,6 +334,8 @@
 FinalAndCovariant/part_wrapped_script2: Fail
 FinalAndCovariant/script2: Fail
 FinalFieldWithoutInitializer/example: Fail
+FinalNotAssignedError/script: Fail # Fasta reports too many errors
+FinalNotAssignedError/part_wrapped_script: Fail # Fasta reports too many errors
 ForInLoopElementTypeNotAssignable/example: Fail
 ForInLoopExactlyOneVariable/analyzerCode: Fail # The analyzer doesn't recover well.
 ForInLoopExactlyOneVariable/part_wrapped_statement: Fail
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index c77266e..4adf914 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -4195,6 +4195,19 @@
       T t; t;
     }
 
+FinalNotAssignedError:
+  template: "Final variable '#name' must be assigned before it can be used."
+  analyzerCode: READ_POTENTIALLY_UNASSIGNED_FINAL
+  configuration: nnbd-strong
+  script: >
+    method(bool b) {
+      final int i;
+      if (b) {
+        i = 0;
+      }
+      i;
+    }
+
 NonNullableLateDefinitelyUnassignedError:
   template: "Non-nullable late variable '#name' without initializer is definitely unassigned."
   configuration: nnbd-strong
diff --git a/pkg/front_end/test/comments_on_certain_arguments_tool.dart b/pkg/front_end/test/comments_on_certain_arguments_tool.dart
index 5920035..c0ff2cb 100644
--- a/pkg/front_end/test/comments_on_certain_arguments_tool.dart
+++ b/pkg/front_end/test/comments_on_certain_arguments_tool.dart
@@ -4,16 +4,7 @@
 
 import 'dart:convert' show utf8;
 import 'dart:io'
-    show
-        Directory,
-        File,
-        FileSystemEntity,
-        Platform,
-        Process,
-        ProcessResult,
-        exitCode,
-        stdin,
-        stdout;
+    show Directory, File, FileSystemEntity, exitCode, stdin, stdout;
 
 import 'package:_fe_analyzer_shared/src/messages/severity.dart' show Severity;
 import 'package:_fe_analyzer_shared/src/scanner/token.dart'
@@ -41,16 +32,9 @@
 import 'package:kernel/target/targets.dart' show TargetFlags;
 import "package:vm/target/vm.dart" show VmTarget;
 
-final Uri repoDir = _computeRepoDir();
+import "utils/io_utils.dart";
 
-Uri _computeRepoDir() {
-  ProcessResult result = Process.runSync(
-      'git', ['rev-parse', '--show-toplevel'],
-      runInShell: true,
-      workingDirectory: new File.fromUri(Platform.script).parent.path);
-  String dirPath = (result.stdout as String).trim();
-  return new Directory(dirPath).uri;
-}
+final Uri repoDir = computeRepoDirUri();
 
 Set<Uri> libUris = {};
 
diff --git a/pkg/front_end/test/explicit_creation_test.dart b/pkg/front_end/test/explicit_creation_test.dart
index 215f824..7e8246a 100644
--- a/pkg/front_end/test/explicit_creation_test.dart
+++ b/pkg/front_end/test/explicit_creation_test.dart
@@ -40,17 +40,9 @@
 import "package:vm/target/vm.dart" show VmTarget;
 
 import 'testing_utils.dart' show getGitFiles;
+import "utils/io_utils.dart";
 
-final Uri repoDir = _computeRepoDir();
-
-Uri _computeRepoDir() {
-  ProcessResult result = Process.runSync(
-      'git', ['rev-parse', '--show-toplevel'],
-      runInShell: true,
-      workingDirectory: new File.fromUri(Platform.script).parent.path);
-  String dirPath = (result.stdout as String).trim();
-  return new Directory(dirPath).uri;
-}
+final Uri repoDir = computeRepoDirUri();
 
 Set<Uri> libUris = {};
 
diff --git a/pkg/front_end/test/fasta/messages_suite.dart b/pkg/front_end/test/fasta/messages_suite.dart
index cb0f930..3a3dcd2 100644
--- a/pkg/front_end/test/fasta/messages_suite.dart
+++ b/pkg/front_end/test/fasta/messages_suite.dart
@@ -6,7 +6,7 @@
 
 import "dart:convert" show utf8;
 
-import "dart:io" show File;
+import 'dart:io' show File, Platform;
 
 import "dart:typed_data" show Uint8List;
 
@@ -97,8 +97,31 @@
   final BatchCompiler compiler;
 
   final bool fastOnly;
+  final bool interactive;
 
-  MessageTestSuite(this.fastOnly)
+  final Set<String> reportedWords = {};
+  final Set<String> reportedWordsDenylisted = {};
+
+  @override
+  Future<void> postRun() {
+    String dartPath = Platform.resolvedExecutable;
+    Uri suiteUri =
+        spell.repoDir.resolve("pkg/front_end/test/fasta/messages_suite.dart");
+    File suiteFile = new File.fromUri(suiteUri).absolute;
+    if (!suiteFile.existsSync()) {
+      throw "Specified suite path is invalid.";
+    }
+    String suitePath = suiteFile.path;
+    spell.spellSummarizeAndInteractiveMode(
+        reportedWords,
+        reportedWordsDenylisted,
+        [spell.Dictionaries.cfeMessages],
+        interactive,
+        '"$dartPath" "$suitePath" -DfastOnly=true -Dinteractive=true');
+    return null;
+  }
+
+  MessageTestSuite(this.fastOnly, this.interactive)
       : fileSystem = new MemoryFileSystem(Uri.parse("org-dartlang-fasta:///")),
         compiler = new BatchCompiler(null);
 
@@ -143,8 +166,8 @@
       Configuration configuration;
 
       Source source;
-      List<String> formatSpellingMistakes(
-          spell.SpellingResult spellResult, int offset, String message) {
+      List<String> formatSpellingMistakes(spell.SpellingResult spellResult,
+          int offset, String message, String messageForDenyListed) {
         if (source == null) {
           List<int> bytes = file.readAsBytesSync();
           List<int> lineStarts = new List<int>();
@@ -160,12 +183,20 @@
         for (int i = 0; i < spellResult.misspelledWords.length; i++) {
           Location location = source.getLocation(
               uri, offset + spellResult.misspelledWordsOffset[i]);
+          bool denylisted = spellResult.misspelledWordsDenylisted[i];
+          String messageToUse = message;
+          if (denylisted) {
+            messageToUse = messageForDenyListed;
+            reportedWordsDenylisted.add(spellResult.misspelledWords[i]);
+          } else {
+            reportedWords.add(spellResult.misspelledWords[i]);
+          }
           result.add(command_line_reporting.formatErrorMessage(
               source.getTextLine(location.line),
               location,
               spellResult.misspelledWords[i].length,
               relativize(uri),
-              "$message: '${spellResult.misspelledWords[i]}'."));
+              "$messageToUse: '${spellResult.misspelledWords[i]}'."));
         }
         return result;
       }
@@ -190,7 +221,10 @@
               spellingMessages.addAll(formatSpellingMistakes(
                   spellingResult,
                   node.span.start.offset,
-                  "Template likely has the following spelling mistake"));
+                  "Template has the following word that is "
+                      "not in our dictionary",
+                  "Template has the following word that is "
+                      "on our deny-list"));
             }
             break;
 
@@ -206,7 +240,10 @@
               spellingMessages.addAll(formatSpellingMistakes(
                   spellingResult,
                   node.span.start.offset,
-                  "Tip likely has the following spelling mistake"));
+                  "Tip has the following word that is "
+                      "not in our dictionary",
+                  "Tip has the following word that is "
+                      "on our deny-list"));
             }
             break;
 
@@ -745,7 +782,8 @@
 Future<MessageTestSuite> createContext(
     Chain suite, Map<String, String> environment) async {
   final bool fastOnly = environment["fastOnly"] == "true";
-  return new MessageTestSuite(fastOnly);
+  final bool interactive = environment["interactive"] == "true";
+  return new MessageTestSuite(fastOnly, interactive);
 }
 
 String relativize(Uri uri) {
diff --git a/pkg/front_end/test/fasta/testing/suite.dart b/pkg/front_end/test/fasta/testing/suite.dart
index 2905b1b..b18d9c2 100644
--- a/pkg/front_end/test/fasta/testing/suite.dart
+++ b/pkg/front_end/test/fasta/testing/suite.dart
@@ -162,6 +162,7 @@
 class FolderOptions {
   final Map<ExperimentalFlag, bool> _experimentalFlags;
   final bool forceLateLowering;
+  final bool forceLateLoweringSentinel;
   final bool forceStaticFieldLowering;
   final bool forceNoExplicitGetterCalls;
   final bool nnbdAgnosticMode;
@@ -170,6 +171,7 @@
 
   FolderOptions(this._experimentalFlags,
       {this.forceLateLowering: false,
+      this.forceLateLoweringSentinel: false,
       this.forceStaticFieldLowering: false,
       this.forceNoExplicitGetterCalls: false,
       this.nnbdAgnosticMode: false,
@@ -177,6 +179,7 @@
       // can be null
       this.overwriteCurrentSdkVersion})
       : assert(forceLateLowering != null),
+        assert(forceLateLoweringSentinel != null),
         assert(forceStaticFieldLowering != null),
         assert(forceNoExplicitGetterCalls != null),
         assert(nnbdAgnosticMode != null),
@@ -317,6 +320,7 @@
     FolderOptions folderOptions = _folderOptions[directory.uri];
     if (folderOptions == null) {
       bool forceLateLowering = false;
+      bool forceLateLoweringSentinel = false;
       bool forceStaticFieldLowering = false;
       bool forceNoExplicitGetterCalls = false;
       bool nnbdAgnosticMode = false;
@@ -324,6 +328,7 @@
       if (directory.uri == baseUri) {
         folderOptions = new FolderOptions({},
             forceLateLowering: forceLateLowering,
+            forceLateLoweringSentinel: forceLateLoweringSentinel,
             forceStaticFieldLowering: forceStaticFieldLowering,
             forceNoExplicitGetterCalls: forceNoExplicitGetterCalls,
             nnbdAgnosticMode: nnbdAgnosticMode,
@@ -342,6 +347,8 @@
             } else if (line.startsWith(overwriteCurrentSdkVersion)) {
               overwriteCurrentSdkVersionArgument =
                   line.substring(overwriteCurrentSdkVersion.length);
+            } else if (line.startsWith(Flags.forceLateLoweringSentinel)) {
+              forceLateLoweringSentinel = true;
             } else if (line.startsWith(Flags.forceLateLowering)) {
               forceLateLowering = true;
             } else if (line.startsWith(Flags.forceStaticFieldLowering)) {
@@ -367,6 +374,7 @@
                   onWarning: (String message) =>
                       throw new ArgumentError(message)),
               forceLateLowering: forceLateLowering,
+              forceLateLoweringSentinel: forceLateLoweringSentinel,
               forceStaticFieldLowering: forceStaticFieldLowering,
               forceNoExplicitGetterCalls: forceNoExplicitGetterCalls,
               nnbdAgnosticMode: nnbdAgnosticMode,
@@ -839,6 +847,8 @@
         await context.computeUriTranslator(description);
     TargetFlags targetFlags = new TargetFlags(
       forceLateLoweringForTesting: testOptions.forceLateLowering,
+      forceLateLoweringSentinelForTesting:
+          testOptions.forceLateLoweringSentinel,
       forceStaticFieldLoweringForTesting: testOptions.forceStaticFieldLowering,
       forceNoExplicitGetterCallsForTesting:
           testOptions.forceNoExplicitGetterCalls,
diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt
index 6b94883..5985a19 100644
--- a/pkg/front_end/test/spell_checking_list_code.txt
+++ b/pkg/front_end/test/spell_checking_list_code.txt
@@ -1036,6 +1036,7 @@
 stdout
 stmt
 str
+strategies
 streak
 streaming
 strict
diff --git a/pkg/front_end/test/spell_checking_list_tests.txt b/pkg/front_end/test/spell_checking_list_tests.txt
index 519403a..5aa5116 100644
--- a/pkg/front_end/test/spell_checking_list_tests.txt
+++ b/pkg/front_end/test/spell_checking_list_tests.txt
@@ -351,6 +351,7 @@
 ko
 koo
 la
+launch
 launching
 le
 legs
diff --git a/pkg/front_end/test/spell_checking_utils.dart b/pkg/front_end/test/spell_checking_utils.dart
index e29b233..948ea88 100644
--- a/pkg/front_end/test/spell_checking_utils.dart
+++ b/pkg/front_end/test/spell_checking_utils.dart
@@ -2,7 +2,11 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-import 'dart:io';
+import 'dart:io' show File, stdin, stdout;
+
+import "utils/io_utils.dart";
+
+final Uri repoDir = computeRepoDirUri();
 
 enum Dictionaries {
   common,
@@ -162,19 +166,18 @@
 Uri dictionaryToUri(Dictionaries dictionaryType) {
   switch (dictionaryType) {
     case Dictionaries.common:
-      return Uri.base
+      return repoDir
           .resolve("pkg/front_end/test/spell_checking_list_common.txt");
     case Dictionaries.cfeMessages:
-      return Uri.base
+      return repoDir
           .resolve("pkg/front_end/test/spell_checking_list_messages.txt");
     case Dictionaries.cfeCode:
-      return Uri.base
-          .resolve("pkg/front_end/test/spell_checking_list_code.txt");
+      return repoDir.resolve("pkg/front_end/test/spell_checking_list_code.txt");
     case Dictionaries.cfeTests:
-      return Uri.base
+      return repoDir
           .resolve("pkg/front_end/test/spell_checking_list_tests.txt");
     case Dictionaries.denylist:
-      return Uri.base
+      return repoDir
           .resolve("pkg/front_end/test/spell_checking_list_denylist.txt");
   }
   throw "Unknown Dictionary";
@@ -342,3 +345,121 @@
   }
   return result;
 }
+
+void spellSummarizeAndInteractiveMode(
+    Set<String> reportedWords,
+    Set<String> reportedWordsDenylisted,
+    List<Dictionaries> dictionaries,
+    bool interactive,
+    String interactiveLaunchExample) {
+  if (reportedWordsDenylisted.isNotEmpty) {
+    print("\n\n\n");
+    print("================");
+    print("The following words was reported as used and denylisted:");
+    print("----------------");
+    for (String s in reportedWordsDenylisted) {
+      print("$s");
+    }
+    print("================");
+  }
+  if (reportedWords.isNotEmpty) {
+    print("\n\n\n");
+    print("================");
+    print("The following word(s) were reported as unknown:");
+    print("----------------");
+
+    Dictionaries dictionaryToUse;
+    if (dictionaries.contains(Dictionaries.cfeTests)) {
+      dictionaryToUse = Dictionaries.cfeTests;
+    } else if (dictionaries.contains(Dictionaries.cfeMessages)) {
+      dictionaryToUse = Dictionaries.cfeMessages;
+    } else if (dictionaries.contains(Dictionaries.cfeCode)) {
+      dictionaryToUse = Dictionaries.cfeCode;
+    } else {
+      for (Dictionaries dictionary in dictionaries) {
+        if (dictionaryToUse == null ||
+            dictionary.index < dictionaryToUse.index) {
+          dictionaryToUse = dictionary;
+        }
+      }
+    }
+
+    if (interactive && dictionaryToUse != null) {
+      List<String> addedWords = new List<String>();
+      for (String s in reportedWords) {
+        print("- $s");
+        String answer;
+        bool add;
+        while (true) {
+          stdout.write("Do you want to add the word to the dictionary "
+              "$dictionaryToUse (y/n)? ");
+          answer = stdin.readLineSync().trim().toLowerCase();
+          switch (answer) {
+            case "y":
+            case "yes":
+            case "true":
+              add = true;
+              break;
+            case "n":
+            case "no":
+            case "false":
+              add = false;
+              break;
+            default:
+              add = null;
+              print("'$answer' is not a valid answer. Please try again.");
+              break;
+          }
+          if (add != null) break;
+        }
+        if (add) {
+          addedWords.add(s);
+        }
+      }
+      if (addedWords.isNotEmpty) {
+        File dictionaryFile =
+            new File.fromUri(dictionaryToUri(dictionaryToUse));
+        List<String> lines = dictionaryFile.readAsLinesSync();
+        List<String> header = new List<String>();
+        List<String> sortThis = new List<String>();
+        for (String line in lines) {
+          if (line.startsWith("#")) {
+            header.add(line);
+          } else if (line.trim().isEmpty && sortThis.isEmpty) {
+            header.add(line);
+          } else if (line.trim().isNotEmpty) {
+            sortThis.add(line);
+          }
+        }
+        sortThis.addAll(addedWords);
+        sortThis.sort();
+        lines = new List<String>();
+        lines.addAll(header);
+        if (header.isEmpty || header.last.isNotEmpty) {
+          lines.add("");
+        }
+        lines.addAll(sortThis);
+        lines.add("");
+        dictionaryFile.writeAsStringSync(lines.join("\n"));
+      }
+    } else {
+      for (String s in reportedWords) {
+        print("$s");
+      }
+      if (dictionaries.isNotEmpty) {
+        print("----------------");
+        print("If the word(s) are correctly spelled please add it to one of "
+            "these files:");
+        for (Dictionaries dictionary in dictionaries) {
+          print(" - ${dictionaryToUri(dictionary)}");
+        }
+
+        print("");
+        print("To add words easily, try to run this script in interactive "
+            "mode via the command");
+        print(interactiveLaunchExample);
+      }
+    }
+    print("================");
+  }
+}
diff --git a/pkg/front_end/test/spelling_test_base.dart b/pkg/front_end/test/spelling_test_base.dart
index 9879c8c..9bafa38 100644
--- a/pkg/front_end/test/spelling_test_base.dart
+++ b/pkg/front_end/test/spelling_test_base.dart
@@ -4,7 +4,7 @@
 
 import 'dart:async' show Future;
 
-import 'dart:io' show File, Platform, stdin, stdout;
+import 'dart:io' show File, Platform;
 
 import 'dart:typed_data' show Uint8List;
 
@@ -51,6 +51,8 @@
 
   bool get onlyDenylisted;
 
+  String get repoRelativeSuitePath;
+
   Set<String> reportedWords = {};
   Set<String> reportedWordsDenylisted = {};
 
@@ -61,111 +63,19 @@
 
   @override
   Future<void> postRun() {
-    if (reportedWordsDenylisted.isNotEmpty) {
-      print("\n\n\n");
-      print("================");
-      print("The following words was reported as used and denylisted:");
-      print("----------------");
-      for (String s in reportedWordsDenylisted) {
-        print("$s");
-      }
-      print("================");
+    String dartPath = Platform.resolvedExecutable;
+    Uri suiteUri = spell.repoDir.resolve(repoRelativeSuitePath);
+    File suiteFile = new File.fromUri(suiteUri).absolute;
+    if (!suiteFile.existsSync()) {
+      throw "Specified suite path is invalid.";
     }
-    if (reportedWords.isNotEmpty) {
-      print("\n\n\n");
-      print("================");
-      print("The following word(s) were reported as unknown:");
-      print("----------------");
-
-      spell.Dictionaries dictionaryToUse;
-      if (dictionaries.contains(spell.Dictionaries.cfeTests)) {
-        dictionaryToUse = spell.Dictionaries.cfeTests;
-      } else if (dictionaries.contains(spell.Dictionaries.cfeMessages)) {
-        dictionaryToUse = spell.Dictionaries.cfeMessages;
-      } else if (dictionaries.contains(spell.Dictionaries.cfeCode)) {
-        dictionaryToUse = spell.Dictionaries.cfeCode;
-      } else {
-        for (spell.Dictionaries dictionary in dictionaries) {
-          if (dictionaryToUse == null ||
-              dictionary.index < dictionaryToUse.index) {
-            dictionaryToUse = dictionary;
-          }
-        }
-      }
-
-      if (interactive && dictionaryToUse != null) {
-        List<String> addedWords = new List<String>();
-        for (String s in reportedWords) {
-          print("- $s");
-          stdout.write("Do you want to add the word to the dictionary "
-              "$dictionaryToUse (y/n)? ");
-          String answer = stdin.readLineSync().trim().toLowerCase();
-          bool add;
-          switch (answer) {
-            case "y":
-            case "yes":
-            case "true":
-              add = true;
-              break;
-            case "n":
-            case "no":
-            case "false":
-              add = false;
-              break;
-            default:
-              throw "Didn't understand '$answer'";
-          }
-          if (add) {
-            addedWords.add(s);
-          }
-        }
-        if (addedWords.isNotEmpty) {
-          File dictionaryFile =
-              new File.fromUri(spell.dictionaryToUri(dictionaryToUse));
-          List<String> lines = dictionaryFile.readAsLinesSync();
-          List<String> header = new List<String>();
-          List<String> sortThis = new List<String>();
-          for (String line in lines) {
-            if (line.startsWith("#")) {
-              header.add(line);
-            } else if (line.trim().isEmpty && sortThis.isEmpty) {
-              header.add(line);
-            } else if (line.trim().isNotEmpty) {
-              sortThis.add(line);
-            }
-          }
-          sortThis.addAll(addedWords);
-          sortThis.sort();
-          lines = new List<String>();
-          lines.addAll(header);
-          if (header.isEmpty || header.last.isNotEmpty) {
-            lines.add("");
-          }
-          lines.addAll(sortThis);
-          lines.add("");
-          dictionaryFile.writeAsStringSync(lines.join("\n"));
-        }
-      } else {
-        for (String s in reportedWords) {
-          print("$s");
-        }
-        if (dictionaries.isNotEmpty) {
-          print("----------------");
-          print("If the word(s) are correctly spelled please add it to one of "
-              "these files:");
-          for (spell.Dictionaries dictionary in dictionaries) {
-            print(" - ${spell.dictionaryToUri(dictionary)}");
-          }
-
-          print("");
-          print("To add words easily, try to run this script in interactive "
-              "mode via the command");
-          print("dart ${Platform.script.toFilePath()} "
-              "-DonlyInGit=$onlyInGit -Dinteractive=true");
-        }
-      }
-      print("================");
-    }
+    String suitePath = suiteFile.path;
+    spell.spellSummarizeAndInteractiveMode(
+        reportedWords,
+        reportedWordsDenylisted,
+        dictionaries,
+        interactive,
+        '"$dartPath" "$suitePath" -DonlyInGit=$onlyInGit -Dinteractive=true');
     return null;
   }
 }
diff --git a/pkg/front_end/test/spelling_test_external_targets.dart b/pkg/front_end/test/spelling_test_external_targets.dart
index f339a46..0330b22 100644
--- a/pkg/front_end/test/spelling_test_external_targets.dart
+++ b/pkg/front_end/test/spelling_test_external_targets.dart
@@ -39,6 +39,10 @@
   @override
   bool get onlyDenylisted => true;
 
+  @override
+  String get repoRelativeSuitePath =>
+      "pkg/front_end/test/spelling_test_external_targets.dart";
+
   Stream<TestDescription> list(Chain suite) async* {
     for (String subdir in const ["pkg/", "sdk/"]) {
       Directory testRoot = new Directory.fromUri(suite.uri.resolve(subdir));
diff --git a/pkg/front_end/test/spelling_test_not_src_suite.dart b/pkg/front_end/test/spelling_test_not_src_suite.dart
index 28d5262..3259c88 100644
--- a/pkg/front_end/test/spelling_test_not_src_suite.dart
+++ b/pkg/front_end/test/spelling_test_not_src_suite.dart
@@ -38,4 +38,8 @@
 
   @override
   bool get onlyDenylisted => false;
+
+  @override
+  String get repoRelativeSuitePath =>
+      "pkg/front_end/test/spelling_test_not_src_suite.dart";
 }
diff --git a/pkg/front_end/test/spelling_test_src_suite.dart b/pkg/front_end/test/spelling_test_src_suite.dart
index 4fe9568..afea1e0 100644
--- a/pkg/front_end/test/spelling_test_src_suite.dart
+++ b/pkg/front_end/test/spelling_test_src_suite.dart
@@ -37,4 +37,8 @@
 
   @override
   bool get onlyDenylisted => false;
+
+  @override
+  String get repoRelativeSuitePath =>
+      "pkg/front_end/test/spelling_test_src_suite.dart";
 }
diff --git a/pkg/front_end/testcases/late_lowering/initializer_rewrite.dart.weak.expect b/pkg/front_end/testcases/late_lowering/initializer_rewrite.dart.weak.expect
index 4747968..8784442 100644
--- a/pkg/front_end/testcases/late_lowering/initializer_rewrite.dart.weak.expect
+++ b/pkg/front_end/testcases/late_lowering/initializer_rewrite.dart.weak.expect
@@ -19,8 +19,16 @@
   synthetic constructor •() → self::Class
     : super core::Object::•()
     ;
-  static get nonNullableStaticField() → core::int
-    return let final core::int? #t1 = self::Class::_#nonNullableStaticField in #t1.==(null) ?{core::int} let final core::int #t2 = (let final core::int #t3 = self::Class::nonNullableStaticFieldReads in let final core::int #t4 = self::Class::nonNullableStaticFieldReads = #t3.{core::num::+}(1) in #t3).{core::num::==}(0) ?{core::int} self::Class::nonNullableStaticField.{core::num::+}(1) : 0 in self::Class::_#nonNullableStaticField.==(null) ?{core::int} self::Class::_#nonNullableStaticField = #t2 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableStaticField' has been assigned during initialization.") : #t1{core::int};
+  static get nonNullableStaticField() → core::int {
+    if(!self::Class::_#nonNullableStaticField#isSet) {
+      final core::int #t1 = (let final core::int #t2 = self::Class::nonNullableStaticFieldReads in let final core::int #t3 = self::Class::nonNullableStaticFieldReads = #t2.{core::num::+}(1) in #t2).{core::num::==}(0) ?{core::int} self::Class::nonNullableStaticField.{core::num::+}(1) : 0;
+      if(self::Class::_#nonNullableStaticField#isSet)
+        throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableStaticField' has been assigned during initialization.");
+      self::Class::_#nonNullableStaticField = #t1;
+      self::Class::_#nonNullableStaticField#isSet = true;
+    }
+    return let final core::int? #t4 = self::Class::_#nonNullableStaticField in #t4{core::int};
+  }
   static get nullableStaticField() → core::int? {
     if(!self::Class::_#nullableStaticField#isSet) {
       final core::int? #t5 = (let final core::int #t6 = self::Class::nullableStaticFieldReads in let final core::int #t7 = self::Class::nullableStaticFieldReads = #t6.{core::num::+}(1) in #t6).{core::num::==}(0) ?{core::int} self::Class::nullableStaticField.{core::Object::hashCode} : 0;
@@ -31,8 +39,16 @@
     }
     return self::Class::_#nullableStaticField;
   }
-  get nonNullableInstanceField() → core::int
-    return let final core::int? #t8 = this.{self::Class::_#Class#nonNullableInstanceField} in #t8.==(null) ?{core::int} let final core::int #t9 = (let final core::int #t10 = this.{self::Class::nonNullableInstanceFieldReads} in let final core::int #t11 = this.{self::Class::nonNullableInstanceFieldReads} = #t10.{core::num::+}(1) in #t10).{core::num::==}(0) ?{core::int} this.{self::Class::nonNullableInstanceField}.{core::num::+}(1) : 0 in this.{self::Class::_#Class#nonNullableInstanceField}.==(null) ?{core::int} this.{self::Class::_#Class#nonNullableInstanceField} = #t9 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableInstanceField' has been assigned during initialization.") : #t8{core::int};
+  get nonNullableInstanceField() → core::int {
+    if(!this.{self::Class::_#Class#nonNullableInstanceField#isSet}) {
+      final core::int #t8 = (let final core::int #t9 = this.{self::Class::nonNullableInstanceFieldReads} in let final core::int #t10 = this.{self::Class::nonNullableInstanceFieldReads} = #t9.{core::num::+}(1) in #t9).{core::num::==}(0) ?{core::int} this.{self::Class::nonNullableInstanceField}.{core::num::+}(1) : 0;
+      if(this.{self::Class::_#Class#nonNullableInstanceField#isSet})
+        throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableInstanceField' has been assigned during initialization.");
+      this.{self::Class::_#Class#nonNullableInstanceField} = #t8;
+      this.{self::Class::_#Class#nonNullableInstanceField#isSet} = true;
+    }
+    return let final core::int? #t11 = this.{self::Class::_#Class#nonNullableInstanceField} in #t11{core::int};
+  }
   get nullableInstanceField() → core::int? {
     if(!this.{self::Class::_#Class#nullableInstanceField#isSet}) {
       final core::int? #t12 = (let final core::int #t13 = this.{self::Class::nullableInstanceFieldReads} in let final core::int #t14 = this.{self::Class::nullableInstanceFieldReads} = #t13.{core::num::+}(1) in #t13).{core::num::==}(0) ?{core::int} this.{self::Class::nullableInstanceField}.{core::Object::hashCode} : 0;
@@ -50,8 +66,16 @@
 static field core::int nullableTopLevelFieldReads = 0;
 static field core::int? _#nullableTopLevelField = null;
 static field core::bool _#nullableTopLevelField#isSet = false;
-static get nonNullableTopLevelField() → core::int
-  return let final core::int? #t15 = self::_#nonNullableTopLevelField in #t15.==(null) ?{core::int} let final core::int #t16 = (let final core::int #t17 = self::nonNullableTopLevelFieldReads in let final core::int #t18 = self::nonNullableTopLevelFieldReads = #t17.{core::num::+}(1) in #t17).{core::num::==}(0) ?{core::int} self::nonNullableTopLevelField.{core::num::+}(1) : 0 in self::_#nonNullableTopLevelField.==(null) ?{core::int} self::_#nonNullableTopLevelField = #t16 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableTopLevelField' has been assigned during initialization.") : #t15{core::int};
+static get nonNullableTopLevelField() → core::int {
+  if(!self::_#nonNullableTopLevelField#isSet) {
+    final core::int #t15 = (let final core::int #t16 = self::nonNullableTopLevelFieldReads in let final core::int #t17 = self::nonNullableTopLevelFieldReads = #t16.{core::num::+}(1) in #t16).{core::num::==}(0) ?{core::int} self::nonNullableTopLevelField.{core::num::+}(1) : 0;
+    if(self::_#nonNullableTopLevelField#isSet)
+      throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableTopLevelField' has been assigned during initialization.");
+    self::_#nonNullableTopLevelField = #t15;
+    self::_#nonNullableTopLevelField#isSet = true;
+  }
+  return let final core::int? #t18 = self::_#nonNullableTopLevelField in #t18{core::int};
+}
 static get nullableTopLevelField() → core::int? {
   if(!self::_#nullableTopLevelField#isSet) {
     final core::int? #t19 = (let final core::int #t20 = self::nullableTopLevelFieldReads in let final core::int #t21 = self::nullableTopLevelFieldReads = #t20.{core::num::+}(1) in #t20).{core::num::==}(0) ?{core::int} self::nullableTopLevelField.{core::Object::hashCode} : 0;
diff --git a/pkg/front_end/testcases/late_lowering/initializer_rewrite.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering/initializer_rewrite.dart.weak.transformed.expect
index 4747968..8784442 100644
--- a/pkg/front_end/testcases/late_lowering/initializer_rewrite.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/initializer_rewrite.dart.weak.transformed.expect
@@ -19,8 +19,16 @@
   synthetic constructor •() → self::Class
     : super core::Object::•()
     ;
-  static get nonNullableStaticField() → core::int
-    return let final core::int? #t1 = self::Class::_#nonNullableStaticField in #t1.==(null) ?{core::int} let final core::int #t2 = (let final core::int #t3 = self::Class::nonNullableStaticFieldReads in let final core::int #t4 = self::Class::nonNullableStaticFieldReads = #t3.{core::num::+}(1) in #t3).{core::num::==}(0) ?{core::int} self::Class::nonNullableStaticField.{core::num::+}(1) : 0 in self::Class::_#nonNullableStaticField.==(null) ?{core::int} self::Class::_#nonNullableStaticField = #t2 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableStaticField' has been assigned during initialization.") : #t1{core::int};
+  static get nonNullableStaticField() → core::int {
+    if(!self::Class::_#nonNullableStaticField#isSet) {
+      final core::int #t1 = (let final core::int #t2 = self::Class::nonNullableStaticFieldReads in let final core::int #t3 = self::Class::nonNullableStaticFieldReads = #t2.{core::num::+}(1) in #t2).{core::num::==}(0) ?{core::int} self::Class::nonNullableStaticField.{core::num::+}(1) : 0;
+      if(self::Class::_#nonNullableStaticField#isSet)
+        throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableStaticField' has been assigned during initialization.");
+      self::Class::_#nonNullableStaticField = #t1;
+      self::Class::_#nonNullableStaticField#isSet = true;
+    }
+    return let final core::int? #t4 = self::Class::_#nonNullableStaticField in #t4{core::int};
+  }
   static get nullableStaticField() → core::int? {
     if(!self::Class::_#nullableStaticField#isSet) {
       final core::int? #t5 = (let final core::int #t6 = self::Class::nullableStaticFieldReads in let final core::int #t7 = self::Class::nullableStaticFieldReads = #t6.{core::num::+}(1) in #t6).{core::num::==}(0) ?{core::int} self::Class::nullableStaticField.{core::Object::hashCode} : 0;
@@ -31,8 +39,16 @@
     }
     return self::Class::_#nullableStaticField;
   }
-  get nonNullableInstanceField() → core::int
-    return let final core::int? #t8 = this.{self::Class::_#Class#nonNullableInstanceField} in #t8.==(null) ?{core::int} let final core::int #t9 = (let final core::int #t10 = this.{self::Class::nonNullableInstanceFieldReads} in let final core::int #t11 = this.{self::Class::nonNullableInstanceFieldReads} = #t10.{core::num::+}(1) in #t10).{core::num::==}(0) ?{core::int} this.{self::Class::nonNullableInstanceField}.{core::num::+}(1) : 0 in this.{self::Class::_#Class#nonNullableInstanceField}.==(null) ?{core::int} this.{self::Class::_#Class#nonNullableInstanceField} = #t9 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableInstanceField' has been assigned during initialization.") : #t8{core::int};
+  get nonNullableInstanceField() → core::int {
+    if(!this.{self::Class::_#Class#nonNullableInstanceField#isSet}) {
+      final core::int #t8 = (let final core::int #t9 = this.{self::Class::nonNullableInstanceFieldReads} in let final core::int #t10 = this.{self::Class::nonNullableInstanceFieldReads} = #t9.{core::num::+}(1) in #t9).{core::num::==}(0) ?{core::int} this.{self::Class::nonNullableInstanceField}.{core::num::+}(1) : 0;
+      if(this.{self::Class::_#Class#nonNullableInstanceField#isSet})
+        throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableInstanceField' has been assigned during initialization.");
+      this.{self::Class::_#Class#nonNullableInstanceField} = #t8;
+      this.{self::Class::_#Class#nonNullableInstanceField#isSet} = true;
+    }
+    return let final core::int? #t11 = this.{self::Class::_#Class#nonNullableInstanceField} in #t11{core::int};
+  }
   get nullableInstanceField() → core::int? {
     if(!this.{self::Class::_#Class#nullableInstanceField#isSet}) {
       final core::int? #t12 = (let final core::int #t13 = this.{self::Class::nullableInstanceFieldReads} in let final core::int #t14 = this.{self::Class::nullableInstanceFieldReads} = #t13.{core::num::+}(1) in #t13).{core::num::==}(0) ?{core::int} this.{self::Class::nullableInstanceField}.{core::Object::hashCode} : 0;
@@ -50,8 +66,16 @@
 static field core::int nullableTopLevelFieldReads = 0;
 static field core::int? _#nullableTopLevelField = null;
 static field core::bool _#nullableTopLevelField#isSet = false;
-static get nonNullableTopLevelField() → core::int
-  return let final core::int? #t15 = self::_#nonNullableTopLevelField in #t15.==(null) ?{core::int} let final core::int #t16 = (let final core::int #t17 = self::nonNullableTopLevelFieldReads in let final core::int #t18 = self::nonNullableTopLevelFieldReads = #t17.{core::num::+}(1) in #t17).{core::num::==}(0) ?{core::int} self::nonNullableTopLevelField.{core::num::+}(1) : 0 in self::_#nonNullableTopLevelField.==(null) ?{core::int} self::_#nonNullableTopLevelField = #t16 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableTopLevelField' has been assigned during initialization.") : #t15{core::int};
+static get nonNullableTopLevelField() → core::int {
+  if(!self::_#nonNullableTopLevelField#isSet) {
+    final core::int #t15 = (let final core::int #t16 = self::nonNullableTopLevelFieldReads in let final core::int #t17 = self::nonNullableTopLevelFieldReads = #t16.{core::num::+}(1) in #t16).{core::num::==}(0) ?{core::int} self::nonNullableTopLevelField.{core::num::+}(1) : 0;
+    if(self::_#nonNullableTopLevelField#isSet)
+      throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableTopLevelField' has been assigned during initialization.");
+    self::_#nonNullableTopLevelField = #t15;
+    self::_#nonNullableTopLevelField#isSet = true;
+  }
+  return let final core::int? #t18 = self::_#nonNullableTopLevelField in #t18{core::int};
+}
 static get nullableTopLevelField() → core::int? {
   if(!self::_#nullableTopLevelField#isSet) {
     final core::int? #t19 = (let final core::int #t20 = self::nullableTopLevelFieldReads in let final core::int #t21 = self::nullableTopLevelFieldReads = #t20.{core::num::+}(1) in #t20).{core::num::==}(0) ?{core::int} self::nullableTopLevelField.{core::Object::hashCode} : 0;
diff --git a/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart b/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart
new file mode 100644
index 0000000..2f01985
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart
@@ -0,0 +1,65 @@
+// 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.
+
+import 'initializer_rewrite_from_opt_out_lib.dart';
+
+int nonNullableTopLevelFieldReads = 0;
+
+late final int nonNullableTopLevelField = nonNullableTopLevelFieldReads++ == 0
+    ? nonNullableTopLevelField
+    : computeInitialValue();
+
+int nullableTopLevelFieldReads = 0;
+
+late final int? nullableTopLevelField = nullableTopLevelFieldReads++ == 0
+    ? nullableTopLevelField
+    : computeInitialValue();
+
+class Class {
+  static int nonNullableStaticFieldReads = 0;
+
+  static late final int nonNullableStaticField =
+      nonNullableStaticFieldReads++ == 0
+          ? nonNullableStaticField
+          : computeInitialValue();
+
+  static int nullableStaticFieldReads = 0;
+
+  static late final int? nullableStaticField = nullableStaticFieldReads++ == 0
+      ? nullableStaticField
+      : computeInitialValue();
+
+  int nonNullableInstanceFieldReads = 0;
+
+  late final int nonNullableInstanceField = nonNullableInstanceFieldReads++ == 0
+      ? nonNullableInstanceField
+      : computeInitialValue();
+
+  int nullableInstanceFieldReads = 0;
+
+  late final int? nullableInstanceField = nullableInstanceFieldReads++ == 0
+      ? nullableInstanceField
+      : computeInitialValue();
+}
+
+void main() {
+  throws(() => nonNullableTopLevelField, "Read nonNullableTopLevelField");
+  throws(() => nullableTopLevelField, "Read nullableTopLevelField");
+  throws(() => Class.nonNullableStaticField, "Read nonNullableStaticField");
+  throws(() => Class.nullableStaticField, "Read nullableStaticField");
+  throws(() => new Class().nonNullableInstanceField,
+      "Read nonNullableInstanceField");
+  throws(() => new Class().nullableInstanceField, "Read nullableInstanceField");
+}
+
+throws(f(), String message) {
+  dynamic value;
+  try {
+    value = f();
+  } on LateInitializationError catch (e) {
+    print(e);
+    return;
+  }
+  throw '$message: $value';
+}
diff --git a/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart.outline.expect b/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart.outline.expect
new file mode 100644
index 0000000..7ddeb49
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart.outline.expect
@@ -0,0 +1,49 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+import "org-dartlang-testcase:///initializer_rewrite_from_opt_out_lib.dart";
+
+class Class extends core::Object {
+  static field core::int nonNullableStaticFieldReads;
+  static field core::int? _#nonNullableStaticField;
+  static field core::int nullableStaticFieldReads;
+  static field core::int? _#nullableStaticField;
+  static field core::bool _#nullableStaticField#isSet;
+  field core::int nonNullableInstanceFieldReads;
+  field core::int? _#Class#nonNullableInstanceField;
+  field core::int nullableInstanceFieldReads;
+  field core::int? _#Class#nullableInstanceField;
+  field core::bool _#Class#nullableInstanceField#isSet;
+  synthetic constructor •() → self::Class
+    ;
+  static get nonNullableStaticField() → core::int;
+  static get nullableStaticField() → core::int?;
+  get nonNullableInstanceField() → core::int;
+  get nullableInstanceField() → core::int?;
+}
+static field core::int nonNullableTopLevelFieldReads;
+static field core::int? _#nonNullableTopLevelField;
+static field core::int nullableTopLevelFieldReads;
+static field core::int? _#nullableTopLevelField;
+static field core::bool _#nullableTopLevelField#isSet;
+static get nonNullableTopLevelField() → core::int;
+static get nullableTopLevelField() → core::int?;
+static method main() → void
+  ;
+static method throws(() → dynamic f, core::String message) → dynamic
+  ;
+
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out_lib.dart:5:1: Error: A library can't opt out of null safety by default, when using sound null safety.
+// // @dart=2.8
+// ^^^^^^^^^^^^
+//
+import self as self2;
+import "dart:core" as core;
+
+static method computeInitialValue() → core::int
+  ;
diff --git a/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart.strong.expect b/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart.strong.expect
new file mode 100644
index 0000000..2a73d8e
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart.strong.expect
@@ -0,0 +1,103 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "initializer_rewrite_from_opt_out_lib.dart" as ini;
+import "dart:_internal" as _in;
+
+import "org-dartlang-testcase:///initializer_rewrite_from_opt_out_lib.dart";
+
+class Class extends core::Object {
+  static field core::int nonNullableStaticFieldReads = 0;
+  static field core::int? _#nonNullableStaticField = null;
+  static field core::int nullableStaticFieldReads = 0;
+  static field core::int? _#nullableStaticField = null;
+  static field core::bool _#nullableStaticField#isSet = false;
+  field core::int nonNullableInstanceFieldReads = 0;
+  field core::int? _#Class#nonNullableInstanceField = null;
+  field core::int nullableInstanceFieldReads = 0;
+  field core::int? _#Class#nullableInstanceField = null;
+  field core::bool _#Class#nullableInstanceField#isSet = false;
+  synthetic constructor •() → self::Class
+    : super core::Object::•()
+    ;
+  static get nonNullableStaticField() → core::int
+    return let final core::int? #t1 = self::Class::_#nonNullableStaticField in #t1.==(null) ?{core::int} let final core::int #t2 = (let final core::int #t3 = self::Class::nonNullableStaticFieldReads in let final core::int #t4 = self::Class::nonNullableStaticFieldReads = #t3.{core::num::+}(1) in #t3).{core::num::==}(0) ?{core::int} self::Class::nonNullableStaticField : ini::computeInitialValue() in self::Class::_#nonNullableStaticField.==(null) ?{core::int} self::Class::_#nonNullableStaticField = #t2 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableStaticField' has been assigned during initialization.") : #t1{core::int};
+  static get nullableStaticField() → core::int? {
+    if(!self::Class::_#nullableStaticField#isSet) {
+      final core::int? #t5 = (let final core::int #t6 = self::Class::nullableStaticFieldReads in let final core::int #t7 = self::Class::nullableStaticFieldReads = #t6.{core::num::+}(1) in #t6).{core::num::==}(0) ?{core::int?} self::Class::nullableStaticField : ini::computeInitialValue();
+      if(self::Class::_#nullableStaticField#isSet)
+        throw new _in::LateInitializationErrorImpl::•("Field 'nullableStaticField' has been assigned during initialization.");
+      self::Class::_#nullableStaticField = #t5;
+      self::Class::_#nullableStaticField#isSet = true;
+    }
+    return self::Class::_#nullableStaticField;
+  }
+  get nonNullableInstanceField() → core::int
+    return let final core::int? #t8 = this.{self::Class::_#Class#nonNullableInstanceField} in #t8.==(null) ?{core::int} let final core::int #t9 = (let final core::int #t10 = this.{self::Class::nonNullableInstanceFieldReads} in let final core::int #t11 = this.{self::Class::nonNullableInstanceFieldReads} = #t10.{core::num::+}(1) in #t10).{core::num::==}(0) ?{core::int} this.{self::Class::nonNullableInstanceField} : ini::computeInitialValue() in this.{self::Class::_#Class#nonNullableInstanceField}.==(null) ?{core::int} this.{self::Class::_#Class#nonNullableInstanceField} = #t9 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableInstanceField' has been assigned during initialization.") : #t8{core::int};
+  get nullableInstanceField() → core::int? {
+    if(!this.{self::Class::_#Class#nullableInstanceField#isSet}) {
+      final core::int? #t12 = (let final core::int #t13 = this.{self::Class::nullableInstanceFieldReads} in let final core::int #t14 = this.{self::Class::nullableInstanceFieldReads} = #t13.{core::num::+}(1) in #t13).{core::num::==}(0) ?{core::int?} this.{self::Class::nullableInstanceField} : ini::computeInitialValue();
+      if(this.{self::Class::_#Class#nullableInstanceField#isSet})
+        throw new _in::LateInitializationErrorImpl::•("Field 'nullableInstanceField' has been assigned during initialization.");
+      this.{self::Class::_#Class#nullableInstanceField} = #t12;
+      this.{self::Class::_#Class#nullableInstanceField#isSet} = true;
+    }
+    return this.{self::Class::_#Class#nullableInstanceField};
+  }
+}
+static field core::int nonNullableTopLevelFieldReads = 0;
+static field core::int? _#nonNullableTopLevelField = null;
+static field core::int nullableTopLevelFieldReads = 0;
+static field core::int? _#nullableTopLevelField = null;
+static field core::bool _#nullableTopLevelField#isSet = false;
+static get nonNullableTopLevelField() → core::int
+  return let final core::int? #t15 = self::_#nonNullableTopLevelField in #t15.==(null) ?{core::int} let final core::int #t16 = (let final core::int #t17 = self::nonNullableTopLevelFieldReads in let final core::int #t18 = self::nonNullableTopLevelFieldReads = #t17.{core::num::+}(1) in #t17).{core::num::==}(0) ?{core::int} self::nonNullableTopLevelField : ini::computeInitialValue() in self::_#nonNullableTopLevelField.==(null) ?{core::int} self::_#nonNullableTopLevelField = #t16 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableTopLevelField' has been assigned during initialization.") : #t15{core::int};
+static get nullableTopLevelField() → core::int? {
+  if(!self::_#nullableTopLevelField#isSet) {
+    final core::int? #t19 = (let final core::int #t20 = self::nullableTopLevelFieldReads in let final core::int #t21 = self::nullableTopLevelFieldReads = #t20.{core::num::+}(1) in #t20).{core::num::==}(0) ?{core::int?} self::nullableTopLevelField : ini::computeInitialValue();
+    if(self::_#nullableTopLevelField#isSet)
+      throw new _in::LateInitializationErrorImpl::•("Field 'nullableTopLevelField' has been assigned during initialization.");
+    self::_#nullableTopLevelField = #t19;
+    self::_#nullableTopLevelField#isSet = true;
+  }
+  return self::_#nullableTopLevelField;
+}
+static method main() → void {
+  self::throws(() → core::int => self::nonNullableTopLevelField, "Read nonNullableTopLevelField");
+  self::throws(() → core::int? => self::nullableTopLevelField, "Read nullableTopLevelField");
+  self::throws(() → core::int => self::Class::nonNullableStaticField, "Read nonNullableStaticField");
+  self::throws(() → core::int? => self::Class::nullableStaticField, "Read nullableStaticField");
+  self::throws(() → core::int => new self::Class::•().{self::Class::nonNullableInstanceField}, "Read nonNullableInstanceField");
+  self::throws(() → core::int? => new self::Class::•().{self::Class::nullableInstanceField}, "Read nullableInstanceField");
+}
+static method throws(() → dynamic f, core::String message) → dynamic {
+  dynamic value;
+  try {
+    value = f.call();
+  }
+  on core::LateInitializationError catch(final core::LateInitializationError e) {
+    core::print(e);
+    return;
+  }
+  throw "${message}: ${value}";
+}
+
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out_lib.dart:5:1: Error: A library can't opt out of null safety by default, when using sound null safety.
+// // @dart=2.8
+// ^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out_lib.dart:7:30: Error: A value of type 'Null' can't be returned from a function with return type 'int'.
+// int computeInitialValue() => null;
+//                              ^
+//
+import self as ini;
+import "dart:core" as core;
+
+static method computeInitialValue() → core::int
+  return let final<BottomType> #t22 = invalid-expression "pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out_lib.dart:7:30: Error: A value of type 'Null' can't be returned from a function with return type 'int'.
+int computeInitialValue() => null;
+                             ^" in null as{TypeError,ForNonNullableByDefault} core::int;
diff --git a/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart.strong.transformed.expect
new file mode 100644
index 0000000..e653691
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart.strong.transformed.expect
@@ -0,0 +1,103 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "initializer_rewrite_from_opt_out_lib.dart" as ini;
+import "dart:_internal" as _in;
+
+import "org-dartlang-testcase:///initializer_rewrite_from_opt_out_lib.dart";
+
+class Class extends core::Object {
+  static field core::int nonNullableStaticFieldReads = 0;
+  static field core::int? _#nonNullableStaticField = null;
+  static field core::int nullableStaticFieldReads = 0;
+  static field core::int? _#nullableStaticField = null;
+  static field core::bool _#nullableStaticField#isSet = false;
+  field core::int nonNullableInstanceFieldReads = 0;
+  field core::int? _#Class#nonNullableInstanceField = null;
+  field core::int nullableInstanceFieldReads = 0;
+  field core::int? _#Class#nullableInstanceField = null;
+  field core::bool _#Class#nullableInstanceField#isSet = false;
+  synthetic constructor •() → self::Class
+    : super core::Object::•()
+    ;
+  static get nonNullableStaticField() → core::int
+    return let final core::int? #t1 = self::Class::_#nonNullableStaticField in #t1.==(null) ?{core::int} let final core::int #t2 = (let final core::int #t3 = self::Class::nonNullableStaticFieldReads in let final core::int #t4 = self::Class::nonNullableStaticFieldReads = #t3.{core::num::+}(1) in #t3).{core::num::==}(0) ?{core::int} self::Class::nonNullableStaticField : ini::computeInitialValue() in self::Class::_#nonNullableStaticField.==(null) ?{core::int} self::Class::_#nonNullableStaticField = #t2 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableStaticField' has been assigned during initialization.") : #t1{core::int};
+  static get nullableStaticField() → core::int? {
+    if(!self::Class::_#nullableStaticField#isSet) {
+      final core::int? #t5 = (let final core::int #t6 = self::Class::nullableStaticFieldReads in let final core::int #t7 = self::Class::nullableStaticFieldReads = #t6.{core::num::+}(1) in #t6).{core::num::==}(0) ?{core::int?} self::Class::nullableStaticField : ini::computeInitialValue();
+      if(self::Class::_#nullableStaticField#isSet)
+        throw new _in::LateInitializationErrorImpl::•("Field 'nullableStaticField' has been assigned during initialization.");
+      self::Class::_#nullableStaticField = #t5;
+      self::Class::_#nullableStaticField#isSet = true;
+    }
+    return self::Class::_#nullableStaticField;
+  }
+  get nonNullableInstanceField() → core::int
+    return let final core::int? #t8 = this.{self::Class::_#Class#nonNullableInstanceField} in #t8.==(null) ?{core::int} let final core::int #t9 = (let final core::int #t10 = this.{self::Class::nonNullableInstanceFieldReads} in let final core::int #t11 = this.{self::Class::nonNullableInstanceFieldReads} = #t10.{core::num::+}(1) in #t10).{core::num::==}(0) ?{core::int} this.{self::Class::nonNullableInstanceField} : ini::computeInitialValue() in this.{self::Class::_#Class#nonNullableInstanceField}.==(null) ?{core::int} this.{self::Class::_#Class#nonNullableInstanceField} = #t9 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableInstanceField' has been assigned during initialization.") : #t8{core::int};
+  get nullableInstanceField() → core::int? {
+    if(!this.{self::Class::_#Class#nullableInstanceField#isSet}) {
+      final core::int? #t12 = (let final core::int #t13 = this.{self::Class::nullableInstanceFieldReads} in let final core::int #t14 = this.{self::Class::nullableInstanceFieldReads} = #t13.{core::num::+}(1) in #t13).{core::num::==}(0) ?{core::int?} this.{self::Class::nullableInstanceField} : ini::computeInitialValue();
+      if(this.{self::Class::_#Class#nullableInstanceField#isSet})
+        throw new _in::LateInitializationErrorImpl::•("Field 'nullableInstanceField' has been assigned during initialization.");
+      this.{self::Class::_#Class#nullableInstanceField} = #t12;
+      this.{self::Class::_#Class#nullableInstanceField#isSet} = true;
+    }
+    return this.{self::Class::_#Class#nullableInstanceField};
+  }
+}
+static field core::int nonNullableTopLevelFieldReads = 0;
+static field core::int? _#nonNullableTopLevelField = null;
+static field core::int nullableTopLevelFieldReads = 0;
+static field core::int? _#nullableTopLevelField = null;
+static field core::bool _#nullableTopLevelField#isSet = false;
+static get nonNullableTopLevelField() → core::int
+  return let final core::int? #t15 = self::_#nonNullableTopLevelField in #t15.==(null) ?{core::int} let final core::int #t16 = (let final core::int #t17 = self::nonNullableTopLevelFieldReads in let final core::int #t18 = self::nonNullableTopLevelFieldReads = #t17.{core::num::+}(1) in #t17).{core::num::==}(0) ?{core::int} self::nonNullableTopLevelField : ini::computeInitialValue() in self::_#nonNullableTopLevelField.==(null) ?{core::int} self::_#nonNullableTopLevelField = #t16 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableTopLevelField' has been assigned during initialization.") : #t15{core::int};
+static get nullableTopLevelField() → core::int? {
+  if(!self::_#nullableTopLevelField#isSet) {
+    final core::int? #t19 = (let final core::int #t20 = self::nullableTopLevelFieldReads in let final core::int #t21 = self::nullableTopLevelFieldReads = #t20.{core::num::+}(1) in #t20).{core::num::==}(0) ?{core::int?} self::nullableTopLevelField : ini::computeInitialValue();
+    if(self::_#nullableTopLevelField#isSet)
+      throw new _in::LateInitializationErrorImpl::•("Field 'nullableTopLevelField' has been assigned during initialization.");
+    self::_#nullableTopLevelField = #t19;
+    self::_#nullableTopLevelField#isSet = true;
+  }
+  return self::_#nullableTopLevelField;
+}
+static method main() → void {
+  self::throws(() → core::int => self::nonNullableTopLevelField, "Read nonNullableTopLevelField");
+  self::throws(() → core::int? => self::nullableTopLevelField, "Read nullableTopLevelField");
+  self::throws(() → core::int => self::Class::nonNullableStaticField, "Read nonNullableStaticField");
+  self::throws(() → core::int? => self::Class::nullableStaticField, "Read nullableStaticField");
+  self::throws(() → core::int => new self::Class::•().{self::Class::nonNullableInstanceField}, "Read nonNullableInstanceField");
+  self::throws(() → core::int? => new self::Class::•().{self::Class::nullableInstanceField}, "Read nullableInstanceField");
+}
+static method throws(() → dynamic f, core::String message) → dynamic {
+  dynamic value;
+  try {
+    value = f.call();
+  }
+  on core::LateInitializationError catch(final core::LateInitializationError e) {
+    core::print(e);
+    return;
+  }
+  throw "${message}: ${value}";
+}
+
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out_lib.dart:5:1: Error: A library can't opt out of null safety by default, when using sound null safety.
+// // @dart=2.8
+// ^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out_lib.dart:7:30: Error: A value of type 'Null' can't be returned from a function with return type 'int'.
+// int computeInitialValue() => null;
+//                              ^
+//
+import self as ini;
+import "dart:core" as core;
+
+static method computeInitialValue() → core::int
+  return let final<BottomType> #t22 = invalid-expression "pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out_lib.dart:7:30: Error: A value of type 'Null' can't be returned from a function with return type 'int'.
+int computeInitialValue() => null;
+                             ^" in let core::Null? #t23 = null in #t23.==(null) ?{core::int} #t23 as{TypeError,ForNonNullableByDefault} core::int : #t23{core::int};
diff --git a/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart.textual_outline.expect b/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart.textual_outline.expect
new file mode 100644
index 0000000..181da77
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart.textual_outline.expect
@@ -0,0 +1,23 @@
+import 'initializer_rewrite_from_opt_out_lib.dart';
+int nonNullableTopLevelFieldReads = 0;
+late ;
+final int nonNullableTopLevelField = nonNullableTopLevelFieldReads++ == 0 ? nonNullableTopLevelField : computeInitialValue();
+int nullableTopLevelFieldReads = 0;
+late ;
+final int? nullableTopLevelField = nullableTopLevelFieldReads++ == 0 ? nullableTopLevelField : computeInitialValue();
+class Class {
+  static int nonNullableStaticFieldReads = 0;
+  static late ;
+  final int nonNullableStaticField = nonNullableStaticFieldReads++ == 0 ? nonNullableStaticField : computeInitialValue();
+  static int nullableStaticFieldReads = 0;
+  static late ;
+  final int? nullableStaticField = nullableStaticFieldReads++ == 0 ? nullableStaticField : computeInitialValue();
+  int nonNullableInstanceFieldReads = 0;
+  late ;
+  final int nonNullableInstanceField = nonNullableInstanceFieldReads++ == 0 ? nonNullableInstanceField : computeInitialValue();
+  int nullableInstanceFieldReads = 0;
+  late ;
+  final int? nullableInstanceField = nullableInstanceFieldReads++ == 0 ? nullableInstanceField : computeInitialValue();
+}
+void main() {}
+throws(f(), String message) {}
diff --git a/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart.weak.expect b/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart.weak.expect
new file mode 100644
index 0000000..d58daaa
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart.weak.expect
@@ -0,0 +1,117 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "initializer_rewrite_from_opt_out_lib.dart" as ini;
+import "dart:_internal" as _in;
+
+import "org-dartlang-testcase:///initializer_rewrite_from_opt_out_lib.dart";
+
+class Class extends core::Object {
+  static field core::int nonNullableStaticFieldReads = 0;
+  static field core::int? _#nonNullableStaticField = null;
+  static field core::bool _#nonNullableStaticField#isSet = false;
+  static field core::int nullableStaticFieldReads = 0;
+  static field core::int? _#nullableStaticField = null;
+  static field core::bool _#nullableStaticField#isSet = false;
+  field core::int nonNullableInstanceFieldReads = 0;
+  field core::int? _#Class#nonNullableInstanceField = null;
+  field core::bool _#Class#nonNullableInstanceField#isSet = false;
+  field core::int nullableInstanceFieldReads = 0;
+  field core::int? _#Class#nullableInstanceField = null;
+  field core::bool _#Class#nullableInstanceField#isSet = false;
+  synthetic constructor •() → self::Class
+    : super core::Object::•()
+    ;
+  static get nonNullableStaticField() → core::int {
+    if(!self::Class::_#nonNullableStaticField#isSet) {
+      final core::int #t1 = (let final core::int #t2 = self::Class::nonNullableStaticFieldReads in let final core::int #t3 = self::Class::nonNullableStaticFieldReads = #t2.{core::num::+}(1) in #t2).{core::num::==}(0) ?{core::int*} self::Class::nonNullableStaticField : ini::computeInitialValue();
+      if(self::Class::_#nonNullableStaticField#isSet)
+        throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableStaticField' has been assigned during initialization.");
+      self::Class::_#nonNullableStaticField = #t1;
+      self::Class::_#nonNullableStaticField#isSet = true;
+    }
+    return let final core::int? #t4 = self::Class::_#nonNullableStaticField in #t4{core::int};
+  }
+  static get nullableStaticField() → core::int? {
+    if(!self::Class::_#nullableStaticField#isSet) {
+      final core::int? #t5 = (let final core::int #t6 = self::Class::nullableStaticFieldReads in let final core::int #t7 = self::Class::nullableStaticFieldReads = #t6.{core::num::+}(1) in #t6).{core::num::==}(0) ?{core::int?} self::Class::nullableStaticField : ini::computeInitialValue();
+      if(self::Class::_#nullableStaticField#isSet)
+        throw new _in::LateInitializationErrorImpl::•("Field 'nullableStaticField' has been assigned during initialization.");
+      self::Class::_#nullableStaticField = #t5;
+      self::Class::_#nullableStaticField#isSet = true;
+    }
+    return self::Class::_#nullableStaticField;
+  }
+  get nonNullableInstanceField() → core::int {
+    if(!this.{self::Class::_#Class#nonNullableInstanceField#isSet}) {
+      final core::int #t8 = (let final core::int #t9 = this.{self::Class::nonNullableInstanceFieldReads} in let final core::int #t10 = this.{self::Class::nonNullableInstanceFieldReads} = #t9.{core::num::+}(1) in #t9).{core::num::==}(0) ?{core::int*} this.{self::Class::nonNullableInstanceField} : ini::computeInitialValue();
+      if(this.{self::Class::_#Class#nonNullableInstanceField#isSet})
+        throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableInstanceField' has been assigned during initialization.");
+      this.{self::Class::_#Class#nonNullableInstanceField} = #t8;
+      this.{self::Class::_#Class#nonNullableInstanceField#isSet} = true;
+    }
+    return let final core::int? #t11 = this.{self::Class::_#Class#nonNullableInstanceField} in #t11{core::int};
+  }
+  get nullableInstanceField() → core::int? {
+    if(!this.{self::Class::_#Class#nullableInstanceField#isSet}) {
+      final core::int? #t12 = (let final core::int #t13 = this.{self::Class::nullableInstanceFieldReads} in let final core::int #t14 = this.{self::Class::nullableInstanceFieldReads} = #t13.{core::num::+}(1) in #t13).{core::num::==}(0) ?{core::int?} this.{self::Class::nullableInstanceField} : ini::computeInitialValue();
+      if(this.{self::Class::_#Class#nullableInstanceField#isSet})
+        throw new _in::LateInitializationErrorImpl::•("Field 'nullableInstanceField' has been assigned during initialization.");
+      this.{self::Class::_#Class#nullableInstanceField} = #t12;
+      this.{self::Class::_#Class#nullableInstanceField#isSet} = true;
+    }
+    return this.{self::Class::_#Class#nullableInstanceField};
+  }
+}
+static field core::int nonNullableTopLevelFieldReads = 0;
+static field core::int? _#nonNullableTopLevelField = null;
+static field core::bool _#nonNullableTopLevelField#isSet = false;
+static field core::int nullableTopLevelFieldReads = 0;
+static field core::int? _#nullableTopLevelField = null;
+static field core::bool _#nullableTopLevelField#isSet = false;
+static get nonNullableTopLevelField() → core::int {
+  if(!self::_#nonNullableTopLevelField#isSet) {
+    final core::int #t15 = (let final core::int #t16 = self::nonNullableTopLevelFieldReads in let final core::int #t17 = self::nonNullableTopLevelFieldReads = #t16.{core::num::+}(1) in #t16).{core::num::==}(0) ?{core::int*} self::nonNullableTopLevelField : ini::computeInitialValue();
+    if(self::_#nonNullableTopLevelField#isSet)
+      throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableTopLevelField' has been assigned during initialization.");
+    self::_#nonNullableTopLevelField = #t15;
+    self::_#nonNullableTopLevelField#isSet = true;
+  }
+  return let final core::int? #t18 = self::_#nonNullableTopLevelField in #t18{core::int};
+}
+static get nullableTopLevelField() → core::int? {
+  if(!self::_#nullableTopLevelField#isSet) {
+    final core::int? #t19 = (let final core::int #t20 = self::nullableTopLevelFieldReads in let final core::int #t21 = self::nullableTopLevelFieldReads = #t20.{core::num::+}(1) in #t20).{core::num::==}(0) ?{core::int?} self::nullableTopLevelField : ini::computeInitialValue();
+    if(self::_#nullableTopLevelField#isSet)
+      throw new _in::LateInitializationErrorImpl::•("Field 'nullableTopLevelField' has been assigned during initialization.");
+    self::_#nullableTopLevelField = #t19;
+    self::_#nullableTopLevelField#isSet = true;
+  }
+  return self::_#nullableTopLevelField;
+}
+static method main() → void {
+  self::throws(() → core::int => self::nonNullableTopLevelField, "Read nonNullableTopLevelField");
+  self::throws(() → core::int? => self::nullableTopLevelField, "Read nullableTopLevelField");
+  self::throws(() → core::int => self::Class::nonNullableStaticField, "Read nonNullableStaticField");
+  self::throws(() → core::int? => self::Class::nullableStaticField, "Read nullableStaticField");
+  self::throws(() → core::int => new self::Class::•().{self::Class::nonNullableInstanceField}, "Read nonNullableInstanceField");
+  self::throws(() → core::int? => new self::Class::•().{self::Class::nullableInstanceField}, "Read nullableInstanceField");
+}
+static method throws(() → dynamic f, core::String message) → dynamic {
+  dynamic value;
+  try {
+    value = f.call();
+  }
+  on core::LateInitializationError catch(final core::LateInitializationError e) {
+    core::print(e);
+    return;
+  }
+  throw "${message}: ${value}";
+}
+
+library;
+import self as ini;
+import "dart:core" as core;
+
+static method computeInitialValue() → core::int*
+  return null;
diff --git a/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart.weak.transformed.expect
new file mode 100644
index 0000000..d58daaa
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out.dart.weak.transformed.expect
@@ -0,0 +1,117 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "initializer_rewrite_from_opt_out_lib.dart" as ini;
+import "dart:_internal" as _in;
+
+import "org-dartlang-testcase:///initializer_rewrite_from_opt_out_lib.dart";
+
+class Class extends core::Object {
+  static field core::int nonNullableStaticFieldReads = 0;
+  static field core::int? _#nonNullableStaticField = null;
+  static field core::bool _#nonNullableStaticField#isSet = false;
+  static field core::int nullableStaticFieldReads = 0;
+  static field core::int? _#nullableStaticField = null;
+  static field core::bool _#nullableStaticField#isSet = false;
+  field core::int nonNullableInstanceFieldReads = 0;
+  field core::int? _#Class#nonNullableInstanceField = null;
+  field core::bool _#Class#nonNullableInstanceField#isSet = false;
+  field core::int nullableInstanceFieldReads = 0;
+  field core::int? _#Class#nullableInstanceField = null;
+  field core::bool _#Class#nullableInstanceField#isSet = false;
+  synthetic constructor •() → self::Class
+    : super core::Object::•()
+    ;
+  static get nonNullableStaticField() → core::int {
+    if(!self::Class::_#nonNullableStaticField#isSet) {
+      final core::int #t1 = (let final core::int #t2 = self::Class::nonNullableStaticFieldReads in let final core::int #t3 = self::Class::nonNullableStaticFieldReads = #t2.{core::num::+}(1) in #t2).{core::num::==}(0) ?{core::int*} self::Class::nonNullableStaticField : ini::computeInitialValue();
+      if(self::Class::_#nonNullableStaticField#isSet)
+        throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableStaticField' has been assigned during initialization.");
+      self::Class::_#nonNullableStaticField = #t1;
+      self::Class::_#nonNullableStaticField#isSet = true;
+    }
+    return let final core::int? #t4 = self::Class::_#nonNullableStaticField in #t4{core::int};
+  }
+  static get nullableStaticField() → core::int? {
+    if(!self::Class::_#nullableStaticField#isSet) {
+      final core::int? #t5 = (let final core::int #t6 = self::Class::nullableStaticFieldReads in let final core::int #t7 = self::Class::nullableStaticFieldReads = #t6.{core::num::+}(1) in #t6).{core::num::==}(0) ?{core::int?} self::Class::nullableStaticField : ini::computeInitialValue();
+      if(self::Class::_#nullableStaticField#isSet)
+        throw new _in::LateInitializationErrorImpl::•("Field 'nullableStaticField' has been assigned during initialization.");
+      self::Class::_#nullableStaticField = #t5;
+      self::Class::_#nullableStaticField#isSet = true;
+    }
+    return self::Class::_#nullableStaticField;
+  }
+  get nonNullableInstanceField() → core::int {
+    if(!this.{self::Class::_#Class#nonNullableInstanceField#isSet}) {
+      final core::int #t8 = (let final core::int #t9 = this.{self::Class::nonNullableInstanceFieldReads} in let final core::int #t10 = this.{self::Class::nonNullableInstanceFieldReads} = #t9.{core::num::+}(1) in #t9).{core::num::==}(0) ?{core::int*} this.{self::Class::nonNullableInstanceField} : ini::computeInitialValue();
+      if(this.{self::Class::_#Class#nonNullableInstanceField#isSet})
+        throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableInstanceField' has been assigned during initialization.");
+      this.{self::Class::_#Class#nonNullableInstanceField} = #t8;
+      this.{self::Class::_#Class#nonNullableInstanceField#isSet} = true;
+    }
+    return let final core::int? #t11 = this.{self::Class::_#Class#nonNullableInstanceField} in #t11{core::int};
+  }
+  get nullableInstanceField() → core::int? {
+    if(!this.{self::Class::_#Class#nullableInstanceField#isSet}) {
+      final core::int? #t12 = (let final core::int #t13 = this.{self::Class::nullableInstanceFieldReads} in let final core::int #t14 = this.{self::Class::nullableInstanceFieldReads} = #t13.{core::num::+}(1) in #t13).{core::num::==}(0) ?{core::int?} this.{self::Class::nullableInstanceField} : ini::computeInitialValue();
+      if(this.{self::Class::_#Class#nullableInstanceField#isSet})
+        throw new _in::LateInitializationErrorImpl::•("Field 'nullableInstanceField' has been assigned during initialization.");
+      this.{self::Class::_#Class#nullableInstanceField} = #t12;
+      this.{self::Class::_#Class#nullableInstanceField#isSet} = true;
+    }
+    return this.{self::Class::_#Class#nullableInstanceField};
+  }
+}
+static field core::int nonNullableTopLevelFieldReads = 0;
+static field core::int? _#nonNullableTopLevelField = null;
+static field core::bool _#nonNullableTopLevelField#isSet = false;
+static field core::int nullableTopLevelFieldReads = 0;
+static field core::int? _#nullableTopLevelField = null;
+static field core::bool _#nullableTopLevelField#isSet = false;
+static get nonNullableTopLevelField() → core::int {
+  if(!self::_#nonNullableTopLevelField#isSet) {
+    final core::int #t15 = (let final core::int #t16 = self::nonNullableTopLevelFieldReads in let final core::int #t17 = self::nonNullableTopLevelFieldReads = #t16.{core::num::+}(1) in #t16).{core::num::==}(0) ?{core::int*} self::nonNullableTopLevelField : ini::computeInitialValue();
+    if(self::_#nonNullableTopLevelField#isSet)
+      throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableTopLevelField' has been assigned during initialization.");
+    self::_#nonNullableTopLevelField = #t15;
+    self::_#nonNullableTopLevelField#isSet = true;
+  }
+  return let final core::int? #t18 = self::_#nonNullableTopLevelField in #t18{core::int};
+}
+static get nullableTopLevelField() → core::int? {
+  if(!self::_#nullableTopLevelField#isSet) {
+    final core::int? #t19 = (let final core::int #t20 = self::nullableTopLevelFieldReads in let final core::int #t21 = self::nullableTopLevelFieldReads = #t20.{core::num::+}(1) in #t20).{core::num::==}(0) ?{core::int?} self::nullableTopLevelField : ini::computeInitialValue();
+    if(self::_#nullableTopLevelField#isSet)
+      throw new _in::LateInitializationErrorImpl::•("Field 'nullableTopLevelField' has been assigned during initialization.");
+    self::_#nullableTopLevelField = #t19;
+    self::_#nullableTopLevelField#isSet = true;
+  }
+  return self::_#nullableTopLevelField;
+}
+static method main() → void {
+  self::throws(() → core::int => self::nonNullableTopLevelField, "Read nonNullableTopLevelField");
+  self::throws(() → core::int? => self::nullableTopLevelField, "Read nullableTopLevelField");
+  self::throws(() → core::int => self::Class::nonNullableStaticField, "Read nonNullableStaticField");
+  self::throws(() → core::int? => self::Class::nullableStaticField, "Read nullableStaticField");
+  self::throws(() → core::int => new self::Class::•().{self::Class::nonNullableInstanceField}, "Read nonNullableInstanceField");
+  self::throws(() → core::int? => new self::Class::•().{self::Class::nullableInstanceField}, "Read nullableInstanceField");
+}
+static method throws(() → dynamic f, core::String message) → dynamic {
+  dynamic value;
+  try {
+    value = f.call();
+  }
+  on core::LateInitializationError catch(final core::LateInitializationError e) {
+    core::print(e);
+    return;
+  }
+  throw "${message}: ${value}";
+}
+
+library;
+import self as ini;
+import "dart:core" as core;
+
+static method computeInitialValue() → core::int*
+  return null;
diff --git a/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out_lib.dart b/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out_lib.dart
new file mode 100644
index 0000000..7a87630
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/initializer_rewrite_from_opt_out_lib.dart
@@ -0,0 +1,7 @@
+// 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.
+
+// @dart=2.8
+
+int computeInitialValue() => null;
diff --git a/pkg/front_end/testcases/late_lowering/issue40373.dart.weak.expect b/pkg/front_end/testcases/late_lowering/issue40373.dart.weak.expect
index 266abad..3fc2e39 100644
--- a/pkg/front_end/testcases/late_lowering/issue40373.dart.weak.expect
+++ b/pkg/front_end/testcases/late_lowering/issue40373.dart.weak.expect
@@ -23,8 +23,16 @@
     this.{self::C::_#C#p1#isSet} = true;
     this.{self::C::_#C#p1} = #t2;
   }
-  get p2() → core::num
-    return let final core::num? #t3 = this.{self::C::_#C#p2} in #t3.==(null) ?{core::num} let final core::num #t4 = this.{self::C::pi} in this.{self::C::_#C#p2}.==(null) ?{core::num} this.{self::C::_#C#p2} = #t4 : throw new _in::LateInitializationErrorImpl::•("Field 'p2' has been assigned during initialization.") : #t3{core::num};
+  get p2() → core::num {
+    if(!this.{self::C::_#C#p2#isSet}) {
+      final core::num #t3 = this.{self::C::pi};
+      if(this.{self::C::_#C#p2#isSet})
+        throw new _in::LateInitializationErrorImpl::•("Field 'p2' has been assigned during initialization.");
+      this.{self::C::_#C#p2} = #t3;
+      this.{self::C::_#C#p2#isSet} = true;
+    }
+    return let final core::num? #t4 = this.{self::C::_#C#p2} in #t4{core::num};
+  }
 }
 static method main() → dynamic {
   self::expect(3.14, new self::C::•().{self::C::p1});
diff --git a/pkg/front_end/testcases/late_lowering/issue40373.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering/issue40373.dart.weak.transformed.expect
index 266abad..3fc2e39 100644
--- a/pkg/front_end/testcases/late_lowering/issue40373.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/issue40373.dart.weak.transformed.expect
@@ -23,8 +23,16 @@
     this.{self::C::_#C#p1#isSet} = true;
     this.{self::C::_#C#p1} = #t2;
   }
-  get p2() → core::num
-    return let final core::num? #t3 = this.{self::C::_#C#p2} in #t3.==(null) ?{core::num} let final core::num #t4 = this.{self::C::pi} in this.{self::C::_#C#p2}.==(null) ?{core::num} this.{self::C::_#C#p2} = #t4 : throw new _in::LateInitializationErrorImpl::•("Field 'p2' has been assigned during initialization.") : #t3{core::num};
+  get p2() → core::num {
+    if(!this.{self::C::_#C#p2#isSet}) {
+      final core::num #t3 = this.{self::C::pi};
+      if(this.{self::C::_#C#p2#isSet})
+        throw new _in::LateInitializationErrorImpl::•("Field 'p2' has been assigned during initialization.");
+      this.{self::C::_#C#p2} = #t3;
+      this.{self::C::_#C#p2#isSet} = true;
+    }
+    return let final core::num? #t4 = this.{self::C::_#C#p2} in #t4{core::num};
+  }
 }
 static method main() → dynamic {
   self::expect(3.14, new self::C::•().{self::C::p1});
diff --git a/pkg/front_end/testcases/late_lowering/late_annotations.dart.weak.expect b/pkg/front_end/testcases/late_lowering/late_annotations.dart.weak.expect
index 671dae2..89e5a3a 100644
--- a/pkg/front_end/testcases/late_lowering/late_annotations.dart.weak.expect
+++ b/pkg/front_end/testcases/late_lowering/late_annotations.dart.weak.expect
@@ -46,8 +46,16 @@
       this.{self::A::_#A#finalInstanceField} = #t4;
     }
   @#C1
-  get finalInstanceFieldWithInitializer() → core::int
-    return let final core::int? #t5 = this.{self::A::_#A#finalInstanceFieldWithInitializer} in #t5.==(null) ?{core::int} let final core::int #t6 = 0 in this.{self::A::_#A#finalInstanceFieldWithInitializer}.==(null) ?{core::int} this.{self::A::_#A#finalInstanceFieldWithInitializer} = #t6 : throw new _in::LateInitializationErrorImpl::•("Field 'finalInstanceFieldWithInitializer' has been assigned during initialization.") : #t5{core::int};
+  get finalInstanceFieldWithInitializer() → core::int {
+    if(!this.{self::A::_#A#finalInstanceFieldWithInitializer#isSet}) {
+      final core::int #t5 = 0;
+      if(this.{self::A::_#A#finalInstanceFieldWithInitializer#isSet})
+        throw new _in::LateInitializationErrorImpl::•("Field 'finalInstanceFieldWithInitializer' has been assigned during initialization.");
+      this.{self::A::_#A#finalInstanceFieldWithInitializer} = #t5;
+      this.{self::A::_#A#finalInstanceFieldWithInitializer#isSet} = true;
+    }
+    return let final core::int? #t6 = this.{self::A::_#A#finalInstanceFieldWithInitializer} in #t6{core::int};
+  }
   @#C1
   get covariantInstanceField() → core::num
     return this.{self::A::_#A#covariantInstanceField#isSet} ?{core::num} let final core::num? #t7 = this.{self::A::_#A#covariantInstanceField} in #t7{core::num} : throw new _in::LateInitializationErrorImpl::•("Field 'covariantInstanceField' has not been initialized.");
@@ -76,8 +84,16 @@
       self::A::_#finalStaticField = #t12;
     }
   @#C1
-  static get finalStaticFieldWithInitializer() → core::int
-    return let final core::int? #t13 = self::A::_#finalStaticFieldWithInitializer in #t13.==(null) ?{core::int} let final core::int #t14 = 0 in self::A::_#finalStaticFieldWithInitializer.==(null) ?{core::int} self::A::_#finalStaticFieldWithInitializer = #t14 : throw new _in::LateInitializationErrorImpl::•("Field 'finalStaticFieldWithInitializer' has been assigned during initialization.") : #t13{core::int};
+  static get finalStaticFieldWithInitializer() → core::int {
+    if(!self::A::_#finalStaticFieldWithInitializer#isSet) {
+      final core::int #t13 = 0;
+      if(self::A::_#finalStaticFieldWithInitializer#isSet)
+        throw new _in::LateInitializationErrorImpl::•("Field 'finalStaticFieldWithInitializer' has been assigned during initialization.");
+      self::A::_#finalStaticFieldWithInitializer = #t13;
+      self::A::_#finalStaticFieldWithInitializer#isSet = true;
+    }
+    return let final core::int? #t14 = self::A::_#finalStaticFieldWithInitializer in #t14{core::int};
+  }
 }
 abstract class B extends core::Object /*isMixinDeclaration*/  {
   field core::int? _#B#instanceField = null;
@@ -114,8 +130,16 @@
       this.{self::B::_#B#finalInstanceField} = #t18;
     }
   @#C1
-  get finalInstanceFieldWithInitializer() → core::int
-    return let final core::int? #t19 = this.{self::B::_#B#finalInstanceFieldWithInitializer} in #t19.==(null) ?{core::int} let final core::int #t20 = 0 in this.{self::B::_#B#finalInstanceFieldWithInitializer}.==(null) ?{core::int} this.{self::B::_#B#finalInstanceFieldWithInitializer} = #t20 : throw new _in::LateInitializationErrorImpl::•("Field 'finalInstanceFieldWithInitializer' has been assigned during initialization.") : #t19{core::int};
+  get finalInstanceFieldWithInitializer() → core::int {
+    if(!this.{self::B::_#B#finalInstanceFieldWithInitializer#isSet}) {
+      final core::int #t19 = 0;
+      if(this.{self::B::_#B#finalInstanceFieldWithInitializer#isSet})
+        throw new _in::LateInitializationErrorImpl::•("Field 'finalInstanceFieldWithInitializer' has been assigned during initialization.");
+      this.{self::B::_#B#finalInstanceFieldWithInitializer} = #t19;
+      this.{self::B::_#B#finalInstanceFieldWithInitializer#isSet} = true;
+    }
+    return let final core::int? #t20 = this.{self::B::_#B#finalInstanceFieldWithInitializer} in #t20{core::int};
+  }
   @#C1
   get covariantInstanceField() → core::num
     return this.{self::B::_#B#covariantInstanceField#isSet} ?{core::num} let final core::num? #t21 = this.{self::B::_#B#covariantInstanceField} in #t21{core::num} : throw new _in::LateInitializationErrorImpl::•("Field 'covariantInstanceField' has not been initialized.");
@@ -144,8 +168,16 @@
       self::B::_#finalStaticField = #t26;
     }
   @#C1
-  static get finalStaticFieldWithInitializer() → core::int
-    return let final core::int? #t27 = self::B::_#finalStaticFieldWithInitializer in #t27.==(null) ?{core::int} let final core::int #t28 = 0 in self::B::_#finalStaticFieldWithInitializer.==(null) ?{core::int} self::B::_#finalStaticFieldWithInitializer = #t28 : throw new _in::LateInitializationErrorImpl::•("Field 'finalStaticFieldWithInitializer' has been assigned during initialization.") : #t27{core::int};
+  static get finalStaticFieldWithInitializer() → core::int {
+    if(!self::B::_#finalStaticFieldWithInitializer#isSet) {
+      final core::int #t27 = 0;
+      if(self::B::_#finalStaticFieldWithInitializer#isSet)
+        throw new _in::LateInitializationErrorImpl::•("Field 'finalStaticFieldWithInitializer' has been assigned during initialization.");
+      self::B::_#finalStaticFieldWithInitializer = #t27;
+      self::B::_#finalStaticFieldWithInitializer#isSet = true;
+    }
+    return let final core::int? #t28 = self::B::_#finalStaticFieldWithInitializer in #t28{core::int};
+  }
 }
 extension Extension on self::A {
   static field extensionStaticField = self::_#Extension|extensionStaticField;
@@ -192,8 +224,16 @@
     self::_#finalTopLevelField = #t32;
   }
 @#C1
-static get finalTopLevelFieldWithInitializer() → core::int
-  return let final core::int? #t33 = self::_#finalTopLevelFieldWithInitializer in #t33.==(null) ?{core::int} let final core::int #t34 = 0 in self::_#finalTopLevelFieldWithInitializer.==(null) ?{core::int} self::_#finalTopLevelFieldWithInitializer = #t34 : throw new _in::LateInitializationErrorImpl::•("Field 'finalTopLevelFieldWithInitializer' has been assigned during initialization.") : #t33{core::int};
+static get finalTopLevelFieldWithInitializer() → core::int {
+  if(!self::_#finalTopLevelFieldWithInitializer#isSet) {
+    final core::int #t33 = 0;
+    if(self::_#finalTopLevelFieldWithInitializer#isSet)
+      throw new _in::LateInitializationErrorImpl::•("Field 'finalTopLevelFieldWithInitializer' has been assigned during initialization.");
+    self::_#finalTopLevelFieldWithInitializer = #t33;
+    self::_#finalTopLevelFieldWithInitializer#isSet = true;
+  }
+  return let final core::int? #t34 = self::_#finalTopLevelFieldWithInitializer in #t34{core::int};
+}
 @#C1
 static get Extension|extensionStaticField() → core::int
   return self::_#Extension|extensionStaticField#isSet ?{core::int} let final core::int? #t35 = self::_#Extension|extensionStaticField in #t35{core::int} : throw new _in::LateInitializationErrorImpl::•("Field 'extensionStaticField' has not been initialized.");
@@ -214,8 +254,16 @@
     self::_#Extension|finalExtensionStaticField = #t38;
   }
 @#C1
-static get Extension|finalExtensionStaticFieldWithInitializer() → core::int
-  return let final core::int? #t39 = self::_#Extension|finalExtensionStaticFieldWithInitializer in #t39.==(null) ?{core::int} let final core::int #t40 = 0 in self::_#Extension|finalExtensionStaticFieldWithInitializer.==(null) ?{core::int} self::_#Extension|finalExtensionStaticFieldWithInitializer = #t40 : throw new _in::LateInitializationErrorImpl::•("Field 'finalExtensionStaticFieldWithInitializer' has been assigned during initialization.") : #t39{core::int};
+static get Extension|finalExtensionStaticFieldWithInitializer() → core::int {
+  if(!self::_#Extension|finalExtensionStaticFieldWithInitializer#isSet) {
+    final core::int #t39 = 0;
+    if(self::_#Extension|finalExtensionStaticFieldWithInitializer#isSet)
+      throw new _in::LateInitializationErrorImpl::•("Field 'finalExtensionStaticFieldWithInitializer' has been assigned during initialization.");
+    self::_#Extension|finalExtensionStaticFieldWithInitializer = #t39;
+    self::_#Extension|finalExtensionStaticFieldWithInitializer#isSet = true;
+  }
+  return let final core::int? #t40 = self::_#Extension|finalExtensionStaticFieldWithInitializer in #t40{core::int};
+}
 static method main() → dynamic {}
 
 constants  {
diff --git a/pkg/front_end/testcases/late_lowering/late_annotations.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering/late_annotations.dart.weak.transformed.expect
index 671dae2..89e5a3a 100644
--- a/pkg/front_end/testcases/late_lowering/late_annotations.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/late_annotations.dart.weak.transformed.expect
@@ -46,8 +46,16 @@
       this.{self::A::_#A#finalInstanceField} = #t4;
     }
   @#C1
-  get finalInstanceFieldWithInitializer() → core::int
-    return let final core::int? #t5 = this.{self::A::_#A#finalInstanceFieldWithInitializer} in #t5.==(null) ?{core::int} let final core::int #t6 = 0 in this.{self::A::_#A#finalInstanceFieldWithInitializer}.==(null) ?{core::int} this.{self::A::_#A#finalInstanceFieldWithInitializer} = #t6 : throw new _in::LateInitializationErrorImpl::•("Field 'finalInstanceFieldWithInitializer' has been assigned during initialization.") : #t5{core::int};
+  get finalInstanceFieldWithInitializer() → core::int {
+    if(!this.{self::A::_#A#finalInstanceFieldWithInitializer#isSet}) {
+      final core::int #t5 = 0;
+      if(this.{self::A::_#A#finalInstanceFieldWithInitializer#isSet})
+        throw new _in::LateInitializationErrorImpl::•("Field 'finalInstanceFieldWithInitializer' has been assigned during initialization.");
+      this.{self::A::_#A#finalInstanceFieldWithInitializer} = #t5;
+      this.{self::A::_#A#finalInstanceFieldWithInitializer#isSet} = true;
+    }
+    return let final core::int? #t6 = this.{self::A::_#A#finalInstanceFieldWithInitializer} in #t6{core::int};
+  }
   @#C1
   get covariantInstanceField() → core::num
     return this.{self::A::_#A#covariantInstanceField#isSet} ?{core::num} let final core::num? #t7 = this.{self::A::_#A#covariantInstanceField} in #t7{core::num} : throw new _in::LateInitializationErrorImpl::•("Field 'covariantInstanceField' has not been initialized.");
@@ -76,8 +84,16 @@
       self::A::_#finalStaticField = #t12;
     }
   @#C1
-  static get finalStaticFieldWithInitializer() → core::int
-    return let final core::int? #t13 = self::A::_#finalStaticFieldWithInitializer in #t13.==(null) ?{core::int} let final core::int #t14 = 0 in self::A::_#finalStaticFieldWithInitializer.==(null) ?{core::int} self::A::_#finalStaticFieldWithInitializer = #t14 : throw new _in::LateInitializationErrorImpl::•("Field 'finalStaticFieldWithInitializer' has been assigned during initialization.") : #t13{core::int};
+  static get finalStaticFieldWithInitializer() → core::int {
+    if(!self::A::_#finalStaticFieldWithInitializer#isSet) {
+      final core::int #t13 = 0;
+      if(self::A::_#finalStaticFieldWithInitializer#isSet)
+        throw new _in::LateInitializationErrorImpl::•("Field 'finalStaticFieldWithInitializer' has been assigned during initialization.");
+      self::A::_#finalStaticFieldWithInitializer = #t13;
+      self::A::_#finalStaticFieldWithInitializer#isSet = true;
+    }
+    return let final core::int? #t14 = self::A::_#finalStaticFieldWithInitializer in #t14{core::int};
+  }
 }
 abstract class B extends core::Object /*isMixinDeclaration*/  {
   field core::int? _#B#instanceField = null;
@@ -114,8 +130,16 @@
       this.{self::B::_#B#finalInstanceField} = #t18;
     }
   @#C1
-  get finalInstanceFieldWithInitializer() → core::int
-    return let final core::int? #t19 = this.{self::B::_#B#finalInstanceFieldWithInitializer} in #t19.==(null) ?{core::int} let final core::int #t20 = 0 in this.{self::B::_#B#finalInstanceFieldWithInitializer}.==(null) ?{core::int} this.{self::B::_#B#finalInstanceFieldWithInitializer} = #t20 : throw new _in::LateInitializationErrorImpl::•("Field 'finalInstanceFieldWithInitializer' has been assigned during initialization.") : #t19{core::int};
+  get finalInstanceFieldWithInitializer() → core::int {
+    if(!this.{self::B::_#B#finalInstanceFieldWithInitializer#isSet}) {
+      final core::int #t19 = 0;
+      if(this.{self::B::_#B#finalInstanceFieldWithInitializer#isSet})
+        throw new _in::LateInitializationErrorImpl::•("Field 'finalInstanceFieldWithInitializer' has been assigned during initialization.");
+      this.{self::B::_#B#finalInstanceFieldWithInitializer} = #t19;
+      this.{self::B::_#B#finalInstanceFieldWithInitializer#isSet} = true;
+    }
+    return let final core::int? #t20 = this.{self::B::_#B#finalInstanceFieldWithInitializer} in #t20{core::int};
+  }
   @#C1
   get covariantInstanceField() → core::num
     return this.{self::B::_#B#covariantInstanceField#isSet} ?{core::num} let final core::num? #t21 = this.{self::B::_#B#covariantInstanceField} in #t21{core::num} : throw new _in::LateInitializationErrorImpl::•("Field 'covariantInstanceField' has not been initialized.");
@@ -144,8 +168,16 @@
       self::B::_#finalStaticField = #t26;
     }
   @#C1
-  static get finalStaticFieldWithInitializer() → core::int
-    return let final core::int? #t27 = self::B::_#finalStaticFieldWithInitializer in #t27.==(null) ?{core::int} let final core::int #t28 = 0 in self::B::_#finalStaticFieldWithInitializer.==(null) ?{core::int} self::B::_#finalStaticFieldWithInitializer = #t28 : throw new _in::LateInitializationErrorImpl::•("Field 'finalStaticFieldWithInitializer' has been assigned during initialization.") : #t27{core::int};
+  static get finalStaticFieldWithInitializer() → core::int {
+    if(!self::B::_#finalStaticFieldWithInitializer#isSet) {
+      final core::int #t27 = 0;
+      if(self::B::_#finalStaticFieldWithInitializer#isSet)
+        throw new _in::LateInitializationErrorImpl::•("Field 'finalStaticFieldWithInitializer' has been assigned during initialization.");
+      self::B::_#finalStaticFieldWithInitializer = #t27;
+      self::B::_#finalStaticFieldWithInitializer#isSet = true;
+    }
+    return let final core::int? #t28 = self::B::_#finalStaticFieldWithInitializer in #t28{core::int};
+  }
 }
 extension Extension on self::A {
   static field extensionStaticField = self::_#Extension|extensionStaticField;
@@ -192,8 +224,16 @@
     self::_#finalTopLevelField = #t32;
   }
 @#C1
-static get finalTopLevelFieldWithInitializer() → core::int
-  return let final core::int? #t33 = self::_#finalTopLevelFieldWithInitializer in #t33.==(null) ?{core::int} let final core::int #t34 = 0 in self::_#finalTopLevelFieldWithInitializer.==(null) ?{core::int} self::_#finalTopLevelFieldWithInitializer = #t34 : throw new _in::LateInitializationErrorImpl::•("Field 'finalTopLevelFieldWithInitializer' has been assigned during initialization.") : #t33{core::int};
+static get finalTopLevelFieldWithInitializer() → core::int {
+  if(!self::_#finalTopLevelFieldWithInitializer#isSet) {
+    final core::int #t33 = 0;
+    if(self::_#finalTopLevelFieldWithInitializer#isSet)
+      throw new _in::LateInitializationErrorImpl::•("Field 'finalTopLevelFieldWithInitializer' has been assigned during initialization.");
+    self::_#finalTopLevelFieldWithInitializer = #t33;
+    self::_#finalTopLevelFieldWithInitializer#isSet = true;
+  }
+  return let final core::int? #t34 = self::_#finalTopLevelFieldWithInitializer in #t34{core::int};
+}
 @#C1
 static get Extension|extensionStaticField() → core::int
   return self::_#Extension|extensionStaticField#isSet ?{core::int} let final core::int? #t35 = self::_#Extension|extensionStaticField in #t35{core::int} : throw new _in::LateInitializationErrorImpl::•("Field 'extensionStaticField' has not been initialized.");
@@ -214,8 +254,16 @@
     self::_#Extension|finalExtensionStaticField = #t38;
   }
 @#C1
-static get Extension|finalExtensionStaticFieldWithInitializer() → core::int
-  return let final core::int? #t39 = self::_#Extension|finalExtensionStaticFieldWithInitializer in #t39.==(null) ?{core::int} let final core::int #t40 = 0 in self::_#Extension|finalExtensionStaticFieldWithInitializer.==(null) ?{core::int} self::_#Extension|finalExtensionStaticFieldWithInitializer = #t40 : throw new _in::LateInitializationErrorImpl::•("Field 'finalExtensionStaticFieldWithInitializer' has been assigned during initialization.") : #t39{core::int};
+static get Extension|finalExtensionStaticFieldWithInitializer() → core::int {
+  if(!self::_#Extension|finalExtensionStaticFieldWithInitializer#isSet) {
+    final core::int #t39 = 0;
+    if(self::_#Extension|finalExtensionStaticFieldWithInitializer#isSet)
+      throw new _in::LateInitializationErrorImpl::•("Field 'finalExtensionStaticFieldWithInitializer' has been assigned during initialization.");
+    self::_#Extension|finalExtensionStaticFieldWithInitializer = #t39;
+    self::_#Extension|finalExtensionStaticFieldWithInitializer#isSet = true;
+  }
+  return let final core::int? #t40 = self::_#Extension|finalExtensionStaticFieldWithInitializer in #t40{core::int};
+}
 static method main() → dynamic {}
 
 constants  {
diff --git a/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.weak.expect b/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.weak.expect
index 4b5e6e4..af7e11a 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.weak.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.weak.expect
@@ -15,8 +15,16 @@
   constructor •(core::int x) → self::C
     : super self::B::•(x)
     ;
-  get y() → core::int
-    return let final core::int? #t1 = this.{self::C::_#C#y} in #t1.==(null) ?{core::int} let final core::int #t2 = this.{self::B::x}.{core::num::+}(1) in this.{self::C::_#C#y}.==(null) ?{core::int} this.{self::C::_#C#y} = #t2 : throw new _in::LateInitializationErrorImpl::•("Field 'y' has been assigned during initialization.") : #t1{core::int};
+  get y() → core::int {
+    if(!this.{self::C::_#C#y#isSet}) {
+      final core::int #t1 = this.{self::B::x}.{core::num::+}(1);
+      if(this.{self::C::_#C#y#isSet})
+        throw new _in::LateInitializationErrorImpl::•("Field 'y' has been assigned during initialization.");
+      this.{self::C::_#C#y} = #t1;
+      this.{self::C::_#C#y#isSet} = true;
+    }
+    return let final core::int? #t2 = this.{self::C::_#C#y} in #t2{core::int};
+  }
   method method() → dynamic
     return this.{self::B::x};
 }
@@ -40,13 +48,29 @@
   static method initLateStaticField1(core::int value) → core::int {
     return self::Class::lateStaticField1Init = value;
   }
-  static get lateStaticField1() → core::int
-    return let final core::int? #t3 = self::Class::_#lateStaticField1 in #t3.==(null) ?{core::int} let final core::int #t4 = self::Class::initLateStaticField1(87) in self::Class::_#lateStaticField1.==(null) ?{core::int} self::Class::_#lateStaticField1 = #t4 : throw new _in::LateInitializationErrorImpl::•("Field 'lateStaticField1' has been assigned during initialization.") : #t3{core::int};
+  static get lateStaticField1() → core::int {
+    if(!self::Class::_#lateStaticField1#isSet) {
+      final core::int #t3 = self::Class::initLateStaticField1(87);
+      if(self::Class::_#lateStaticField1#isSet)
+        throw new _in::LateInitializationErrorImpl::•("Field 'lateStaticField1' has been assigned during initialization.");
+      self::Class::_#lateStaticField1 = #t3;
+      self::Class::_#lateStaticField1#isSet = true;
+    }
+    return let final core::int? #t4 = self::Class::_#lateStaticField1 in #t4{core::int};
+  }
   static method initLateStaticField2(core::int value) → core::int {
     return self::Class::lateStaticField2Init = value;
   }
-  static get lateStaticField2() → core::int
-    return let final core::int? #t5 = self::Class::_#lateStaticField2 in #t5.==(null) ?{core::int} let final core::int #t6 = self::Class::initLateStaticField2(42) in self::Class::_#lateStaticField2.==(null) ?{core::int} self::Class::_#lateStaticField2 = #t6 : throw new _in::LateInitializationErrorImpl::•("Field 'lateStaticField2' has been assigned during initialization.") : #t5{core::int};
+  static get lateStaticField2() → core::int {
+    if(!self::Class::_#lateStaticField2#isSet) {
+      final core::int #t5 = self::Class::initLateStaticField2(42);
+      if(self::Class::_#lateStaticField2#isSet)
+        throw new _in::LateInitializationErrorImpl::•("Field 'lateStaticField2' has been assigned during initialization.");
+      self::Class::_#lateStaticField2 = #t5;
+      self::Class::_#lateStaticField2#isSet = true;
+    }
+    return let final core::int? #t6 = self::Class::_#lateStaticField2 in #t6{core::int};
+  }
   static method staticMethod() → dynamic {
     self::expect(null, self::Class::lateStaticField2Init);
     self::expect(42, self::Class::lateStaticField2);
@@ -55,8 +79,16 @@
   method initLateInstanceField(core::int value) → core::int {
     return this.{self::Class::lateInstanceFieldInit} = value;
   }
-  get lateInstanceField() → core::int
-    return let final core::int? #t7 = this.{self::Class::_#Class#lateInstanceField} in #t7.==(null) ?{core::int} let final core::int #t8 = this.{self::Class::initLateInstanceField}(16) in this.{self::Class::_#Class#lateInstanceField}.==(null) ?{core::int} this.{self::Class::_#Class#lateInstanceField} = #t8 : throw new _in::LateInitializationErrorImpl::•("Field 'lateInstanceField' has been assigned during initialization.") : #t7{core::int};
+  get lateInstanceField() → core::int {
+    if(!this.{self::Class::_#Class#lateInstanceField#isSet}) {
+      final core::int #t7 = this.{self::Class::initLateInstanceField}(16);
+      if(this.{self::Class::_#Class#lateInstanceField#isSet})
+        throw new _in::LateInitializationErrorImpl::•("Field 'lateInstanceField' has been assigned during initialization.");
+      this.{self::Class::_#Class#lateInstanceField} = #t7;
+      this.{self::Class::_#Class#lateInstanceField#isSet} = true;
+    }
+    return let final core::int? #t8 = this.{self::Class::_#Class#lateInstanceField} in #t8{core::int};
+  }
   method initLateGenericField(generic-covariant-impl self::Class::T% value) → self::Class::T% {
     return this.{self::Class::lateGenericFieldInit} = value;
   }
@@ -104,18 +136,42 @@
 static method initLateTopLevelField1(core::int value) → core::int {
   return self::lateTopLevelField1Init = value;
 }
-static get lateTopLevelField1() → core::int
-  return let final core::int? #t11 = self::_#lateTopLevelField1 in #t11.==(null) ?{core::int} let final core::int #t12 = self::initLateTopLevelField1(123) in self::_#lateTopLevelField1.==(null) ?{core::int} self::_#lateTopLevelField1 = #t12 : throw new _in::LateInitializationErrorImpl::•("Field 'lateTopLevelField1' has been assigned during initialization.") : #t11{core::int};
+static get lateTopLevelField1() → core::int {
+  if(!self::_#lateTopLevelField1#isSet) {
+    final core::int #t11 = self::initLateTopLevelField1(123);
+    if(self::_#lateTopLevelField1#isSet)
+      throw new _in::LateInitializationErrorImpl::•("Field 'lateTopLevelField1' has been assigned during initialization.");
+    self::_#lateTopLevelField1 = #t11;
+    self::_#lateTopLevelField1#isSet = true;
+  }
+  return let final core::int? #t12 = self::_#lateTopLevelField1 in #t12{core::int};
+}
 static method Extension|initLateExtensionField1(core::int value) → core::int {
   return self::Extension|lateExtensionField1Init = value;
 }
-static get Extension|lateExtensionField1() → core::int
-  return let final core::int? #t13 = self::_#Extension|lateExtensionField1 in #t13.==(null) ?{core::int} let final core::int #t14 = self::Extension|initLateExtensionField1(87) in self::_#Extension|lateExtensionField1.==(null) ?{core::int} self::_#Extension|lateExtensionField1 = #t14 : throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField1' has been assigned during initialization.") : #t13{core::int};
+static get Extension|lateExtensionField1() → core::int {
+  if(!self::_#Extension|lateExtensionField1#isSet) {
+    final core::int #t13 = self::Extension|initLateExtensionField1(87);
+    if(self::_#Extension|lateExtensionField1#isSet)
+      throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField1' has been assigned during initialization.");
+    self::_#Extension|lateExtensionField1 = #t13;
+    self::_#Extension|lateExtensionField1#isSet = true;
+  }
+  return let final core::int? #t14 = self::_#Extension|lateExtensionField1 in #t14{core::int};
+}
 static method Extension|initLateExtensionField2(core::int value) → core::int {
   return self::Extension|lateExtensionField2Init = value;
 }
-static get Extension|lateExtensionField2() → core::int
-  return let final core::int? #t15 = self::_#Extension|lateExtensionField2 in #t15.==(null) ?{core::int} let final core::int #t16 = self::Extension|initLateExtensionField2(42) in self::_#Extension|lateExtensionField2.==(null) ?{core::int} self::_#Extension|lateExtensionField2 = #t16 : throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField2' has been assigned during initialization.") : #t15{core::int};
+static get Extension|lateExtensionField2() → core::int {
+  if(!self::_#Extension|lateExtensionField2#isSet) {
+    final core::int #t15 = self::Extension|initLateExtensionField2(42);
+    if(self::_#Extension|lateExtensionField2#isSet)
+      throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField2' has been assigned during initialization.");
+    self::_#Extension|lateExtensionField2 = #t15;
+    self::_#Extension|lateExtensionField2#isSet = true;
+  }
+  return let final core::int? #t16 = self::_#Extension|lateExtensionField2 in #t16{core::int};
+}
 static method Extension|staticMethod() → dynamic {
   self::expect(null, self::Extension|lateExtensionField2Init);
   self::expect(42, self::Extension|lateExtensionField2);
diff --git a/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.weak.transformed.expect
index 4b5e6e4..af7e11a 100644
--- a/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.weak.transformed.expect
@@ -15,8 +15,16 @@
   constructor •(core::int x) → self::C
     : super self::B::•(x)
     ;
-  get y() → core::int
-    return let final core::int? #t1 = this.{self::C::_#C#y} in #t1.==(null) ?{core::int} let final core::int #t2 = this.{self::B::x}.{core::num::+}(1) in this.{self::C::_#C#y}.==(null) ?{core::int} this.{self::C::_#C#y} = #t2 : throw new _in::LateInitializationErrorImpl::•("Field 'y' has been assigned during initialization.") : #t1{core::int};
+  get y() → core::int {
+    if(!this.{self::C::_#C#y#isSet}) {
+      final core::int #t1 = this.{self::B::x}.{core::num::+}(1);
+      if(this.{self::C::_#C#y#isSet})
+        throw new _in::LateInitializationErrorImpl::•("Field 'y' has been assigned during initialization.");
+      this.{self::C::_#C#y} = #t1;
+      this.{self::C::_#C#y#isSet} = true;
+    }
+    return let final core::int? #t2 = this.{self::C::_#C#y} in #t2{core::int};
+  }
   method method() → dynamic
     return this.{self::B::x};
 }
@@ -40,13 +48,29 @@
   static method initLateStaticField1(core::int value) → core::int {
     return self::Class::lateStaticField1Init = value;
   }
-  static get lateStaticField1() → core::int
-    return let final core::int? #t3 = self::Class::_#lateStaticField1 in #t3.==(null) ?{core::int} let final core::int #t4 = self::Class::initLateStaticField1(87) in self::Class::_#lateStaticField1.==(null) ?{core::int} self::Class::_#lateStaticField1 = #t4 : throw new _in::LateInitializationErrorImpl::•("Field 'lateStaticField1' has been assigned during initialization.") : #t3{core::int};
+  static get lateStaticField1() → core::int {
+    if(!self::Class::_#lateStaticField1#isSet) {
+      final core::int #t3 = self::Class::initLateStaticField1(87);
+      if(self::Class::_#lateStaticField1#isSet)
+        throw new _in::LateInitializationErrorImpl::•("Field 'lateStaticField1' has been assigned during initialization.");
+      self::Class::_#lateStaticField1 = #t3;
+      self::Class::_#lateStaticField1#isSet = true;
+    }
+    return let final core::int? #t4 = self::Class::_#lateStaticField1 in #t4{core::int};
+  }
   static method initLateStaticField2(core::int value) → core::int {
     return self::Class::lateStaticField2Init = value;
   }
-  static get lateStaticField2() → core::int
-    return let final core::int? #t5 = self::Class::_#lateStaticField2 in #t5.==(null) ?{core::int} let final core::int #t6 = self::Class::initLateStaticField2(42) in self::Class::_#lateStaticField2.==(null) ?{core::int} self::Class::_#lateStaticField2 = #t6 : throw new _in::LateInitializationErrorImpl::•("Field 'lateStaticField2' has been assigned during initialization.") : #t5{core::int};
+  static get lateStaticField2() → core::int {
+    if(!self::Class::_#lateStaticField2#isSet) {
+      final core::int #t5 = self::Class::initLateStaticField2(42);
+      if(self::Class::_#lateStaticField2#isSet)
+        throw new _in::LateInitializationErrorImpl::•("Field 'lateStaticField2' has been assigned during initialization.");
+      self::Class::_#lateStaticField2 = #t5;
+      self::Class::_#lateStaticField2#isSet = true;
+    }
+    return let final core::int? #t6 = self::Class::_#lateStaticField2 in #t6{core::int};
+  }
   static method staticMethod() → dynamic {
     self::expect(null, self::Class::lateStaticField2Init);
     self::expect(42, self::Class::lateStaticField2);
@@ -55,8 +79,16 @@
   method initLateInstanceField(core::int value) → core::int {
     return this.{self::Class::lateInstanceFieldInit} = value;
   }
-  get lateInstanceField() → core::int
-    return let final core::int? #t7 = this.{self::Class::_#Class#lateInstanceField} in #t7.==(null) ?{core::int} let final core::int #t8 = this.{self::Class::initLateInstanceField}(16) in this.{self::Class::_#Class#lateInstanceField}.==(null) ?{core::int} this.{self::Class::_#Class#lateInstanceField} = #t8 : throw new _in::LateInitializationErrorImpl::•("Field 'lateInstanceField' has been assigned during initialization.") : #t7{core::int};
+  get lateInstanceField() → core::int {
+    if(!this.{self::Class::_#Class#lateInstanceField#isSet}) {
+      final core::int #t7 = this.{self::Class::initLateInstanceField}(16);
+      if(this.{self::Class::_#Class#lateInstanceField#isSet})
+        throw new _in::LateInitializationErrorImpl::•("Field 'lateInstanceField' has been assigned during initialization.");
+      this.{self::Class::_#Class#lateInstanceField} = #t7;
+      this.{self::Class::_#Class#lateInstanceField#isSet} = true;
+    }
+    return let final core::int? #t8 = this.{self::Class::_#Class#lateInstanceField} in #t8{core::int};
+  }
   method initLateGenericField(generic-covariant-impl self::Class::T% value) → self::Class::T% {
     return this.{self::Class::lateGenericFieldInit} = value;
   }
@@ -104,18 +136,42 @@
 static method initLateTopLevelField1(core::int value) → core::int {
   return self::lateTopLevelField1Init = value;
 }
-static get lateTopLevelField1() → core::int
-  return let final core::int? #t11 = self::_#lateTopLevelField1 in #t11.==(null) ?{core::int} let final core::int #t12 = self::initLateTopLevelField1(123) in self::_#lateTopLevelField1.==(null) ?{core::int} self::_#lateTopLevelField1 = #t12 : throw new _in::LateInitializationErrorImpl::•("Field 'lateTopLevelField1' has been assigned during initialization.") : #t11{core::int};
+static get lateTopLevelField1() → core::int {
+  if(!self::_#lateTopLevelField1#isSet) {
+    final core::int #t11 = self::initLateTopLevelField1(123);
+    if(self::_#lateTopLevelField1#isSet)
+      throw new _in::LateInitializationErrorImpl::•("Field 'lateTopLevelField1' has been assigned during initialization.");
+    self::_#lateTopLevelField1 = #t11;
+    self::_#lateTopLevelField1#isSet = true;
+  }
+  return let final core::int? #t12 = self::_#lateTopLevelField1 in #t12{core::int};
+}
 static method Extension|initLateExtensionField1(core::int value) → core::int {
   return self::Extension|lateExtensionField1Init = value;
 }
-static get Extension|lateExtensionField1() → core::int
-  return let final core::int? #t13 = self::_#Extension|lateExtensionField1 in #t13.==(null) ?{core::int} let final core::int #t14 = self::Extension|initLateExtensionField1(87) in self::_#Extension|lateExtensionField1.==(null) ?{core::int} self::_#Extension|lateExtensionField1 = #t14 : throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField1' has been assigned during initialization.") : #t13{core::int};
+static get Extension|lateExtensionField1() → core::int {
+  if(!self::_#Extension|lateExtensionField1#isSet) {
+    final core::int #t13 = self::Extension|initLateExtensionField1(87);
+    if(self::_#Extension|lateExtensionField1#isSet)
+      throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField1' has been assigned during initialization.");
+    self::_#Extension|lateExtensionField1 = #t13;
+    self::_#Extension|lateExtensionField1#isSet = true;
+  }
+  return let final core::int? #t14 = self::_#Extension|lateExtensionField1 in #t14{core::int};
+}
 static method Extension|initLateExtensionField2(core::int value) → core::int {
   return self::Extension|lateExtensionField2Init = value;
 }
-static get Extension|lateExtensionField2() → core::int
-  return let final core::int? #t15 = self::_#Extension|lateExtensionField2 in #t15.==(null) ?{core::int} let final core::int #t16 = self::Extension|initLateExtensionField2(42) in self::_#Extension|lateExtensionField2.==(null) ?{core::int} self::_#Extension|lateExtensionField2 = #t16 : throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField2' has been assigned during initialization.") : #t15{core::int};
+static get Extension|lateExtensionField2() → core::int {
+  if(!self::_#Extension|lateExtensionField2#isSet) {
+    final core::int #t15 = self::Extension|initLateExtensionField2(42);
+    if(self::_#Extension|lateExtensionField2#isSet)
+      throw new _in::LateInitializationErrorImpl::•("Field 'lateExtensionField2' has been assigned during initialization.");
+    self::_#Extension|lateExtensionField2 = #t15;
+    self::_#Extension|lateExtensionField2#isSet = true;
+  }
+  return let final core::int? #t16 = self::_#Extension|lateExtensionField2 in #t16{core::int};
+}
 static method Extension|staticMethod() → dynamic {
   self::expect(null, self::Extension|lateExtensionField2Init);
   self::expect(42, self::Extension|lateExtensionField2);
diff --git a/pkg/front_end/testcases/late_lowering/later.dart.weak.expect b/pkg/front_end/testcases/late_lowering/later.dart.weak.expect
index 78fc27d..3a9b187 100644
--- a/pkg/front_end/testcases/late_lowering/later.dart.weak.expect
+++ b/pkg/front_end/testcases/late_lowering/later.dart.weak.expect
@@ -93,8 +93,16 @@
   const constructor •() → self::B
     : super core::Object::•()
     ;
-  get x() → core::int
-    return let final core::int? #t3 = this.{self::B::_#B#x} in #t3.==(null) ?{core::int} let final core::int #t4 = 42 in this.{self::B::_#B#x}.==(null) ?{core::int} this.{self::B::_#B#x} = #t4 : throw new _in::LateInitializationErrorImpl::•("Field 'x' has been assigned during initialization.") : #t3{core::int};
+  get x() → core::int {
+    if(!this.{self::B::_#B#x#isSet}) {
+      final core::int #t3 = 42;
+      if(this.{self::B::_#B#x#isSet})
+        throw new _in::LateInitializationErrorImpl::•("Field 'x' has been assigned during initialization.");
+      this.{self::B::_#B#x} = #t3;
+      this.{self::B::_#B#x#isSet} = true;
+    }
+    return let final core::int? #t4 = this.{self::B::_#B#x} in #t4{core::int};
+  }
 }
 class C extends core::Object {
   field core::int? _#C#x = null;
diff --git a/pkg/front_end/testcases/late_lowering/later.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering/later.dart.weak.transformed.expect
index 92573ba..27b946d 100644
--- a/pkg/front_end/testcases/late_lowering/later.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/later.dart.weak.transformed.expect
@@ -93,8 +93,16 @@
   const constructor •() → self::B
     : super core::Object::•()
     ;
-  get x() → core::int
-    return let final core::int? #t3 = this.{self::B::_#B#x} in #t3.==(null) ?{core::int} let final core::int #t4 = 42 in this.{self::B::_#B#x}.==(null) ?{core::int} this.{self::B::_#B#x} = #t4 : throw new _in::LateInitializationErrorImpl::•("Field 'x' has been assigned during initialization.") : #t3{core::int};
+  get x() → core::int {
+    if(!this.{self::B::_#B#x#isSet}) {
+      final core::int #t3 = 42;
+      if(this.{self::B::_#B#x#isSet})
+        throw new _in::LateInitializationErrorImpl::•("Field 'x' has been assigned during initialization.");
+      this.{self::B::_#B#x} = #t3;
+      this.{self::B::_#B#x#isSet} = true;
+    }
+    return let final core::int? #t4 = this.{self::B::_#B#x} in #t4{core::int};
+  }
 }
 class C extends core::Object {
   field core::int? _#C#x = null;
diff --git a/pkg/front_end/testcases/late_lowering/override.dart.weak.expect b/pkg/front_end/testcases/late_lowering/override.dart.weak.expect
index a4add12..961d813 100644
--- a/pkg/front_end/testcases/late_lowering/override.dart.weak.expect
+++ b/pkg/front_end/testcases/late_lowering/override.dart.weak.expect
@@ -84,8 +84,16 @@
       this.{self::SubClass::_#SubClass#field3#isSet} = true;
       this.{self::SubClass::_#SubClass#field3} = #t14;
     }
-  get field4() → core::int
-    return let final core::int? #t15 = this.{self::SubClass::_#SubClass#field4} in #t15.==(null) ?{core::int} let final core::int #t16 = 0 in this.{self::SubClass::_#SubClass#field4}.==(null) ?{core::int} this.{self::SubClass::_#SubClass#field4} = #t16 : throw new _in::LateInitializationErrorImpl::•("Field 'field4' has been assigned during initialization.") : #t15{core::int};
+  get field4() → core::int {
+    if(!this.{self::SubClass::_#SubClass#field4#isSet}) {
+      final core::int #t15 = 0;
+      if(this.{self::SubClass::_#SubClass#field4#isSet})
+        throw new _in::LateInitializationErrorImpl::•("Field 'field4' has been assigned during initialization.");
+      this.{self::SubClass::_#SubClass#field4} = #t15;
+      this.{self::SubClass::_#SubClass#field4#isSet} = true;
+    }
+    return let final core::int? #t16 = this.{self::SubClass::_#SubClass#field4} in #t16{core::int};
+  }
   get directField1() → core::int
     return super.{self::Class::field1};
   set directField1(core::int value) → void {
diff --git a/pkg/front_end/testcases/late_lowering/override.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering/override.dart.weak.transformed.expect
index a4add12..961d813 100644
--- a/pkg/front_end/testcases/late_lowering/override.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/override.dart.weak.transformed.expect
@@ -84,8 +84,16 @@
       this.{self::SubClass::_#SubClass#field3#isSet} = true;
       this.{self::SubClass::_#SubClass#field3} = #t14;
     }
-  get field4() → core::int
-    return let final core::int? #t15 = this.{self::SubClass::_#SubClass#field4} in #t15.==(null) ?{core::int} let final core::int #t16 = 0 in this.{self::SubClass::_#SubClass#field4}.==(null) ?{core::int} this.{self::SubClass::_#SubClass#field4} = #t16 : throw new _in::LateInitializationErrorImpl::•("Field 'field4' has been assigned during initialization.") : #t15{core::int};
+  get field4() → core::int {
+    if(!this.{self::SubClass::_#SubClass#field4#isSet}) {
+      final core::int #t15 = 0;
+      if(this.{self::SubClass::_#SubClass#field4#isSet})
+        throw new _in::LateInitializationErrorImpl::•("Field 'field4' has been assigned during initialization.");
+      this.{self::SubClass::_#SubClass#field4} = #t15;
+      this.{self::SubClass::_#SubClass#field4#isSet} = true;
+    }
+    return let final core::int? #t16 = this.{self::SubClass::_#SubClass#field4} in #t16{core::int};
+  }
   get directField1() → core::int
     return super.{self::Class::field1};
   set directField1(core::int value) → void {
diff --git a/pkg/front_end/testcases/late_lowering/override_getter_setter.dart.weak.expect b/pkg/front_end/testcases/late_lowering/override_getter_setter.dart.weak.expect
index 2c3785b..e51321c 100644
--- a/pkg/front_end/testcases/late_lowering/override_getter_setter.dart.weak.expect
+++ b/pkg/front_end/testcases/late_lowering/override_getter_setter.dart.weak.expect
@@ -47,8 +47,16 @@
   synthetic constructor •() → self::C
     : super self::A::•()
     ;
-  get x() → core::int
-    return let final core::int? #t4 = this.{self::C::_#C#x} in #t4.==(null) ?{core::int} let final core::int #t5 = 2 in this.{self::C::_#C#x}.==(null) ?{core::int} this.{self::C::_#C#x} = #t5 : throw new _in::LateInitializationErrorImpl::•("Field 'x' has been assigned during initialization.") : #t4{core::int};
+  get x() → core::int {
+    if(!this.{self::C::_#C#x#isSet}) {
+      final core::int #t4 = 2;
+      if(this.{self::C::_#C#x#isSet})
+        throw new _in::LateInitializationErrorImpl::•("Field 'x' has been assigned during initialization.");
+      this.{self::C::_#C#x} = #t4;
+      this.{self::C::_#C#x#isSet} = true;
+    }
+    return let final core::int? #t5 = this.{self::C::_#C#x} in #t5{core::int};
+  }
   get y() → core::int? {
     if(!this.{self::C::_#C#y#isSet}) {
       final core::int? #t6 = 2;
diff --git a/pkg/front_end/testcases/late_lowering/override_getter_setter.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering/override_getter_setter.dart.weak.transformed.expect
index 2c3785b..e51321c 100644
--- a/pkg/front_end/testcases/late_lowering/override_getter_setter.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/late_lowering/override_getter_setter.dart.weak.transformed.expect
@@ -47,8 +47,16 @@
   synthetic constructor •() → self::C
     : super self::A::•()
     ;
-  get x() → core::int
-    return let final core::int? #t4 = this.{self::C::_#C#x} in #t4.==(null) ?{core::int} let final core::int #t5 = 2 in this.{self::C::_#C#x}.==(null) ?{core::int} this.{self::C::_#C#x} = #t5 : throw new _in::LateInitializationErrorImpl::•("Field 'x' has been assigned during initialization.") : #t4{core::int};
+  get x() → core::int {
+    if(!this.{self::C::_#C#x#isSet}) {
+      final core::int #t4 = 2;
+      if(this.{self::C::_#C#x#isSet})
+        throw new _in::LateInitializationErrorImpl::•("Field 'x' has been assigned during initialization.");
+      this.{self::C::_#C#x} = #t4;
+      this.{self::C::_#C#x#isSet} = true;
+    }
+    return let final core::int? #t5 = this.{self::C::_#C#x} in #t5{core::int};
+  }
   get y() → core::int? {
     if(!this.{self::C::_#C#y#isSet}) {
       final core::int? #t6 = 2;
diff --git a/pkg/front_end/testcases/late_lowering_sentinel/folder.options b/pkg/front_end/testcases/late_lowering_sentinel/folder.options
new file mode 100644
index 0000000..8d48ec9
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering_sentinel/folder.options
@@ -0,0 +1,3 @@
+--enable-experiment=non-nullable
+--force-late-lowering
+--force-late-lowering-sentinel
\ No newline at end of file
diff --git a/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart b/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart
new file mode 100644
index 0000000..3434c11
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart
@@ -0,0 +1,14 @@
+// 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.
+
+late int? nullableTopLevelField;
+late int nonNullableTopLevelField;
+late int? nullableTopLevelFieldWithInitializer = null;
+late int nonNullableTopLevelFieldWithInitializer = 0;
+late final int? nullableFinalTopLevelField;
+late final int nonNullableFinalTopLevelField;
+late final int? nullableFinalTopLevelFieldWithInitializer = null;
+late final int nonNullableFinalTopLevelFieldWithInitializer = 0;
+
+main() {}
diff --git a/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart.outline.expect b/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart.outline.expect
new file mode 100644
index 0000000..98525c7
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart.outline.expect
@@ -0,0 +1,28 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static field core::int? _#nullableTopLevelField;
+static field core::int? _#nonNullableTopLevelField;
+static field core::int? _#nullableTopLevelFieldWithInitializer;
+static field core::int? _#nonNullableTopLevelFieldWithInitializer;
+static field core::int? _#nullableFinalTopLevelField;
+static field core::int? _#nonNullableFinalTopLevelField;
+static field core::int? _#nullableFinalTopLevelFieldWithInitializer;
+static field core::int? _#nonNullableFinalTopLevelFieldWithInitializer;
+static get nullableTopLevelField() → core::int?;
+static set nullableTopLevelField(core::int? #t1) → void;
+static get nonNullableTopLevelField() → core::int;
+static set nonNullableTopLevelField(core::int #t2) → void;
+static get nullableTopLevelFieldWithInitializer() → core::int?;
+static set nullableTopLevelFieldWithInitializer(core::int? #t3) → void;
+static get nonNullableTopLevelFieldWithInitializer() → core::int;
+static set nonNullableTopLevelFieldWithInitializer(core::int #t4) → void;
+static get nullableFinalTopLevelField() → core::int?;
+static set nullableFinalTopLevelField(core::int? #t5) → void;
+static get nonNullableFinalTopLevelField() → core::int;
+static set nonNullableFinalTopLevelField(core::int #t6) → void;
+static get nullableFinalTopLevelFieldWithInitializer() → core::int?;
+static get nonNullableFinalTopLevelFieldWithInitializer() → core::int;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart.strong.expect b/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart.strong.expect
new file mode 100644
index 0000000..2bd9072
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart.strong.expect
@@ -0,0 +1,48 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+static field core::int? _#nullableTopLevelField = _in::createSentinel<core::int?>();
+static field core::int? _#nonNullableTopLevelField = null;
+static field core::int? _#nullableTopLevelFieldWithInitializer = _in::createSentinel<core::int?>();
+static field core::int? _#nonNullableTopLevelFieldWithInitializer = null;
+static field core::int? _#nullableFinalTopLevelField = _in::createSentinel<core::int?>();
+static field core::int? _#nonNullableFinalTopLevelField = null;
+static field core::int? _#nullableFinalTopLevelFieldWithInitializer = _in::createSentinel<core::int?>();
+static field core::int? _#nonNullableFinalTopLevelFieldWithInitializer = null;
+static get nullableTopLevelField() → core::int?
+  return let final core::int? #t1 = self::_#nullableTopLevelField in _in::isSentinel(#t1) ?{core::int?} throw new _in::LateInitializationErrorImpl::•("Field 'nullableTopLevelField' has not been initialized.") : #t1{core::int?};
+static set nullableTopLevelField(core::int? #t2) → void
+  self::_#nullableTopLevelField = #t2;
+static get nonNullableTopLevelField() → core::int
+  return let final core::int? #t3 = self::_#nonNullableTopLevelField in #t3.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableTopLevelField' has not been initialized.") : #t3{core::int};
+static set nonNullableTopLevelField(core::int #t4) → void
+  self::_#nonNullableTopLevelField = #t4;
+static get nullableTopLevelFieldWithInitializer() → core::int?
+  return let final core::int? #t5 = self::_#nullableTopLevelFieldWithInitializer in _in::isSentinel(#t5) ?{core::int?} self::_#nullableTopLevelFieldWithInitializer = null : #t5{core::int?};
+static set nullableTopLevelFieldWithInitializer(core::int? #t6) → void
+  self::_#nullableTopLevelFieldWithInitializer = #t6;
+static get nonNullableTopLevelFieldWithInitializer() → core::int
+  return let final core::int? #t7 = self::_#nonNullableTopLevelFieldWithInitializer in #t7.==(null) ?{core::int} self::_#nonNullableTopLevelFieldWithInitializer = 0 : #t7{core::int};
+static set nonNullableTopLevelFieldWithInitializer(core::int #t8) → void
+  self::_#nonNullableTopLevelFieldWithInitializer = #t8;
+static get nullableFinalTopLevelField() → core::int?
+  return let final core::int? #t9 = self::_#nullableFinalTopLevelField in _in::isSentinel(#t9) ?{core::int?} throw new _in::LateInitializationErrorImpl::•("Field 'nullableFinalTopLevelField' has not been initialized.") : #t9{core::int?};
+static set nullableFinalTopLevelField(core::int? #t10) → void
+  if(_in::isSentinel(self::_#nullableFinalTopLevelField))
+    self::_#nullableFinalTopLevelField = #t10;
+  else
+    throw new _in::LateInitializationErrorImpl::•("Field 'nullableFinalTopLevelField' has already been initialized.");
+static get nonNullableFinalTopLevelField() → core::int
+  return let final core::int? #t11 = self::_#nonNullableFinalTopLevelField in #t11.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableFinalTopLevelField' has not been initialized.") : #t11{core::int};
+static set nonNullableFinalTopLevelField(core::int #t12) → void
+  if(self::_#nonNullableFinalTopLevelField.==(null))
+    self::_#nonNullableFinalTopLevelField = #t12;
+  else
+    throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableFinalTopLevelField' has already been initialized.");
+static get nullableFinalTopLevelFieldWithInitializer() → core::int?
+  return let final core::int? #t13 = self::_#nullableFinalTopLevelFieldWithInitializer in _in::isSentinel(#t13) ?{core::int?} let final core::int? #t14 = null in _in::isSentinel(self::_#nullableFinalTopLevelFieldWithInitializer) ?{core::int?} self::_#nullableFinalTopLevelFieldWithInitializer = #t14 : throw new _in::LateInitializationErrorImpl::•("Field 'nullableFinalTopLevelFieldWithInitializer' has been assigned during initialization.") : #t13;
+static get nonNullableFinalTopLevelFieldWithInitializer() → core::int
+  return let final core::int? #t15 = self::_#nonNullableFinalTopLevelFieldWithInitializer in #t15.==(null) ?{core::int} let final core::int #t16 = 0 in self::_#nonNullableFinalTopLevelFieldWithInitializer.==(null) ?{core::int} self::_#nonNullableFinalTopLevelFieldWithInitializer = #t16 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableFinalTopLevelFieldWithInitializer' has been assigned during initialization.") : #t15{core::int};
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart.strong.transformed.expect
new file mode 100644
index 0000000..2bd9072
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart.strong.transformed.expect
@@ -0,0 +1,48 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+static field core::int? _#nullableTopLevelField = _in::createSentinel<core::int?>();
+static field core::int? _#nonNullableTopLevelField = null;
+static field core::int? _#nullableTopLevelFieldWithInitializer = _in::createSentinel<core::int?>();
+static field core::int? _#nonNullableTopLevelFieldWithInitializer = null;
+static field core::int? _#nullableFinalTopLevelField = _in::createSentinel<core::int?>();
+static field core::int? _#nonNullableFinalTopLevelField = null;
+static field core::int? _#nullableFinalTopLevelFieldWithInitializer = _in::createSentinel<core::int?>();
+static field core::int? _#nonNullableFinalTopLevelFieldWithInitializer = null;
+static get nullableTopLevelField() → core::int?
+  return let final core::int? #t1 = self::_#nullableTopLevelField in _in::isSentinel(#t1) ?{core::int?} throw new _in::LateInitializationErrorImpl::•("Field 'nullableTopLevelField' has not been initialized.") : #t1{core::int?};
+static set nullableTopLevelField(core::int? #t2) → void
+  self::_#nullableTopLevelField = #t2;
+static get nonNullableTopLevelField() → core::int
+  return let final core::int? #t3 = self::_#nonNullableTopLevelField in #t3.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableTopLevelField' has not been initialized.") : #t3{core::int};
+static set nonNullableTopLevelField(core::int #t4) → void
+  self::_#nonNullableTopLevelField = #t4;
+static get nullableTopLevelFieldWithInitializer() → core::int?
+  return let final core::int? #t5 = self::_#nullableTopLevelFieldWithInitializer in _in::isSentinel(#t5) ?{core::int?} self::_#nullableTopLevelFieldWithInitializer = null : #t5{core::int?};
+static set nullableTopLevelFieldWithInitializer(core::int? #t6) → void
+  self::_#nullableTopLevelFieldWithInitializer = #t6;
+static get nonNullableTopLevelFieldWithInitializer() → core::int
+  return let final core::int? #t7 = self::_#nonNullableTopLevelFieldWithInitializer in #t7.==(null) ?{core::int} self::_#nonNullableTopLevelFieldWithInitializer = 0 : #t7{core::int};
+static set nonNullableTopLevelFieldWithInitializer(core::int #t8) → void
+  self::_#nonNullableTopLevelFieldWithInitializer = #t8;
+static get nullableFinalTopLevelField() → core::int?
+  return let final core::int? #t9 = self::_#nullableFinalTopLevelField in _in::isSentinel(#t9) ?{core::int?} throw new _in::LateInitializationErrorImpl::•("Field 'nullableFinalTopLevelField' has not been initialized.") : #t9{core::int?};
+static set nullableFinalTopLevelField(core::int? #t10) → void
+  if(_in::isSentinel(self::_#nullableFinalTopLevelField))
+    self::_#nullableFinalTopLevelField = #t10;
+  else
+    throw new _in::LateInitializationErrorImpl::•("Field 'nullableFinalTopLevelField' has already been initialized.");
+static get nonNullableFinalTopLevelField() → core::int
+  return let final core::int? #t11 = self::_#nonNullableFinalTopLevelField in #t11.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableFinalTopLevelField' has not been initialized.") : #t11{core::int};
+static set nonNullableFinalTopLevelField(core::int #t12) → void
+  if(self::_#nonNullableFinalTopLevelField.==(null))
+    self::_#nonNullableFinalTopLevelField = #t12;
+  else
+    throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableFinalTopLevelField' has already been initialized.");
+static get nullableFinalTopLevelFieldWithInitializer() → core::int?
+  return let final core::int? #t13 = self::_#nullableFinalTopLevelFieldWithInitializer in _in::isSentinel(#t13) ?{core::int?} let final core::int? #t14 = null in _in::isSentinel(self::_#nullableFinalTopLevelFieldWithInitializer) ?{core::int?} self::_#nullableFinalTopLevelFieldWithInitializer = #t14 : throw new _in::LateInitializationErrorImpl::•("Field 'nullableFinalTopLevelFieldWithInitializer' has been assigned during initialization.") : #t13;
+static get nonNullableFinalTopLevelFieldWithInitializer() → core::int
+  return let final core::int? #t15 = self::_#nonNullableFinalTopLevelFieldWithInitializer in #t15.==(null) ?{core::int} let final core::int #t16 = 0 in self::_#nonNullableFinalTopLevelFieldWithInitializer.==(null) ?{core::int} self::_#nonNullableFinalTopLevelFieldWithInitializer = #t16 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableFinalTopLevelFieldWithInitializer' has been assigned during initialization.") : #t15{core::int};
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart.textual_outline.expect b/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart.textual_outline.expect
new file mode 100644
index 0000000..34e9a83
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart.textual_outline.expect
@@ -0,0 +1,19 @@
+late int;
+?
+nullableTopLevelField;
+late int ;
+nonNullableTopLevelField;
+late int;
+?
+nullableTopLevelFieldWithInitializer = null;
+late int ;
+nonNullableTopLevelFieldWithInitializer = 0;
+late ;
+final int? nullableFinalTopLevelField;
+late ;
+final int nonNullableFinalTopLevelField;
+late ;
+final int? nullableFinalTopLevelFieldWithInitializer = null;
+late ;
+final int nonNullableFinalTopLevelFieldWithInitializer = 0;
+main() {}
diff --git a/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart.weak.expect b/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart.weak.expect
new file mode 100644
index 0000000..2bd9072
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart.weak.expect
@@ -0,0 +1,48 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+static field core::int? _#nullableTopLevelField = _in::createSentinel<core::int?>();
+static field core::int? _#nonNullableTopLevelField = null;
+static field core::int? _#nullableTopLevelFieldWithInitializer = _in::createSentinel<core::int?>();
+static field core::int? _#nonNullableTopLevelFieldWithInitializer = null;
+static field core::int? _#nullableFinalTopLevelField = _in::createSentinel<core::int?>();
+static field core::int? _#nonNullableFinalTopLevelField = null;
+static field core::int? _#nullableFinalTopLevelFieldWithInitializer = _in::createSentinel<core::int?>();
+static field core::int? _#nonNullableFinalTopLevelFieldWithInitializer = null;
+static get nullableTopLevelField() → core::int?
+  return let final core::int? #t1 = self::_#nullableTopLevelField in _in::isSentinel(#t1) ?{core::int?} throw new _in::LateInitializationErrorImpl::•("Field 'nullableTopLevelField' has not been initialized.") : #t1{core::int?};
+static set nullableTopLevelField(core::int? #t2) → void
+  self::_#nullableTopLevelField = #t2;
+static get nonNullableTopLevelField() → core::int
+  return let final core::int? #t3 = self::_#nonNullableTopLevelField in #t3.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableTopLevelField' has not been initialized.") : #t3{core::int};
+static set nonNullableTopLevelField(core::int #t4) → void
+  self::_#nonNullableTopLevelField = #t4;
+static get nullableTopLevelFieldWithInitializer() → core::int?
+  return let final core::int? #t5 = self::_#nullableTopLevelFieldWithInitializer in _in::isSentinel(#t5) ?{core::int?} self::_#nullableTopLevelFieldWithInitializer = null : #t5{core::int?};
+static set nullableTopLevelFieldWithInitializer(core::int? #t6) → void
+  self::_#nullableTopLevelFieldWithInitializer = #t6;
+static get nonNullableTopLevelFieldWithInitializer() → core::int
+  return let final core::int? #t7 = self::_#nonNullableTopLevelFieldWithInitializer in #t7.==(null) ?{core::int} self::_#nonNullableTopLevelFieldWithInitializer = 0 : #t7{core::int};
+static set nonNullableTopLevelFieldWithInitializer(core::int #t8) → void
+  self::_#nonNullableTopLevelFieldWithInitializer = #t8;
+static get nullableFinalTopLevelField() → core::int?
+  return let final core::int? #t9 = self::_#nullableFinalTopLevelField in _in::isSentinel(#t9) ?{core::int?} throw new _in::LateInitializationErrorImpl::•("Field 'nullableFinalTopLevelField' has not been initialized.") : #t9{core::int?};
+static set nullableFinalTopLevelField(core::int? #t10) → void
+  if(_in::isSentinel(self::_#nullableFinalTopLevelField))
+    self::_#nullableFinalTopLevelField = #t10;
+  else
+    throw new _in::LateInitializationErrorImpl::•("Field 'nullableFinalTopLevelField' has already been initialized.");
+static get nonNullableFinalTopLevelField() → core::int
+  return let final core::int? #t11 = self::_#nonNullableFinalTopLevelField in #t11.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableFinalTopLevelField' has not been initialized.") : #t11{core::int};
+static set nonNullableFinalTopLevelField(core::int #t12) → void
+  if(self::_#nonNullableFinalTopLevelField.==(null))
+    self::_#nonNullableFinalTopLevelField = #t12;
+  else
+    throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableFinalTopLevelField' has already been initialized.");
+static get nullableFinalTopLevelFieldWithInitializer() → core::int?
+  return let final core::int? #t13 = self::_#nullableFinalTopLevelFieldWithInitializer in _in::isSentinel(#t13) ?{core::int?} let final core::int? #t14 = null in _in::isSentinel(self::_#nullableFinalTopLevelFieldWithInitializer) ?{core::int?} self::_#nullableFinalTopLevelFieldWithInitializer = #t14 : throw new _in::LateInitializationErrorImpl::•("Field 'nullableFinalTopLevelFieldWithInitializer' has been assigned during initialization.") : #t13;
+static get nonNullableFinalTopLevelFieldWithInitializer() → core::int
+  return let final core::int? #t15 = self::_#nonNullableFinalTopLevelFieldWithInitializer in #t15.==(null) ?{core::int} let final core::int #t16 = 0 in self::_#nonNullableFinalTopLevelFieldWithInitializer.==(null) ?{core::int} self::_#nonNullableFinalTopLevelFieldWithInitializer = #t16 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableFinalTopLevelFieldWithInitializer' has been assigned during initialization.") : #t15{core::int};
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart.weak.transformed.expect
new file mode 100644
index 0000000..2bd9072
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering_sentinel/late_fields.dart.weak.transformed.expect
@@ -0,0 +1,48 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+static field core::int? _#nullableTopLevelField = _in::createSentinel<core::int?>();
+static field core::int? _#nonNullableTopLevelField = null;
+static field core::int? _#nullableTopLevelFieldWithInitializer = _in::createSentinel<core::int?>();
+static field core::int? _#nonNullableTopLevelFieldWithInitializer = null;
+static field core::int? _#nullableFinalTopLevelField = _in::createSentinel<core::int?>();
+static field core::int? _#nonNullableFinalTopLevelField = null;
+static field core::int? _#nullableFinalTopLevelFieldWithInitializer = _in::createSentinel<core::int?>();
+static field core::int? _#nonNullableFinalTopLevelFieldWithInitializer = null;
+static get nullableTopLevelField() → core::int?
+  return let final core::int? #t1 = self::_#nullableTopLevelField in _in::isSentinel(#t1) ?{core::int?} throw new _in::LateInitializationErrorImpl::•("Field 'nullableTopLevelField' has not been initialized.") : #t1{core::int?};
+static set nullableTopLevelField(core::int? #t2) → void
+  self::_#nullableTopLevelField = #t2;
+static get nonNullableTopLevelField() → core::int
+  return let final core::int? #t3 = self::_#nonNullableTopLevelField in #t3.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableTopLevelField' has not been initialized.") : #t3{core::int};
+static set nonNullableTopLevelField(core::int #t4) → void
+  self::_#nonNullableTopLevelField = #t4;
+static get nullableTopLevelFieldWithInitializer() → core::int?
+  return let final core::int? #t5 = self::_#nullableTopLevelFieldWithInitializer in _in::isSentinel(#t5) ?{core::int?} self::_#nullableTopLevelFieldWithInitializer = null : #t5{core::int?};
+static set nullableTopLevelFieldWithInitializer(core::int? #t6) → void
+  self::_#nullableTopLevelFieldWithInitializer = #t6;
+static get nonNullableTopLevelFieldWithInitializer() → core::int
+  return let final core::int? #t7 = self::_#nonNullableTopLevelFieldWithInitializer in #t7.==(null) ?{core::int} self::_#nonNullableTopLevelFieldWithInitializer = 0 : #t7{core::int};
+static set nonNullableTopLevelFieldWithInitializer(core::int #t8) → void
+  self::_#nonNullableTopLevelFieldWithInitializer = #t8;
+static get nullableFinalTopLevelField() → core::int?
+  return let final core::int? #t9 = self::_#nullableFinalTopLevelField in _in::isSentinel(#t9) ?{core::int?} throw new _in::LateInitializationErrorImpl::•("Field 'nullableFinalTopLevelField' has not been initialized.") : #t9{core::int?};
+static set nullableFinalTopLevelField(core::int? #t10) → void
+  if(_in::isSentinel(self::_#nullableFinalTopLevelField))
+    self::_#nullableFinalTopLevelField = #t10;
+  else
+    throw new _in::LateInitializationErrorImpl::•("Field 'nullableFinalTopLevelField' has already been initialized.");
+static get nonNullableFinalTopLevelField() → core::int
+  return let final core::int? #t11 = self::_#nonNullableFinalTopLevelField in #t11.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableFinalTopLevelField' has not been initialized.") : #t11{core::int};
+static set nonNullableFinalTopLevelField(core::int #t12) → void
+  if(self::_#nonNullableFinalTopLevelField.==(null))
+    self::_#nonNullableFinalTopLevelField = #t12;
+  else
+    throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableFinalTopLevelField' has already been initialized.");
+static get nullableFinalTopLevelFieldWithInitializer() → core::int?
+  return let final core::int? #t13 = self::_#nullableFinalTopLevelFieldWithInitializer in _in::isSentinel(#t13) ?{core::int?} let final core::int? #t14 = null in _in::isSentinel(self::_#nullableFinalTopLevelFieldWithInitializer) ?{core::int?} self::_#nullableFinalTopLevelFieldWithInitializer = #t14 : throw new _in::LateInitializationErrorImpl::•("Field 'nullableFinalTopLevelFieldWithInitializer' has been assigned during initialization.") : #t13;
+static get nonNullableFinalTopLevelFieldWithInitializer() → core::int
+  return let final core::int? #t15 = self::_#nonNullableFinalTopLevelFieldWithInitializer in #t15.==(null) ?{core::int} let final core::int #t16 = 0 in self::_#nonNullableFinalTopLevelFieldWithInitializer.==(null) ?{core::int} self::_#nonNullableFinalTopLevelFieldWithInitializer = #t16 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableFinalTopLevelFieldWithInitializer' has been assigned during initialization.") : #t15{core::int};
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart b/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart
new file mode 100644
index 0000000..b0799a6
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart
@@ -0,0 +1,16 @@
+// 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.
+
+test() {
+  late int? nullableTopLevelLocal;
+  late int nonNullableTopLevelLocal;
+  late int? nullableTopLevelLocalWithInitializer = null;
+  late int nonNullableTopLevelLocalWithInitializer = 0;
+  late final int? nullableFinalTopLevelLocal;
+  late final int nonNullableFinalTopLevelLocal;
+  late final int? nullableFinalTopLevelLocalWithInitializer = null;
+  late final int nonNullableFinalTopLevelLocalWithInitializer = 0;
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.outline.expect b/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.outline.expect
new file mode 100644
index 0000000..64923de
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.outline.expect
@@ -0,0 +1,7 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+
+static method test() → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.strong.expect b/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.strong.expect
new file mode 100644
index 0000000..aace5e6
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.strong.expect
@@ -0,0 +1,50 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+static method test() → dynamic {
+  core::int? nullableTopLevelLocal = _in::createSentinel<core::int?>();
+  function #nullableTopLevelLocal#get() → core::int?
+    return let final core::int? #t1 = nullableTopLevelLocal in _in::isSentinel(#t1) ?{core::int?} throw new _in::LateInitializationErrorImpl::•("Local 'nullableTopLevelLocal' has not been initialized.") : #t1{core::int?};
+  function #nullableTopLevelLocal#set(core::int? #t2) → dynamic
+    return nullableTopLevelLocal = #t2;
+  core::int? nonNullableTopLevelLocal;
+  function #nonNullableTopLevelLocal#get() → core::int
+    return let final core::int? #t3 = nonNullableTopLevelLocal in #t3.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Local 'nonNullableTopLevelLocal' has not been initialized.") : #t3{core::int};
+  function #nonNullableTopLevelLocal#set(core::int #t4) → dynamic
+    return nonNullableTopLevelLocal = #t4;
+  core::int? nullableTopLevelLocalWithInitializer = _in::createSentinel<core::int?>();
+  function #nullableTopLevelLocalWithInitializer#get() → core::int?
+    return let final core::int? #t5 = nullableTopLevelLocalWithInitializer in _in::isSentinel(#t5) ?{core::int?} nullableTopLevelLocalWithInitializer = null : #t5{core::int?};
+  function #nullableTopLevelLocalWithInitializer#set(core::int? #t6) → dynamic
+    return nullableTopLevelLocalWithInitializer = #t6;
+  core::int? nonNullableTopLevelLocalWithInitializer;
+  function #nonNullableTopLevelLocalWithInitializer#get() → core::int
+    return let final core::int? #t7 = nonNullableTopLevelLocalWithInitializer in #t7.==(null) ?{core::int} nonNullableTopLevelLocalWithInitializer = 0 : #t7{core::int};
+  function #nonNullableTopLevelLocalWithInitializer#set(core::int #t8) → dynamic
+    return nonNullableTopLevelLocalWithInitializer = #t8;
+  final core::int? nullableFinalTopLevelLocal = _in::createSentinel<core::int?>();
+  function #nullableFinalTopLevelLocal#get() → core::int?
+    return let final core::int? #t9 = nullableFinalTopLevelLocal in _in::isSentinel(#t9) ?{core::int?} throw new _in::LateInitializationErrorImpl::•("Local 'nullableFinalTopLevelLocal' has not been initialized.") : #t9{core::int?};
+  function #nullableFinalTopLevelLocal#set(core::int? #t10) → dynamic
+    if(_in::isSentinel(nullableFinalTopLevelLocal))
+      return nullableFinalTopLevelLocal = #t10;
+    else
+      throw new _in::LateInitializationErrorImpl::•("Local 'nullableFinalTopLevelLocal' has already been initialized.");
+  final core::int? nonNullableFinalTopLevelLocal;
+  function #nonNullableFinalTopLevelLocal#get() → core::int
+    return let final core::int? #t11 = nonNullableFinalTopLevelLocal in #t11.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Local 'nonNullableFinalTopLevelLocal' has not been initialized.") : #t11{core::int};
+  function #nonNullableFinalTopLevelLocal#set(core::int #t12) → dynamic
+    if(nonNullableFinalTopLevelLocal.==(null))
+      return nonNullableFinalTopLevelLocal = #t12;
+    else
+      throw new _in::LateInitializationErrorImpl::•("Local 'nonNullableFinalTopLevelLocal' has already been initialized.");
+  final core::int? nullableFinalTopLevelLocalWithInitializer = _in::createSentinel<core::int?>();
+  function #nullableFinalTopLevelLocalWithInitializer#get() → core::int?
+    return let final core::int? #t13 = nullableFinalTopLevelLocalWithInitializer in _in::isSentinel(#t13) ?{core::int?} nullableFinalTopLevelLocalWithInitializer = null : #t13{core::int?};
+  final core::int? nonNullableFinalTopLevelLocalWithInitializer;
+  function #nonNullableFinalTopLevelLocalWithInitializer#get() → core::int
+    return let final core::int? #t14 = nonNullableFinalTopLevelLocalWithInitializer in #t14.==(null) ?{core::int} nonNullableFinalTopLevelLocalWithInitializer = 0 : #t14{core::int};
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.strong.transformed.expect
new file mode 100644
index 0000000..aace5e6
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.strong.transformed.expect
@@ -0,0 +1,50 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+static method test() → dynamic {
+  core::int? nullableTopLevelLocal = _in::createSentinel<core::int?>();
+  function #nullableTopLevelLocal#get() → core::int?
+    return let final core::int? #t1 = nullableTopLevelLocal in _in::isSentinel(#t1) ?{core::int?} throw new _in::LateInitializationErrorImpl::•("Local 'nullableTopLevelLocal' has not been initialized.") : #t1{core::int?};
+  function #nullableTopLevelLocal#set(core::int? #t2) → dynamic
+    return nullableTopLevelLocal = #t2;
+  core::int? nonNullableTopLevelLocal;
+  function #nonNullableTopLevelLocal#get() → core::int
+    return let final core::int? #t3 = nonNullableTopLevelLocal in #t3.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Local 'nonNullableTopLevelLocal' has not been initialized.") : #t3{core::int};
+  function #nonNullableTopLevelLocal#set(core::int #t4) → dynamic
+    return nonNullableTopLevelLocal = #t4;
+  core::int? nullableTopLevelLocalWithInitializer = _in::createSentinel<core::int?>();
+  function #nullableTopLevelLocalWithInitializer#get() → core::int?
+    return let final core::int? #t5 = nullableTopLevelLocalWithInitializer in _in::isSentinel(#t5) ?{core::int?} nullableTopLevelLocalWithInitializer = null : #t5{core::int?};
+  function #nullableTopLevelLocalWithInitializer#set(core::int? #t6) → dynamic
+    return nullableTopLevelLocalWithInitializer = #t6;
+  core::int? nonNullableTopLevelLocalWithInitializer;
+  function #nonNullableTopLevelLocalWithInitializer#get() → core::int
+    return let final core::int? #t7 = nonNullableTopLevelLocalWithInitializer in #t7.==(null) ?{core::int} nonNullableTopLevelLocalWithInitializer = 0 : #t7{core::int};
+  function #nonNullableTopLevelLocalWithInitializer#set(core::int #t8) → dynamic
+    return nonNullableTopLevelLocalWithInitializer = #t8;
+  final core::int? nullableFinalTopLevelLocal = _in::createSentinel<core::int?>();
+  function #nullableFinalTopLevelLocal#get() → core::int?
+    return let final core::int? #t9 = nullableFinalTopLevelLocal in _in::isSentinel(#t9) ?{core::int?} throw new _in::LateInitializationErrorImpl::•("Local 'nullableFinalTopLevelLocal' has not been initialized.") : #t9{core::int?};
+  function #nullableFinalTopLevelLocal#set(core::int? #t10) → dynamic
+    if(_in::isSentinel(nullableFinalTopLevelLocal))
+      return nullableFinalTopLevelLocal = #t10;
+    else
+      throw new _in::LateInitializationErrorImpl::•("Local 'nullableFinalTopLevelLocal' has already been initialized.");
+  final core::int? nonNullableFinalTopLevelLocal;
+  function #nonNullableFinalTopLevelLocal#get() → core::int
+    return let final core::int? #t11 = nonNullableFinalTopLevelLocal in #t11.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Local 'nonNullableFinalTopLevelLocal' has not been initialized.") : #t11{core::int};
+  function #nonNullableFinalTopLevelLocal#set(core::int #t12) → dynamic
+    if(nonNullableFinalTopLevelLocal.==(null))
+      return nonNullableFinalTopLevelLocal = #t12;
+    else
+      throw new _in::LateInitializationErrorImpl::•("Local 'nonNullableFinalTopLevelLocal' has already been initialized.");
+  final core::int? nullableFinalTopLevelLocalWithInitializer = _in::createSentinel<core::int?>();
+  function #nullableFinalTopLevelLocalWithInitializer#get() → core::int?
+    return let final core::int? #t13 = nullableFinalTopLevelLocalWithInitializer in _in::isSentinel(#t13) ?{core::int?} nullableFinalTopLevelLocalWithInitializer = null : #t13{core::int?};
+  final core::int? nonNullableFinalTopLevelLocalWithInitializer;
+  function #nonNullableFinalTopLevelLocalWithInitializer#get() → core::int
+    return let final core::int? #t14 = nonNullableFinalTopLevelLocalWithInitializer in #t14.==(null) ?{core::int} nonNullableFinalTopLevelLocalWithInitializer = 0 : #t14{core::int};
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.textual_outline.expect b/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.textual_outline.expect
new file mode 100644
index 0000000..ec6b9e0
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.textual_outline.expect
@@ -0,0 +1,2 @@
+test() {}
+main() {}
diff --git a/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..f67dbb0
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.textual_outline_modelled.expect
@@ -0,0 +1,2 @@
+main() {}
+test() {}
diff --git a/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.weak.expect b/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.weak.expect
new file mode 100644
index 0000000..aace5e6
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.weak.expect
@@ -0,0 +1,50 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+static method test() → dynamic {
+  core::int? nullableTopLevelLocal = _in::createSentinel<core::int?>();
+  function #nullableTopLevelLocal#get() → core::int?
+    return let final core::int? #t1 = nullableTopLevelLocal in _in::isSentinel(#t1) ?{core::int?} throw new _in::LateInitializationErrorImpl::•("Local 'nullableTopLevelLocal' has not been initialized.") : #t1{core::int?};
+  function #nullableTopLevelLocal#set(core::int? #t2) → dynamic
+    return nullableTopLevelLocal = #t2;
+  core::int? nonNullableTopLevelLocal;
+  function #nonNullableTopLevelLocal#get() → core::int
+    return let final core::int? #t3 = nonNullableTopLevelLocal in #t3.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Local 'nonNullableTopLevelLocal' has not been initialized.") : #t3{core::int};
+  function #nonNullableTopLevelLocal#set(core::int #t4) → dynamic
+    return nonNullableTopLevelLocal = #t4;
+  core::int? nullableTopLevelLocalWithInitializer = _in::createSentinel<core::int?>();
+  function #nullableTopLevelLocalWithInitializer#get() → core::int?
+    return let final core::int? #t5 = nullableTopLevelLocalWithInitializer in _in::isSentinel(#t5) ?{core::int?} nullableTopLevelLocalWithInitializer = null : #t5{core::int?};
+  function #nullableTopLevelLocalWithInitializer#set(core::int? #t6) → dynamic
+    return nullableTopLevelLocalWithInitializer = #t6;
+  core::int? nonNullableTopLevelLocalWithInitializer;
+  function #nonNullableTopLevelLocalWithInitializer#get() → core::int
+    return let final core::int? #t7 = nonNullableTopLevelLocalWithInitializer in #t7.==(null) ?{core::int} nonNullableTopLevelLocalWithInitializer = 0 : #t7{core::int};
+  function #nonNullableTopLevelLocalWithInitializer#set(core::int #t8) → dynamic
+    return nonNullableTopLevelLocalWithInitializer = #t8;
+  final core::int? nullableFinalTopLevelLocal = _in::createSentinel<core::int?>();
+  function #nullableFinalTopLevelLocal#get() → core::int?
+    return let final core::int? #t9 = nullableFinalTopLevelLocal in _in::isSentinel(#t9) ?{core::int?} throw new _in::LateInitializationErrorImpl::•("Local 'nullableFinalTopLevelLocal' has not been initialized.") : #t9{core::int?};
+  function #nullableFinalTopLevelLocal#set(core::int? #t10) → dynamic
+    if(_in::isSentinel(nullableFinalTopLevelLocal))
+      return nullableFinalTopLevelLocal = #t10;
+    else
+      throw new _in::LateInitializationErrorImpl::•("Local 'nullableFinalTopLevelLocal' has already been initialized.");
+  final core::int? nonNullableFinalTopLevelLocal;
+  function #nonNullableFinalTopLevelLocal#get() → core::int
+    return let final core::int? #t11 = nonNullableFinalTopLevelLocal in #t11.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Local 'nonNullableFinalTopLevelLocal' has not been initialized.") : #t11{core::int};
+  function #nonNullableFinalTopLevelLocal#set(core::int #t12) → dynamic
+    if(nonNullableFinalTopLevelLocal.==(null))
+      return nonNullableFinalTopLevelLocal = #t12;
+    else
+      throw new _in::LateInitializationErrorImpl::•("Local 'nonNullableFinalTopLevelLocal' has already been initialized.");
+  final core::int? nullableFinalTopLevelLocalWithInitializer = _in::createSentinel<core::int?>();
+  function #nullableFinalTopLevelLocalWithInitializer#get() → core::int?
+    return let final core::int? #t13 = nullableFinalTopLevelLocalWithInitializer in _in::isSentinel(#t13) ?{core::int?} nullableFinalTopLevelLocalWithInitializer = null : #t13{core::int?};
+  final core::int? nonNullableFinalTopLevelLocalWithInitializer;
+  function #nonNullableFinalTopLevelLocalWithInitializer#get() → core::int
+    return let final core::int? #t14 = nonNullableFinalTopLevelLocalWithInitializer in #t14.==(null) ?{core::int} nonNullableFinalTopLevelLocalWithInitializer = 0 : #t14{core::int};
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.weak.transformed.expect b/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.weak.transformed.expect
new file mode 100644
index 0000000..aace5e6
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering_sentinel/late_locals.dart.weak.transformed.expect
@@ -0,0 +1,50 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:_internal" as _in;
+
+static method test() → dynamic {
+  core::int? nullableTopLevelLocal = _in::createSentinel<core::int?>();
+  function #nullableTopLevelLocal#get() → core::int?
+    return let final core::int? #t1 = nullableTopLevelLocal in _in::isSentinel(#t1) ?{core::int?} throw new _in::LateInitializationErrorImpl::•("Local 'nullableTopLevelLocal' has not been initialized.") : #t1{core::int?};
+  function #nullableTopLevelLocal#set(core::int? #t2) → dynamic
+    return nullableTopLevelLocal = #t2;
+  core::int? nonNullableTopLevelLocal;
+  function #nonNullableTopLevelLocal#get() → core::int
+    return let final core::int? #t3 = nonNullableTopLevelLocal in #t3.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Local 'nonNullableTopLevelLocal' has not been initialized.") : #t3{core::int};
+  function #nonNullableTopLevelLocal#set(core::int #t4) → dynamic
+    return nonNullableTopLevelLocal = #t4;
+  core::int? nullableTopLevelLocalWithInitializer = _in::createSentinel<core::int?>();
+  function #nullableTopLevelLocalWithInitializer#get() → core::int?
+    return let final core::int? #t5 = nullableTopLevelLocalWithInitializer in _in::isSentinel(#t5) ?{core::int?} nullableTopLevelLocalWithInitializer = null : #t5{core::int?};
+  function #nullableTopLevelLocalWithInitializer#set(core::int? #t6) → dynamic
+    return nullableTopLevelLocalWithInitializer = #t6;
+  core::int? nonNullableTopLevelLocalWithInitializer;
+  function #nonNullableTopLevelLocalWithInitializer#get() → core::int
+    return let final core::int? #t7 = nonNullableTopLevelLocalWithInitializer in #t7.==(null) ?{core::int} nonNullableTopLevelLocalWithInitializer = 0 : #t7{core::int};
+  function #nonNullableTopLevelLocalWithInitializer#set(core::int #t8) → dynamic
+    return nonNullableTopLevelLocalWithInitializer = #t8;
+  final core::int? nullableFinalTopLevelLocal = _in::createSentinel<core::int?>();
+  function #nullableFinalTopLevelLocal#get() → core::int?
+    return let final core::int? #t9 = nullableFinalTopLevelLocal in _in::isSentinel(#t9) ?{core::int?} throw new _in::LateInitializationErrorImpl::•("Local 'nullableFinalTopLevelLocal' has not been initialized.") : #t9{core::int?};
+  function #nullableFinalTopLevelLocal#set(core::int? #t10) → dynamic
+    if(_in::isSentinel(nullableFinalTopLevelLocal))
+      return nullableFinalTopLevelLocal = #t10;
+    else
+      throw new _in::LateInitializationErrorImpl::•("Local 'nullableFinalTopLevelLocal' has already been initialized.");
+  final core::int? nonNullableFinalTopLevelLocal;
+  function #nonNullableFinalTopLevelLocal#get() → core::int
+    return let final core::int? #t11 = nonNullableFinalTopLevelLocal in #t11.==(null) ?{core::int} throw new _in::LateInitializationErrorImpl::•("Local 'nonNullableFinalTopLevelLocal' has not been initialized.") : #t11{core::int};
+  function #nonNullableFinalTopLevelLocal#set(core::int #t12) → dynamic
+    if(nonNullableFinalTopLevelLocal.==(null))
+      return nonNullableFinalTopLevelLocal = #t12;
+    else
+      throw new _in::LateInitializationErrorImpl::•("Local 'nonNullableFinalTopLevelLocal' has already been initialized.");
+  final core::int? nullableFinalTopLevelLocalWithInitializer = _in::createSentinel<core::int?>();
+  function #nullableFinalTopLevelLocalWithInitializer#get() → core::int?
+    return let final core::int? #t13 = nullableFinalTopLevelLocalWithInitializer in _in::isSentinel(#t13) ?{core::int?} nullableFinalTopLevelLocalWithInitializer = null : #t13{core::int?};
+  final core::int? nonNullableFinalTopLevelLocalWithInitializer;
+  function #nonNullableFinalTopLevelLocalWithInitializer#get() → core::int
+    return let final core::int? #t14 = nonNullableFinalTopLevelLocalWithInitializer in #t14.==(null) ?{core::int} nonNullableFinalTopLevelLocalWithInitializer = 0 : #t14{core::int};
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/abstract_field_errors.dart.outline.expect b/pkg/front_end/testcases/nnbd/abstract_field_errors.dart.outline.expect
index 4ac62a9..6bc5231 100644
--- a/pkg/front_end/testcases/nnbd/abstract_field_errors.dart.outline.expect
+++ b/pkg/front_end/testcases/nnbd/abstract_field_errors.dart.outline.expect
@@ -188,27 +188,27 @@
   constructor •(core::int initializedField1) → self::A
     ;
   abstract get fieldWithInitializer() → core::int;
-  abstract set fieldWithInitializer(core::int #t1) → void;
+  abstract set fieldWithInitializer(core::int #externalFieldValue) → void;
   abstract get initializedField1() → core::int;
-  abstract set initializedField1(core::int #t2) → void;
+  abstract set initializedField1(core::int #externalFieldValue) → void;
   abstract get initializedField2() → core::int;
-  abstract set initializedField2(core::int #t3) → void;
+  abstract set initializedField2(core::int #externalFieldValue) → void;
   external get externalInstanceField() → core::int;
-  external set externalInstanceField(core::int #t4) → void;
+  external set externalInstanceField(core::int #externalFieldValue) → void;
   external get externalFinalInstanceField() → core::int;
   external get externalCovariantInstanceField() → core::num;
-  external set externalCovariantInstanceField(covariant core::num #t5) → void;
+  external set externalCovariantInstanceField(covariant core::num #externalFieldValue) → void;
   external get externalLateInstanceField() → core::int;
-  external set externalLateInstanceField(core::int #t6) → void;
+  external set externalLateInstanceField(core::int #externalFieldValue) → void;
 }
 abstract class B extends core::Object /*isMixinDeclaration*/  {
   static field core::int staticField;
   static final field core::int finalStaticField;
   external get externalInstanceField() → core::int;
-  external set externalInstanceField(core::int #t7) → void;
+  external set externalInstanceField(core::int #externalFieldValue) → void;
   external get externalFinalInstanceField() → core::int;
   external get externalCovariantInstanceField() → core::num;
-  external set externalCovariantInstanceField(covariant core::num #t8) → void;
+  external set externalCovariantInstanceField(covariant core::num #externalFieldValue) → void;
 }
 extension Extension on self::A {
   get extensionInstanceField = get self::Extension|extensionInstanceField;
@@ -223,7 +223,7 @@
 static field core::int Extension|extensionStaticField;
 static final field core::int Extension|finalExtensionStaticField;
 static abstract get Extension|extensionInstanceField() → core::int;
-static abstract set Extension|extensionInstanceField(core::int #t9) → void;
+static abstract set Extension|extensionInstanceField(core::int #externalFieldValue) → void;
 static abstract get Extension|finalExtensionInstanceField() → core::int;
 static method main() → dynamic
   ;
diff --git a/pkg/front_end/testcases/nnbd/abstract_field_errors.dart.strong.expect b/pkg/front_end/testcases/nnbd/abstract_field_errors.dart.strong.expect
index 8181af4..fa28c87 100644
--- a/pkg/front_end/testcases/nnbd/abstract_field_errors.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/abstract_field_errors.dart.strong.expect
@@ -220,27 +220,27 @@
                                    ^^^^^^^^^^^^^^^^^"
     ;
   abstract get fieldWithInitializer() → core::int;
-  abstract set fieldWithInitializer(core::int #t3) → void;
+  abstract set fieldWithInitializer(core::int #externalFieldValue) → void;
   abstract get initializedField1() → core::int;
-  abstract set initializedField1(core::int #t4) → void;
+  abstract set initializedField1(core::int #externalFieldValue) → void;
   abstract get initializedField2() → core::int;
-  abstract set initializedField2(core::int #t5) → void;
+  abstract set initializedField2(core::int #externalFieldValue) → void;
   external get externalInstanceField() → core::int;
-  external set externalInstanceField(core::int #t6) → void;
+  external set externalInstanceField(core::int #externalFieldValue) → void;
   external get externalFinalInstanceField() → core::int;
   external get externalCovariantInstanceField() → core::num;
-  external set externalCovariantInstanceField(covariant core::num #t7) → void;
+  external set externalCovariantInstanceField(covariant core::num #externalFieldValue) → void;
   external get externalLateInstanceField() → core::int;
-  external set externalLateInstanceField(core::int #t8) → void;
+  external set externalLateInstanceField(core::int #externalFieldValue) → void;
 }
 abstract class B extends core::Object /*isMixinDeclaration*/  {
   static field core::int staticField = null;
   static final field core::int finalStaticField = null;
   external get externalInstanceField() → core::int;
-  external set externalInstanceField(core::int #t9) → void;
+  external set externalInstanceField(core::int #externalFieldValue) → void;
   external get externalFinalInstanceField() → core::int;
   external get externalCovariantInstanceField() → core::num;
-  external set externalCovariantInstanceField(covariant core::num #t10) → void;
+  external set externalCovariantInstanceField(covariant core::num #externalFieldValue) → void;
 }
 extension Extension on self::A {
   get extensionInstanceField = get self::Extension|extensionInstanceField;
@@ -255,7 +255,7 @@
 static field core::int Extension|extensionStaticField;
 static final field core::int Extension|finalExtensionStaticField;
 static abstract get Extension|extensionInstanceField() → core::int;
-static abstract set Extension|extensionInstanceField(core::int #t11) → void;
+static abstract set Extension|extensionInstanceField(core::int #externalFieldValue) → void;
 static abstract get Extension|finalExtensionInstanceField() → core::int;
 static method main() → dynamic {}
 
diff --git a/pkg/front_end/testcases/nnbd/abstract_field_errors.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/abstract_field_errors.dart.strong.transformed.expect
index 8181af4..fa28c87 100644
--- a/pkg/front_end/testcases/nnbd/abstract_field_errors.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/abstract_field_errors.dart.strong.transformed.expect
@@ -220,27 +220,27 @@
                                    ^^^^^^^^^^^^^^^^^"
     ;
   abstract get fieldWithInitializer() → core::int;
-  abstract set fieldWithInitializer(core::int #t3) → void;
+  abstract set fieldWithInitializer(core::int #externalFieldValue) → void;
   abstract get initializedField1() → core::int;
-  abstract set initializedField1(core::int #t4) → void;
+  abstract set initializedField1(core::int #externalFieldValue) → void;
   abstract get initializedField2() → core::int;
-  abstract set initializedField2(core::int #t5) → void;
+  abstract set initializedField2(core::int #externalFieldValue) → void;
   external get externalInstanceField() → core::int;
-  external set externalInstanceField(core::int #t6) → void;
+  external set externalInstanceField(core::int #externalFieldValue) → void;
   external get externalFinalInstanceField() → core::int;
   external get externalCovariantInstanceField() → core::num;
-  external set externalCovariantInstanceField(covariant core::num #t7) → void;
+  external set externalCovariantInstanceField(covariant core::num #externalFieldValue) → void;
   external get externalLateInstanceField() → core::int;
-  external set externalLateInstanceField(core::int #t8) → void;
+  external set externalLateInstanceField(core::int #externalFieldValue) → void;
 }
 abstract class B extends core::Object /*isMixinDeclaration*/  {
   static field core::int staticField = null;
   static final field core::int finalStaticField = null;
   external get externalInstanceField() → core::int;
-  external set externalInstanceField(core::int #t9) → void;
+  external set externalInstanceField(core::int #externalFieldValue) → void;
   external get externalFinalInstanceField() → core::int;
   external get externalCovariantInstanceField() → core::num;
-  external set externalCovariantInstanceField(covariant core::num #t10) → void;
+  external set externalCovariantInstanceField(covariant core::num #externalFieldValue) → void;
 }
 extension Extension on self::A {
   get extensionInstanceField = get self::Extension|extensionInstanceField;
@@ -255,7 +255,7 @@
 static field core::int Extension|extensionStaticField;
 static final field core::int Extension|finalExtensionStaticField;
 static abstract get Extension|extensionInstanceField() → core::int;
-static abstract set Extension|extensionInstanceField(core::int #t11) → void;
+static abstract set Extension|extensionInstanceField(core::int #externalFieldValue) → void;
 static abstract get Extension|finalExtensionInstanceField() → core::int;
 static method main() → dynamic {}
 
diff --git a/pkg/front_end/testcases/nnbd/abstract_field_errors.dart.weak.expect b/pkg/front_end/testcases/nnbd/abstract_field_errors.dart.weak.expect
index 8181af4..fa28c87 100644
--- a/pkg/front_end/testcases/nnbd/abstract_field_errors.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/abstract_field_errors.dart.weak.expect
@@ -220,27 +220,27 @@
                                    ^^^^^^^^^^^^^^^^^"
     ;
   abstract get fieldWithInitializer() → core::int;
-  abstract set fieldWithInitializer(core::int #t3) → void;
+  abstract set fieldWithInitializer(core::int #externalFieldValue) → void;
   abstract get initializedField1() → core::int;
-  abstract set initializedField1(core::int #t4) → void;
+  abstract set initializedField1(core::int #externalFieldValue) → void;
   abstract get initializedField2() → core::int;
-  abstract set initializedField2(core::int #t5) → void;
+  abstract set initializedField2(core::int #externalFieldValue) → void;
   external get externalInstanceField() → core::int;
-  external set externalInstanceField(core::int #t6) → void;
+  external set externalInstanceField(core::int #externalFieldValue) → void;
   external get externalFinalInstanceField() → core::int;
   external get externalCovariantInstanceField() → core::num;
-  external set externalCovariantInstanceField(covariant core::num #t7) → void;
+  external set externalCovariantInstanceField(covariant core::num #externalFieldValue) → void;
   external get externalLateInstanceField() → core::int;
-  external set externalLateInstanceField(core::int #t8) → void;
+  external set externalLateInstanceField(core::int #externalFieldValue) → void;
 }
 abstract class B extends core::Object /*isMixinDeclaration*/  {
   static field core::int staticField = null;
   static final field core::int finalStaticField = null;
   external get externalInstanceField() → core::int;
-  external set externalInstanceField(core::int #t9) → void;
+  external set externalInstanceField(core::int #externalFieldValue) → void;
   external get externalFinalInstanceField() → core::int;
   external get externalCovariantInstanceField() → core::num;
-  external set externalCovariantInstanceField(covariant core::num #t10) → void;
+  external set externalCovariantInstanceField(covariant core::num #externalFieldValue) → void;
 }
 extension Extension on self::A {
   get extensionInstanceField = get self::Extension|extensionInstanceField;
@@ -255,7 +255,7 @@
 static field core::int Extension|extensionStaticField;
 static final field core::int Extension|finalExtensionStaticField;
 static abstract get Extension|extensionInstanceField() → core::int;
-static abstract set Extension|extensionInstanceField(core::int #t11) → void;
+static abstract set Extension|extensionInstanceField(core::int #externalFieldValue) → void;
 static abstract get Extension|finalExtensionInstanceField() → core::int;
 static method main() → dynamic {}
 
diff --git a/pkg/front_end/testcases/nnbd/abstract_field_errors.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/abstract_field_errors.dart.weak.transformed.expect
index 8181af4..fa28c87 100644
--- a/pkg/front_end/testcases/nnbd/abstract_field_errors.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/abstract_field_errors.dart.weak.transformed.expect
@@ -220,27 +220,27 @@
                                    ^^^^^^^^^^^^^^^^^"
     ;
   abstract get fieldWithInitializer() → core::int;
-  abstract set fieldWithInitializer(core::int #t3) → void;
+  abstract set fieldWithInitializer(core::int #externalFieldValue) → void;
   abstract get initializedField1() → core::int;
-  abstract set initializedField1(core::int #t4) → void;
+  abstract set initializedField1(core::int #externalFieldValue) → void;
   abstract get initializedField2() → core::int;
-  abstract set initializedField2(core::int #t5) → void;
+  abstract set initializedField2(core::int #externalFieldValue) → void;
   external get externalInstanceField() → core::int;
-  external set externalInstanceField(core::int #t6) → void;
+  external set externalInstanceField(core::int #externalFieldValue) → void;
   external get externalFinalInstanceField() → core::int;
   external get externalCovariantInstanceField() → core::num;
-  external set externalCovariantInstanceField(covariant core::num #t7) → void;
+  external set externalCovariantInstanceField(covariant core::num #externalFieldValue) → void;
   external get externalLateInstanceField() → core::int;
-  external set externalLateInstanceField(core::int #t8) → void;
+  external set externalLateInstanceField(core::int #externalFieldValue) → void;
 }
 abstract class B extends core::Object /*isMixinDeclaration*/  {
   static field core::int staticField = null;
   static final field core::int finalStaticField = null;
   external get externalInstanceField() → core::int;
-  external set externalInstanceField(core::int #t9) → void;
+  external set externalInstanceField(core::int #externalFieldValue) → void;
   external get externalFinalInstanceField() → core::int;
   external get externalCovariantInstanceField() → core::num;
-  external set externalCovariantInstanceField(covariant core::num #t10) → void;
+  external set externalCovariantInstanceField(covariant core::num #externalFieldValue) → void;
 }
 extension Extension on self::A {
   get extensionInstanceField = get self::Extension|extensionInstanceField;
@@ -255,7 +255,7 @@
 static field core::int Extension|extensionStaticField;
 static final field core::int Extension|finalExtensionStaticField;
 static abstract get Extension|extensionInstanceField() → core::int;
-static abstract set Extension|extensionInstanceField(core::int #t11) → void;
+static abstract set Extension|extensionInstanceField(core::int #externalFieldValue) → void;
 static abstract get Extension|finalExtensionInstanceField() → core::int;
 static method main() → dynamic {}
 
diff --git a/pkg/front_end/testcases/nnbd/abstract_fields.dart.outline.expect b/pkg/front_end/testcases/nnbd/abstract_fields.dart.outline.expect
index e13a36a..ff6c1e2 100644
--- a/pkg/front_end/testcases/nnbd/abstract_fields.dart.outline.expect
+++ b/pkg/front_end/testcases/nnbd/abstract_fields.dart.outline.expect
@@ -6,17 +6,17 @@
   synthetic constructor •() → self::A
     ;
   abstract get instanceField() → core::int;
-  abstract set instanceField(core::int #t1) → void;
+  abstract set instanceField(core::int #externalFieldValue) → void;
   abstract get finalInstanceField() → core::int;
   abstract get covariantInstanceField() → core::num;
-  abstract set covariantInstanceField(covariant core::num #t2) → void;
+  abstract set covariantInstanceField(covariant core::num #externalFieldValue) → void;
 }
 abstract class B extends core::Object /*isMixinDeclaration*/  {
   abstract get instanceField() → core::int;
-  abstract set instanceField(core::int #t3) → void;
+  abstract set instanceField(core::int #externalFieldValue) → void;
   abstract get finalInstanceField() → core::int;
   abstract get covariantInstanceField() → core::num;
-  abstract set covariantInstanceField(covariant core::num #t4) → void;
+  abstract set covariantInstanceField(covariant core::num #externalFieldValue) → void;
 }
 static method main() → dynamic
   ;
diff --git a/pkg/front_end/testcases/nnbd/abstract_fields.dart.strong.expect b/pkg/front_end/testcases/nnbd/abstract_fields.dart.strong.expect
index d5823fb..3e5529f 100644
--- a/pkg/front_end/testcases/nnbd/abstract_fields.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/abstract_fields.dart.strong.expect
@@ -7,16 +7,16 @@
     : super core::Object::•()
     ;
   abstract get instanceField() → core::int;
-  abstract set instanceField(core::int #t1) → void;
+  abstract set instanceField(core::int #externalFieldValue) → void;
   abstract get finalInstanceField() → core::int;
   abstract get covariantInstanceField() → core::num;
-  abstract set covariantInstanceField(covariant core::num #t2) → void;
+  abstract set covariantInstanceField(covariant core::num #externalFieldValue) → void;
 }
 abstract class B extends core::Object /*isMixinDeclaration*/  {
   abstract get instanceField() → core::int;
-  abstract set instanceField(core::int #t3) → void;
+  abstract set instanceField(core::int #externalFieldValue) → void;
   abstract get finalInstanceField() → core::int;
   abstract get covariantInstanceField() → core::num;
-  abstract set covariantInstanceField(covariant core::num #t4) → void;
+  abstract set covariantInstanceField(covariant core::num #externalFieldValue) → void;
 }
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/abstract_fields.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/abstract_fields.dart.strong.transformed.expect
index d5823fb..3e5529f 100644
--- a/pkg/front_end/testcases/nnbd/abstract_fields.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/abstract_fields.dart.strong.transformed.expect
@@ -7,16 +7,16 @@
     : super core::Object::•()
     ;
   abstract get instanceField() → core::int;
-  abstract set instanceField(core::int #t1) → void;
+  abstract set instanceField(core::int #externalFieldValue) → void;
   abstract get finalInstanceField() → core::int;
   abstract get covariantInstanceField() → core::num;
-  abstract set covariantInstanceField(covariant core::num #t2) → void;
+  abstract set covariantInstanceField(covariant core::num #externalFieldValue) → void;
 }
 abstract class B extends core::Object /*isMixinDeclaration*/  {
   abstract get instanceField() → core::int;
-  abstract set instanceField(core::int #t3) → void;
+  abstract set instanceField(core::int #externalFieldValue) → void;
   abstract get finalInstanceField() → core::int;
   abstract get covariantInstanceField() → core::num;
-  abstract set covariantInstanceField(covariant core::num #t4) → void;
+  abstract set covariantInstanceField(covariant core::num #externalFieldValue) → void;
 }
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/abstract_fields.dart.weak.expect b/pkg/front_end/testcases/nnbd/abstract_fields.dart.weak.expect
index d5823fb..3e5529f 100644
--- a/pkg/front_end/testcases/nnbd/abstract_fields.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/abstract_fields.dart.weak.expect
@@ -7,16 +7,16 @@
     : super core::Object::•()
     ;
   abstract get instanceField() → core::int;
-  abstract set instanceField(core::int #t1) → void;
+  abstract set instanceField(core::int #externalFieldValue) → void;
   abstract get finalInstanceField() → core::int;
   abstract get covariantInstanceField() → core::num;
-  abstract set covariantInstanceField(covariant core::num #t2) → void;
+  abstract set covariantInstanceField(covariant core::num #externalFieldValue) → void;
 }
 abstract class B extends core::Object /*isMixinDeclaration*/  {
   abstract get instanceField() → core::int;
-  abstract set instanceField(core::int #t3) → void;
+  abstract set instanceField(core::int #externalFieldValue) → void;
   abstract get finalInstanceField() → core::int;
   abstract get covariantInstanceField() → core::num;
-  abstract set covariantInstanceField(covariant core::num #t4) → void;
+  abstract set covariantInstanceField(covariant core::num #externalFieldValue) → void;
 }
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/abstract_fields.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/abstract_fields.dart.weak.transformed.expect
index d5823fb..3e5529f 100644
--- a/pkg/front_end/testcases/nnbd/abstract_fields.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/abstract_fields.dart.weak.transformed.expect
@@ -7,16 +7,16 @@
     : super core::Object::•()
     ;
   abstract get instanceField() → core::int;
-  abstract set instanceField(core::int #t1) → void;
+  abstract set instanceField(core::int #externalFieldValue) → void;
   abstract get finalInstanceField() → core::int;
   abstract get covariantInstanceField() → core::num;
-  abstract set covariantInstanceField(covariant core::num #t2) → void;
+  abstract set covariantInstanceField(covariant core::num #externalFieldValue) → void;
 }
 abstract class B extends core::Object /*isMixinDeclaration*/  {
   abstract get instanceField() → core::int;
-  abstract set instanceField(core::int #t3) → void;
+  abstract set instanceField(core::int #externalFieldValue) → void;
   abstract get finalInstanceField() → core::int;
   abstract get covariantInstanceField() → core::num;
-  abstract set covariantInstanceField(covariant core::num #t4) → void;
+  abstract set covariantInstanceField(covariant core::num #externalFieldValue) → void;
 }
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/abstract_fields_spec.dart.outline.expect b/pkg/front_end/testcases/nnbd/abstract_fields_spec.dart.outline.expect
index 492b9a7..21e1617 100644
--- a/pkg/front_end/testcases/nnbd/abstract_fields_spec.dart.outline.expect
+++ b/pkg/front_end/testcases/nnbd/abstract_fields_spec.dart.outline.expect
@@ -6,17 +6,17 @@
   synthetic constructor •() → self::A
     ;
   abstract get i1() → core::int;
-  abstract set i1(core::int #t1) → void;
+  abstract set i1(core::int #externalFieldValue) → void;
   abstract get i2() → core::int;
-  abstract set i2(core::int #t2) → void;
+  abstract set i2(core::int #externalFieldValue) → void;
   abstract get x() → dynamic;
-  abstract set x(dynamic #t3) → void;
+  abstract set x(dynamic #externalFieldValue) → void;
   abstract get fi() → core::int;
   abstract get fx() → dynamic;
   abstract get cn() → core::num;
-  abstract set cn(covariant core::num #t4) → void;
+  abstract set cn(covariant core::num #externalFieldValue) → void;
   abstract get cx() → dynamic;
-  abstract set cx(covariant dynamic #t5) → void;
+  abstract set cx(covariant dynamic #externalFieldValue) → void;
 }
 static method main() → dynamic
   ;
diff --git a/pkg/front_end/testcases/nnbd/abstract_fields_spec.dart.strong.expect b/pkg/front_end/testcases/nnbd/abstract_fields_spec.dart.strong.expect
index 345a7f1..c91e11c 100644
--- a/pkg/front_end/testcases/nnbd/abstract_fields_spec.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/abstract_fields_spec.dart.strong.expect
@@ -7,16 +7,16 @@
     : super core::Object::•()
     ;
   abstract get i1() → core::int;
-  abstract set i1(core::int #t1) → void;
+  abstract set i1(core::int #externalFieldValue) → void;
   abstract get i2() → core::int;
-  abstract set i2(core::int #t2) → void;
+  abstract set i2(core::int #externalFieldValue) → void;
   abstract get x() → dynamic;
-  abstract set x(dynamic #t3) → void;
+  abstract set x(dynamic #externalFieldValue) → void;
   abstract get fi() → core::int;
   abstract get fx() → dynamic;
   abstract get cn() → core::num;
-  abstract set cn(covariant core::num #t4) → void;
+  abstract set cn(covariant core::num #externalFieldValue) → void;
   abstract get cx() → dynamic;
-  abstract set cx(covariant dynamic #t5) → void;
+  abstract set cx(covariant dynamic #externalFieldValue) → void;
 }
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/abstract_fields_spec.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/abstract_fields_spec.dart.strong.transformed.expect
index 345a7f1..c91e11c 100644
--- a/pkg/front_end/testcases/nnbd/abstract_fields_spec.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/abstract_fields_spec.dart.strong.transformed.expect
@@ -7,16 +7,16 @@
     : super core::Object::•()
     ;
   abstract get i1() → core::int;
-  abstract set i1(core::int #t1) → void;
+  abstract set i1(core::int #externalFieldValue) → void;
   abstract get i2() → core::int;
-  abstract set i2(core::int #t2) → void;
+  abstract set i2(core::int #externalFieldValue) → void;
   abstract get x() → dynamic;
-  abstract set x(dynamic #t3) → void;
+  abstract set x(dynamic #externalFieldValue) → void;
   abstract get fi() → core::int;
   abstract get fx() → dynamic;
   abstract get cn() → core::num;
-  abstract set cn(covariant core::num #t4) → void;
+  abstract set cn(covariant core::num #externalFieldValue) → void;
   abstract get cx() → dynamic;
-  abstract set cx(covariant dynamic #t5) → void;
+  abstract set cx(covariant dynamic #externalFieldValue) → void;
 }
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/abstract_fields_spec.dart.weak.expect b/pkg/front_end/testcases/nnbd/abstract_fields_spec.dart.weak.expect
index 345a7f1..c91e11c 100644
--- a/pkg/front_end/testcases/nnbd/abstract_fields_spec.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/abstract_fields_spec.dart.weak.expect
@@ -7,16 +7,16 @@
     : super core::Object::•()
     ;
   abstract get i1() → core::int;
-  abstract set i1(core::int #t1) → void;
+  abstract set i1(core::int #externalFieldValue) → void;
   abstract get i2() → core::int;
-  abstract set i2(core::int #t2) → void;
+  abstract set i2(core::int #externalFieldValue) → void;
   abstract get x() → dynamic;
-  abstract set x(dynamic #t3) → void;
+  abstract set x(dynamic #externalFieldValue) → void;
   abstract get fi() → core::int;
   abstract get fx() → dynamic;
   abstract get cn() → core::num;
-  abstract set cn(covariant core::num #t4) → void;
+  abstract set cn(covariant core::num #externalFieldValue) → void;
   abstract get cx() → dynamic;
-  abstract set cx(covariant dynamic #t5) → void;
+  abstract set cx(covariant dynamic #externalFieldValue) → void;
 }
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/abstract_fields_spec.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/abstract_fields_spec.dart.weak.transformed.expect
index 345a7f1..c91e11c 100644
--- a/pkg/front_end/testcases/nnbd/abstract_fields_spec.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/abstract_fields_spec.dart.weak.transformed.expect
@@ -7,16 +7,16 @@
     : super core::Object::•()
     ;
   abstract get i1() → core::int;
-  abstract set i1(core::int #t1) → void;
+  abstract set i1(core::int #externalFieldValue) → void;
   abstract get i2() → core::int;
-  abstract set i2(core::int #t2) → void;
+  abstract set i2(core::int #externalFieldValue) → void;
   abstract get x() → dynamic;
-  abstract set x(dynamic #t3) → void;
+  abstract set x(dynamic #externalFieldValue) → void;
   abstract get fi() → core::int;
   abstract get fx() → dynamic;
   abstract get cn() → core::num;
-  abstract set cn(covariant core::num #t4) → void;
+  abstract set cn(covariant core::num #externalFieldValue) → void;
   abstract get cx() → dynamic;
-  abstract set cx(covariant dynamic #t5) → void;
+  abstract set cx(covariant dynamic #externalFieldValue) → void;
 }
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/external_field_errors.dart.outline.expect b/pkg/front_end/testcases/nnbd/external_field_errors.dart.outline.expect
index 197f942..d92b2fe 100644
--- a/pkg/front_end/testcases/nnbd/external_field_errors.dart.outline.expect
+++ b/pkg/front_end/testcases/nnbd/external_field_errors.dart.outline.expect
@@ -6,18 +6,18 @@
   constructor •(core::int initializedField1) → self::A
     ;
   external get fieldWithInitializer() → core::int;
-  external set fieldWithInitializer(core::int #t1) → void;
+  external set fieldWithInitializer(core::int #externalFieldValue) → void;
   external get initializedField1() → core::int;
-  external set initializedField1(core::int #t2) → void;
+  external set initializedField1(core::int #externalFieldValue) → void;
   external get initializedField2() → core::int;
-  external set initializedField2(core::int #t3) → void;
+  external set initializedField2(core::int #externalFieldValue) → void;
   external static get staticField() → core::int;
-  external static set staticField(core::int #t4) → void;
+  external static set staticField(core::int #externalFieldValue) → void;
   external static get finalStaticField() → core::int;
 }
 abstract class B extends core::Object /*isMixinDeclaration*/  {
   external static get staticField() → core::int;
-  external static set staticField(core::int #t5) → void;
+  external static set staticField(core::int #externalFieldValue) → void;
   external static get finalStaticField() → core::int;
 }
 extension Extension on self::A {
@@ -29,15 +29,15 @@
   static get finalExtensionStaticField = get self::Extension|finalExtensionStaticField;
 }
 external static get topLevelField() → core::int;
-external static set topLevelField(core::int #t6) → void;
+external static set topLevelField(core::int #externalFieldValue) → void;
 external static get finalTopLevelField() → core::int;
 external static get constField() → core::int;
-external static set constField(core::int #t7) → void;
+external static set constField(core::int #externalFieldValue) → void;
 external static get Extension|extensionInstanceField() → core::int;
-external static set Extension|extensionInstanceField(core::int #t8) → void;
+external static set Extension|extensionInstanceField(core::int #externalFieldValue) → void;
 external static get Extension|finalExtensionInstanceField() → core::int;
 external static get Extension|extensionStaticField() → core::int;
-external static set Extension|extensionStaticField(core::int #t9) → void;
+external static set Extension|extensionStaticField(core::int #externalFieldValue) → void;
 external static get Extension|finalExtensionStaticField() → core::int;
 static method main() → dynamic
   ;
diff --git a/pkg/front_end/testcases/nnbd/external_field_errors.dart.strong.expect b/pkg/front_end/testcases/nnbd/external_field_errors.dart.strong.expect
index 895696f..5d4f518 100644
--- a/pkg/front_end/testcases/nnbd/external_field_errors.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/external_field_errors.dart.strong.expect
@@ -86,18 +86,18 @@
                                    ^^^^^^^^^^^^^^^^^"
     ;
   external get fieldWithInitializer() → core::int;
-  external set fieldWithInitializer(core::int #t3) → void;
+  external set fieldWithInitializer(core::int #externalFieldValue) → void;
   external get initializedField1() → core::int;
-  external set initializedField1(core::int #t4) → void;
+  external set initializedField1(core::int #externalFieldValue) → void;
   external get initializedField2() → core::int;
-  external set initializedField2(core::int #t5) → void;
+  external set initializedField2(core::int #externalFieldValue) → void;
   external static get staticField() → core::int;
-  external static set staticField(core::int #t6) → void;
+  external static set staticField(core::int #externalFieldValue) → void;
   external static get finalStaticField() → core::int;
 }
 abstract class B extends core::Object /*isMixinDeclaration*/  {
   external static get staticField() → core::int;
-  external static set staticField(core::int #t7) → void;
+  external static set staticField(core::int #externalFieldValue) → void;
   external static get finalStaticField() → core::int;
 }
 extension Extension on self::A {
@@ -109,14 +109,14 @@
   static get finalExtensionStaticField = get self::Extension|finalExtensionStaticField;
 }
 external static get topLevelField() → core::int;
-external static set topLevelField(core::int #t8) → void;
+external static set topLevelField(core::int #externalFieldValue) → void;
 external static get finalTopLevelField() → core::int;
 external static get constField() → core::int;
-external static set constField(core::int #t9) → void;
+external static set constField(core::int #externalFieldValue) → void;
 external static get Extension|extensionInstanceField() → core::int;
-external static set Extension|extensionInstanceField(core::int #t10) → void;
+external static set Extension|extensionInstanceField(core::int #externalFieldValue) → void;
 external static get Extension|finalExtensionInstanceField() → core::int;
 external static get Extension|extensionStaticField() → core::int;
-external static set Extension|extensionStaticField(core::int #t11) → void;
+external static set Extension|extensionStaticField(core::int #externalFieldValue) → void;
 external static get Extension|finalExtensionStaticField() → core::int;
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/external_field_errors.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/external_field_errors.dart.strong.transformed.expect
index 895696f..5d4f518 100644
--- a/pkg/front_end/testcases/nnbd/external_field_errors.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/external_field_errors.dart.strong.transformed.expect
@@ -86,18 +86,18 @@
                                    ^^^^^^^^^^^^^^^^^"
     ;
   external get fieldWithInitializer() → core::int;
-  external set fieldWithInitializer(core::int #t3) → void;
+  external set fieldWithInitializer(core::int #externalFieldValue) → void;
   external get initializedField1() → core::int;
-  external set initializedField1(core::int #t4) → void;
+  external set initializedField1(core::int #externalFieldValue) → void;
   external get initializedField2() → core::int;
-  external set initializedField2(core::int #t5) → void;
+  external set initializedField2(core::int #externalFieldValue) → void;
   external static get staticField() → core::int;
-  external static set staticField(core::int #t6) → void;
+  external static set staticField(core::int #externalFieldValue) → void;
   external static get finalStaticField() → core::int;
 }
 abstract class B extends core::Object /*isMixinDeclaration*/  {
   external static get staticField() → core::int;
-  external static set staticField(core::int #t7) → void;
+  external static set staticField(core::int #externalFieldValue) → void;
   external static get finalStaticField() → core::int;
 }
 extension Extension on self::A {
@@ -109,14 +109,14 @@
   static get finalExtensionStaticField = get self::Extension|finalExtensionStaticField;
 }
 external static get topLevelField() → core::int;
-external static set topLevelField(core::int #t8) → void;
+external static set topLevelField(core::int #externalFieldValue) → void;
 external static get finalTopLevelField() → core::int;
 external static get constField() → core::int;
-external static set constField(core::int #t9) → void;
+external static set constField(core::int #externalFieldValue) → void;
 external static get Extension|extensionInstanceField() → core::int;
-external static set Extension|extensionInstanceField(core::int #t10) → void;
+external static set Extension|extensionInstanceField(core::int #externalFieldValue) → void;
 external static get Extension|finalExtensionInstanceField() → core::int;
 external static get Extension|extensionStaticField() → core::int;
-external static set Extension|extensionStaticField(core::int #t11) → void;
+external static set Extension|extensionStaticField(core::int #externalFieldValue) → void;
 external static get Extension|finalExtensionStaticField() → core::int;
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/external_field_errors.dart.weak.expect b/pkg/front_end/testcases/nnbd/external_field_errors.dart.weak.expect
index 895696f..5d4f518 100644
--- a/pkg/front_end/testcases/nnbd/external_field_errors.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/external_field_errors.dart.weak.expect
@@ -86,18 +86,18 @@
                                    ^^^^^^^^^^^^^^^^^"
     ;
   external get fieldWithInitializer() → core::int;
-  external set fieldWithInitializer(core::int #t3) → void;
+  external set fieldWithInitializer(core::int #externalFieldValue) → void;
   external get initializedField1() → core::int;
-  external set initializedField1(core::int #t4) → void;
+  external set initializedField1(core::int #externalFieldValue) → void;
   external get initializedField2() → core::int;
-  external set initializedField2(core::int #t5) → void;
+  external set initializedField2(core::int #externalFieldValue) → void;
   external static get staticField() → core::int;
-  external static set staticField(core::int #t6) → void;
+  external static set staticField(core::int #externalFieldValue) → void;
   external static get finalStaticField() → core::int;
 }
 abstract class B extends core::Object /*isMixinDeclaration*/  {
   external static get staticField() → core::int;
-  external static set staticField(core::int #t7) → void;
+  external static set staticField(core::int #externalFieldValue) → void;
   external static get finalStaticField() → core::int;
 }
 extension Extension on self::A {
@@ -109,14 +109,14 @@
   static get finalExtensionStaticField = get self::Extension|finalExtensionStaticField;
 }
 external static get topLevelField() → core::int;
-external static set topLevelField(core::int #t8) → void;
+external static set topLevelField(core::int #externalFieldValue) → void;
 external static get finalTopLevelField() → core::int;
 external static get constField() → core::int;
-external static set constField(core::int #t9) → void;
+external static set constField(core::int #externalFieldValue) → void;
 external static get Extension|extensionInstanceField() → core::int;
-external static set Extension|extensionInstanceField(core::int #t10) → void;
+external static set Extension|extensionInstanceField(core::int #externalFieldValue) → void;
 external static get Extension|finalExtensionInstanceField() → core::int;
 external static get Extension|extensionStaticField() → core::int;
-external static set Extension|extensionStaticField(core::int #t11) → void;
+external static set Extension|extensionStaticField(core::int #externalFieldValue) → void;
 external static get Extension|finalExtensionStaticField() → core::int;
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/external_field_errors.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/external_field_errors.dart.weak.transformed.expect
index 895696f..5d4f518 100644
--- a/pkg/front_end/testcases/nnbd/external_field_errors.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/external_field_errors.dart.weak.transformed.expect
@@ -86,18 +86,18 @@
                                    ^^^^^^^^^^^^^^^^^"
     ;
   external get fieldWithInitializer() → core::int;
-  external set fieldWithInitializer(core::int #t3) → void;
+  external set fieldWithInitializer(core::int #externalFieldValue) → void;
   external get initializedField1() → core::int;
-  external set initializedField1(core::int #t4) → void;
+  external set initializedField1(core::int #externalFieldValue) → void;
   external get initializedField2() → core::int;
-  external set initializedField2(core::int #t5) → void;
+  external set initializedField2(core::int #externalFieldValue) → void;
   external static get staticField() → core::int;
-  external static set staticField(core::int #t6) → void;
+  external static set staticField(core::int #externalFieldValue) → void;
   external static get finalStaticField() → core::int;
 }
 abstract class B extends core::Object /*isMixinDeclaration*/  {
   external static get staticField() → core::int;
-  external static set staticField(core::int #t7) → void;
+  external static set staticField(core::int #externalFieldValue) → void;
   external static get finalStaticField() → core::int;
 }
 extension Extension on self::A {
@@ -109,14 +109,14 @@
   static get finalExtensionStaticField = get self::Extension|finalExtensionStaticField;
 }
 external static get topLevelField() → core::int;
-external static set topLevelField(core::int #t8) → void;
+external static set topLevelField(core::int #externalFieldValue) → void;
 external static get finalTopLevelField() → core::int;
 external static get constField() → core::int;
-external static set constField(core::int #t9) → void;
+external static set constField(core::int #externalFieldValue) → void;
 external static get Extension|extensionInstanceField() → core::int;
-external static set Extension|extensionInstanceField(core::int #t10) → void;
+external static set Extension|extensionInstanceField(core::int #externalFieldValue) → void;
 external static get Extension|finalExtensionInstanceField() → core::int;
 external static get Extension|extensionStaticField() → core::int;
-external static set Extension|extensionStaticField(core::int #t11) → void;
+external static set Extension|extensionStaticField(core::int #externalFieldValue) → void;
 external static get Extension|finalExtensionStaticField() → core::int;
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/external_fields.dart.outline.expect b/pkg/front_end/testcases/nnbd/external_fields.dart.outline.expect
index b475be4..3a6dda73 100644
--- a/pkg/front_end/testcases/nnbd/external_fields.dart.outline.expect
+++ b/pkg/front_end/testcases/nnbd/external_fields.dart.outline.expect
@@ -13,67 +13,67 @@
   @self::Annotation::•()
   external get instanceField() → core::int;
   @self::Annotation::•()
-  external set instanceField(core::int #t1) → void;
+  external set instanceField(core::int #externalFieldValue) → void;
   @self::Annotation::•()
   external get finalInstanceField() → core::int;
   @self::Annotation::•()
   external get covariantInstanceField() → core::num;
   @self::Annotation::•()
-  external set covariantInstanceField(covariant core::num #t2) → void;
+  external set covariantInstanceField(covariant core::num #externalFieldValue) → void;
   @self::Annotation::•()
   external static get staticField() → core::int;
   @self::Annotation::•()
-  external static set staticField(core::int #t3) → void;
+  external static set staticField(core::int #externalFieldValue) → void;
   @self::Annotation::•()
   external static get finalStaticField() → core::int;
   external get untypedInstanceField() → dynamic;
-  external set untypedInstanceField(dynamic #t4) → void;
+  external set untypedInstanceField(dynamic #externalFieldValue) → void;
   external get untypedFinalInstanceField() → dynamic;
   external get untypedCovariantInstanceField() → dynamic;
-  external set untypedCovariantInstanceField(covariant dynamic #t5) → void;
+  external set untypedCovariantInstanceField(covariant dynamic #externalFieldValue) → void;
   external static get untypedStaticField() → dynamic;
-  external static set untypedStaticField(dynamic #t6) → void;
+  external static set untypedStaticField(dynamic #externalFieldValue) → void;
   external static get untypedFinalStaticField() → dynamic;
 }
 abstract class B extends core::Object /*isMixinDeclaration*/  {
   @self::Annotation::•()
   external get instanceField() → core::int;
   @self::Annotation::•()
-  external set instanceField(core::int #t7) → void;
+  external set instanceField(core::int #externalFieldValue) → void;
   @self::Annotation::•()
   external get finalInstanceField() → core::int;
   @self::Annotation::•()
   external get covariantInstanceField() → core::num;
   @self::Annotation::•()
-  external set covariantInstanceField(covariant core::num #t8) → void;
+  external set covariantInstanceField(covariant core::num #externalFieldValue) → void;
   @self::Annotation::•()
   external static get staticField() → core::int;
   @self::Annotation::•()
-  external static set staticField(core::int #t9) → void;
+  external static set staticField(core::int #externalFieldValue) → void;
   @self::Annotation::•()
   external static get finalStaticField() → core::int;
   external get untypedInstanceField() → dynamic;
-  external set untypedInstanceField(dynamic #t10) → void;
+  external set untypedInstanceField(dynamic #externalFieldValue) → void;
   external get untypedFinalInstanceField() → dynamic;
   external get untypedCovariantInstanceField() → dynamic;
-  external set untypedCovariantInstanceField(covariant dynamic #t11) → void;
+  external set untypedCovariantInstanceField(covariant dynamic #externalFieldValue) → void;
   external static get untypedStaticField() → dynamic;
-  external static set untypedStaticField(dynamic #t12) → void;
+  external static set untypedStaticField(dynamic #externalFieldValue) → void;
   external static get untypedFinalStaticField() → dynamic;
 }
 class C extends core::Object implements self::A {
   synthetic constructor •() → self::C
     ;
   external get instanceField() → core::int;
-  external set instanceField(core::int #t13) → void;
+  external set instanceField(core::int #externalFieldValue) → void;
   external get finalInstanceField() → core::int;
   external get covariantInstanceField() → core::num;
-  external set covariantInstanceField(covariant core::num #t14) → void;
+  external set covariantInstanceField(covariant core::num #externalFieldValue) → void;
   external get untypedInstanceField() → dynamic;
-  external set untypedInstanceField(dynamic #t15) → void;
+  external set untypedInstanceField(dynamic #externalFieldValue) → void;
   external get untypedFinalInstanceField() → dynamic;
   external get untypedCovariantInstanceField() → dynamic;
-  external set untypedCovariantInstanceField(covariant dynamic #t16) → void;
+  external set untypedCovariantInstanceField(covariant dynamic #externalFieldValue) → void;
 }
 extension Extension on self::A {
   get extensionInstanceField = get self::Extension|extensionInstanceField;
@@ -92,29 +92,29 @@
 @self::Annotation::•()
 external static get topLevelField() → core::int;
 @self::Annotation::•()
-external static set topLevelField(core::int #t17) → void;
+external static set topLevelField(core::int #externalFieldValue) → void;
 @self::Annotation::•()
 external static get finalTopLevelField() → core::int;
 external static get untypedTopLevelField() → dynamic;
-external static set untypedTopLevelField(dynamic #t18) → void;
+external static set untypedTopLevelField(dynamic #externalFieldValue) → void;
 external static get untypedFinalTopLevelField() → dynamic;
 @self::Annotation::•()
 external static get Extension|extensionInstanceField() → core::int;
 @self::Annotation::•()
-external static set Extension|extensionInstanceField(core::int #t19) → void;
+external static set Extension|extensionInstanceField(core::int #externalFieldValue) → void;
 @self::Annotation::•()
 external static get Extension|finalExtensionInstanceField() → core::int;
 @self::Annotation::•()
 external static get Extension|extensionStaticField() → core::int;
 @self::Annotation::•()
-external static set Extension|extensionStaticField(core::int #t20) → void;
+external static set Extension|extensionStaticField(core::int #externalFieldValue) → void;
 @self::Annotation::•()
 external static get Extension|finalExtensionStaticField() → core::int;
 external static get Extension|untypedExtensionInstanceField() → dynamic;
-external static set Extension|untypedExtensionInstanceField(dynamic #t21) → void;
+external static set Extension|untypedExtensionInstanceField(dynamic #externalFieldValue) → void;
 external static get Extension|untypedFinalExtensionInstanceField() → dynamic;
 external static get Extension|untypedExtensionStaticField() → dynamic;
-external static set Extension|untypedExtensionStaticField(dynamic #t22) → void;
+external static set Extension|untypedExtensionStaticField(dynamic #externalFieldValue) → void;
 external static get Extension|untypedFinalExtensionStaticField() → dynamic;
 static method main() → dynamic
   ;
diff --git a/pkg/front_end/testcases/nnbd/external_fields.dart.strong.expect b/pkg/front_end/testcases/nnbd/external_fields.dart.strong.expect
index 8f52a91..cbc138b 100644
--- a/pkg/front_end/testcases/nnbd/external_fields.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/external_fields.dart.strong.expect
@@ -14,52 +14,52 @@
   @#C1
   external get instanceField() → core::int;
   @#C1
-  external set instanceField(core::int #t1) → void;
+  external set instanceField(core::int #externalFieldValue) → void;
   @#C1
   external get finalInstanceField() → core::int;
   @#C1
   external get covariantInstanceField() → core::num;
   @#C1
-  external set covariantInstanceField(covariant core::num #t2) → void;
+  external set covariantInstanceField(covariant core::num #externalFieldValue) → void;
   @#C1
   external static get staticField() → core::int;
   @#C1
-  external static set staticField(core::int #t3) → void;
+  external static set staticField(core::int #externalFieldValue) → void;
   @#C1
   external static get finalStaticField() → core::int;
   external get untypedInstanceField() → dynamic;
-  external set untypedInstanceField(dynamic #t4) → void;
+  external set untypedInstanceField(dynamic #externalFieldValue) → void;
   external get untypedFinalInstanceField() → dynamic;
   external get untypedCovariantInstanceField() → dynamic;
-  external set untypedCovariantInstanceField(covariant dynamic #t5) → void;
+  external set untypedCovariantInstanceField(covariant dynamic #externalFieldValue) → void;
   external static get untypedStaticField() → dynamic;
-  external static set untypedStaticField(dynamic #t6) → void;
+  external static set untypedStaticField(dynamic #externalFieldValue) → void;
   external static get untypedFinalStaticField() → dynamic;
 }
 abstract class B extends core::Object /*isMixinDeclaration*/  {
   @#C1
   external get instanceField() → core::int;
   @#C1
-  external set instanceField(core::int #t7) → void;
+  external set instanceField(core::int #externalFieldValue) → void;
   @#C1
   external get finalInstanceField() → core::int;
   @#C1
   external get covariantInstanceField() → core::num;
   @#C1
-  external set covariantInstanceField(covariant core::num #t8) → void;
+  external set covariantInstanceField(covariant core::num #externalFieldValue) → void;
   @#C1
   external static get staticField() → core::int;
   @#C1
-  external static set staticField(core::int #t9) → void;
+  external static set staticField(core::int #externalFieldValue) → void;
   @#C1
   external static get finalStaticField() → core::int;
   external get untypedInstanceField() → dynamic;
-  external set untypedInstanceField(dynamic #t10) → void;
+  external set untypedInstanceField(dynamic #externalFieldValue) → void;
   external get untypedFinalInstanceField() → dynamic;
   external get untypedCovariantInstanceField() → dynamic;
-  external set untypedCovariantInstanceField(covariant dynamic #t11) → void;
+  external set untypedCovariantInstanceField(covariant dynamic #externalFieldValue) → void;
   external static get untypedStaticField() → dynamic;
-  external static set untypedStaticField(dynamic #t12) → void;
+  external static set untypedStaticField(dynamic #externalFieldValue) → void;
   external static get untypedFinalStaticField() → dynamic;
 }
 class C extends core::Object implements self::A {
@@ -67,15 +67,15 @@
     : super core::Object::•()
     ;
   external get instanceField() → core::int;
-  external set instanceField(core::int #t13) → void;
+  external set instanceField(core::int #externalFieldValue) → void;
   external get finalInstanceField() → core::int;
   external get covariantInstanceField() → core::num;
-  external set covariantInstanceField(covariant core::num #t14) → void;
+  external set covariantInstanceField(covariant core::num #externalFieldValue) → void;
   external get untypedInstanceField() → dynamic;
-  external set untypedInstanceField(dynamic #t15) → void;
+  external set untypedInstanceField(dynamic #externalFieldValue) → void;
   external get untypedFinalInstanceField() → dynamic;
   external get untypedCovariantInstanceField() → dynamic;
-  external set untypedCovariantInstanceField(covariant dynamic #t16) → void;
+  external set untypedCovariantInstanceField(covariant dynamic #externalFieldValue) → void;
 }
 extension Extension on self::A {
   get extensionInstanceField = get self::Extension|extensionInstanceField;
@@ -94,29 +94,29 @@
 @#C1
 external static get topLevelField() → core::int;
 @#C1
-external static set topLevelField(core::int #t17) → void;
+external static set topLevelField(core::int #externalFieldValue) → void;
 @#C1
 external static get finalTopLevelField() → core::int;
 external static get untypedTopLevelField() → dynamic;
-external static set untypedTopLevelField(dynamic #t18) → void;
+external static set untypedTopLevelField(dynamic #externalFieldValue) → void;
 external static get untypedFinalTopLevelField() → dynamic;
 @#C1
 external static get Extension|extensionInstanceField() → core::int;
 @#C1
-external static set Extension|extensionInstanceField(core::int #t19) → void;
+external static set Extension|extensionInstanceField(core::int #externalFieldValue) → void;
 @#C1
 external static get Extension|finalExtensionInstanceField() → core::int;
 @#C1
 external static get Extension|extensionStaticField() → core::int;
 @#C1
-external static set Extension|extensionStaticField(core::int #t20) → void;
+external static set Extension|extensionStaticField(core::int #externalFieldValue) → void;
 @#C1
 external static get Extension|finalExtensionStaticField() → core::int;
 external static get Extension|untypedExtensionInstanceField() → dynamic;
-external static set Extension|untypedExtensionInstanceField(dynamic #t21) → void;
+external static set Extension|untypedExtensionInstanceField(dynamic #externalFieldValue) → void;
 external static get Extension|untypedFinalExtensionInstanceField() → dynamic;
 external static get Extension|untypedExtensionStaticField() → dynamic;
-external static set Extension|untypedExtensionStaticField(dynamic #t22) → void;
+external static set Extension|untypedExtensionStaticField(dynamic #externalFieldValue) → void;
 external static get Extension|untypedFinalExtensionStaticField() → dynamic;
 static method main() → dynamic {}
 
diff --git a/pkg/front_end/testcases/nnbd/external_fields.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/external_fields.dart.strong.transformed.expect
index 8f52a91..cbc138b 100644
--- a/pkg/front_end/testcases/nnbd/external_fields.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/external_fields.dart.strong.transformed.expect
@@ -14,52 +14,52 @@
   @#C1
   external get instanceField() → core::int;
   @#C1
-  external set instanceField(core::int #t1) → void;
+  external set instanceField(core::int #externalFieldValue) → void;
   @#C1
   external get finalInstanceField() → core::int;
   @#C1
   external get covariantInstanceField() → core::num;
   @#C1
-  external set covariantInstanceField(covariant core::num #t2) → void;
+  external set covariantInstanceField(covariant core::num #externalFieldValue) → void;
   @#C1
   external static get staticField() → core::int;
   @#C1
-  external static set staticField(core::int #t3) → void;
+  external static set staticField(core::int #externalFieldValue) → void;
   @#C1
   external static get finalStaticField() → core::int;
   external get untypedInstanceField() → dynamic;
-  external set untypedInstanceField(dynamic #t4) → void;
+  external set untypedInstanceField(dynamic #externalFieldValue) → void;
   external get untypedFinalInstanceField() → dynamic;
   external get untypedCovariantInstanceField() → dynamic;
-  external set untypedCovariantInstanceField(covariant dynamic #t5) → void;
+  external set untypedCovariantInstanceField(covariant dynamic #externalFieldValue) → void;
   external static get untypedStaticField() → dynamic;
-  external static set untypedStaticField(dynamic #t6) → void;
+  external static set untypedStaticField(dynamic #externalFieldValue) → void;
   external static get untypedFinalStaticField() → dynamic;
 }
 abstract class B extends core::Object /*isMixinDeclaration*/  {
   @#C1
   external get instanceField() → core::int;
   @#C1
-  external set instanceField(core::int #t7) → void;
+  external set instanceField(core::int #externalFieldValue) → void;
   @#C1
   external get finalInstanceField() → core::int;
   @#C1
   external get covariantInstanceField() → core::num;
   @#C1
-  external set covariantInstanceField(covariant core::num #t8) → void;
+  external set covariantInstanceField(covariant core::num #externalFieldValue) → void;
   @#C1
   external static get staticField() → core::int;
   @#C1
-  external static set staticField(core::int #t9) → void;
+  external static set staticField(core::int #externalFieldValue) → void;
   @#C1
   external static get finalStaticField() → core::int;
   external get untypedInstanceField() → dynamic;
-  external set untypedInstanceField(dynamic #t10) → void;
+  external set untypedInstanceField(dynamic #externalFieldValue) → void;
   external get untypedFinalInstanceField() → dynamic;
   external get untypedCovariantInstanceField() → dynamic;
-  external set untypedCovariantInstanceField(covariant dynamic #t11) → void;
+  external set untypedCovariantInstanceField(covariant dynamic #externalFieldValue) → void;
   external static get untypedStaticField() → dynamic;
-  external static set untypedStaticField(dynamic #t12) → void;
+  external static set untypedStaticField(dynamic #externalFieldValue) → void;
   external static get untypedFinalStaticField() → dynamic;
 }
 class C extends core::Object implements self::A {
@@ -67,15 +67,15 @@
     : super core::Object::•()
     ;
   external get instanceField() → core::int;
-  external set instanceField(core::int #t13) → void;
+  external set instanceField(core::int #externalFieldValue) → void;
   external get finalInstanceField() → core::int;
   external get covariantInstanceField() → core::num;
-  external set covariantInstanceField(covariant core::num #t14) → void;
+  external set covariantInstanceField(covariant core::num #externalFieldValue) → void;
   external get untypedInstanceField() → dynamic;
-  external set untypedInstanceField(dynamic #t15) → void;
+  external set untypedInstanceField(dynamic #externalFieldValue) → void;
   external get untypedFinalInstanceField() → dynamic;
   external get untypedCovariantInstanceField() → dynamic;
-  external set untypedCovariantInstanceField(covariant dynamic #t16) → void;
+  external set untypedCovariantInstanceField(covariant dynamic #externalFieldValue) → void;
 }
 extension Extension on self::A {
   get extensionInstanceField = get self::Extension|extensionInstanceField;
@@ -94,29 +94,29 @@
 @#C1
 external static get topLevelField() → core::int;
 @#C1
-external static set topLevelField(core::int #t17) → void;
+external static set topLevelField(core::int #externalFieldValue) → void;
 @#C1
 external static get finalTopLevelField() → core::int;
 external static get untypedTopLevelField() → dynamic;
-external static set untypedTopLevelField(dynamic #t18) → void;
+external static set untypedTopLevelField(dynamic #externalFieldValue) → void;
 external static get untypedFinalTopLevelField() → dynamic;
 @#C1
 external static get Extension|extensionInstanceField() → core::int;
 @#C1
-external static set Extension|extensionInstanceField(core::int #t19) → void;
+external static set Extension|extensionInstanceField(core::int #externalFieldValue) → void;
 @#C1
 external static get Extension|finalExtensionInstanceField() → core::int;
 @#C1
 external static get Extension|extensionStaticField() → core::int;
 @#C1
-external static set Extension|extensionStaticField(core::int #t20) → void;
+external static set Extension|extensionStaticField(core::int #externalFieldValue) → void;
 @#C1
 external static get Extension|finalExtensionStaticField() → core::int;
 external static get Extension|untypedExtensionInstanceField() → dynamic;
-external static set Extension|untypedExtensionInstanceField(dynamic #t21) → void;
+external static set Extension|untypedExtensionInstanceField(dynamic #externalFieldValue) → void;
 external static get Extension|untypedFinalExtensionInstanceField() → dynamic;
 external static get Extension|untypedExtensionStaticField() → dynamic;
-external static set Extension|untypedExtensionStaticField(dynamic #t22) → void;
+external static set Extension|untypedExtensionStaticField(dynamic #externalFieldValue) → void;
 external static get Extension|untypedFinalExtensionStaticField() → dynamic;
 static method main() → dynamic {}
 
diff --git a/pkg/front_end/testcases/nnbd/external_fields.dart.weak.expect b/pkg/front_end/testcases/nnbd/external_fields.dart.weak.expect
index 8f52a91..cbc138b 100644
--- a/pkg/front_end/testcases/nnbd/external_fields.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/external_fields.dart.weak.expect
@@ -14,52 +14,52 @@
   @#C1
   external get instanceField() → core::int;
   @#C1
-  external set instanceField(core::int #t1) → void;
+  external set instanceField(core::int #externalFieldValue) → void;
   @#C1
   external get finalInstanceField() → core::int;
   @#C1
   external get covariantInstanceField() → core::num;
   @#C1
-  external set covariantInstanceField(covariant core::num #t2) → void;
+  external set covariantInstanceField(covariant core::num #externalFieldValue) → void;
   @#C1
   external static get staticField() → core::int;
   @#C1
-  external static set staticField(core::int #t3) → void;
+  external static set staticField(core::int #externalFieldValue) → void;
   @#C1
   external static get finalStaticField() → core::int;
   external get untypedInstanceField() → dynamic;
-  external set untypedInstanceField(dynamic #t4) → void;
+  external set untypedInstanceField(dynamic #externalFieldValue) → void;
   external get untypedFinalInstanceField() → dynamic;
   external get untypedCovariantInstanceField() → dynamic;
-  external set untypedCovariantInstanceField(covariant dynamic #t5) → void;
+  external set untypedCovariantInstanceField(covariant dynamic #externalFieldValue) → void;
   external static get untypedStaticField() → dynamic;
-  external static set untypedStaticField(dynamic #t6) → void;
+  external static set untypedStaticField(dynamic #externalFieldValue) → void;
   external static get untypedFinalStaticField() → dynamic;
 }
 abstract class B extends core::Object /*isMixinDeclaration*/  {
   @#C1
   external get instanceField() → core::int;
   @#C1
-  external set instanceField(core::int #t7) → void;
+  external set instanceField(core::int #externalFieldValue) → void;
   @#C1
   external get finalInstanceField() → core::int;
   @#C1
   external get covariantInstanceField() → core::num;
   @#C1
-  external set covariantInstanceField(covariant core::num #t8) → void;
+  external set covariantInstanceField(covariant core::num #externalFieldValue) → void;
   @#C1
   external static get staticField() → core::int;
   @#C1
-  external static set staticField(core::int #t9) → void;
+  external static set staticField(core::int #externalFieldValue) → void;
   @#C1
   external static get finalStaticField() → core::int;
   external get untypedInstanceField() → dynamic;
-  external set untypedInstanceField(dynamic #t10) → void;
+  external set untypedInstanceField(dynamic #externalFieldValue) → void;
   external get untypedFinalInstanceField() → dynamic;
   external get untypedCovariantInstanceField() → dynamic;
-  external set untypedCovariantInstanceField(covariant dynamic #t11) → void;
+  external set untypedCovariantInstanceField(covariant dynamic #externalFieldValue) → void;
   external static get untypedStaticField() → dynamic;
-  external static set untypedStaticField(dynamic #t12) → void;
+  external static set untypedStaticField(dynamic #externalFieldValue) → void;
   external static get untypedFinalStaticField() → dynamic;
 }
 class C extends core::Object implements self::A {
@@ -67,15 +67,15 @@
     : super core::Object::•()
     ;
   external get instanceField() → core::int;
-  external set instanceField(core::int #t13) → void;
+  external set instanceField(core::int #externalFieldValue) → void;
   external get finalInstanceField() → core::int;
   external get covariantInstanceField() → core::num;
-  external set covariantInstanceField(covariant core::num #t14) → void;
+  external set covariantInstanceField(covariant core::num #externalFieldValue) → void;
   external get untypedInstanceField() → dynamic;
-  external set untypedInstanceField(dynamic #t15) → void;
+  external set untypedInstanceField(dynamic #externalFieldValue) → void;
   external get untypedFinalInstanceField() → dynamic;
   external get untypedCovariantInstanceField() → dynamic;
-  external set untypedCovariantInstanceField(covariant dynamic #t16) → void;
+  external set untypedCovariantInstanceField(covariant dynamic #externalFieldValue) → void;
 }
 extension Extension on self::A {
   get extensionInstanceField = get self::Extension|extensionInstanceField;
@@ -94,29 +94,29 @@
 @#C1
 external static get topLevelField() → core::int;
 @#C1
-external static set topLevelField(core::int #t17) → void;
+external static set topLevelField(core::int #externalFieldValue) → void;
 @#C1
 external static get finalTopLevelField() → core::int;
 external static get untypedTopLevelField() → dynamic;
-external static set untypedTopLevelField(dynamic #t18) → void;
+external static set untypedTopLevelField(dynamic #externalFieldValue) → void;
 external static get untypedFinalTopLevelField() → dynamic;
 @#C1
 external static get Extension|extensionInstanceField() → core::int;
 @#C1
-external static set Extension|extensionInstanceField(core::int #t19) → void;
+external static set Extension|extensionInstanceField(core::int #externalFieldValue) → void;
 @#C1
 external static get Extension|finalExtensionInstanceField() → core::int;
 @#C1
 external static get Extension|extensionStaticField() → core::int;
 @#C1
-external static set Extension|extensionStaticField(core::int #t20) → void;
+external static set Extension|extensionStaticField(core::int #externalFieldValue) → void;
 @#C1
 external static get Extension|finalExtensionStaticField() → core::int;
 external static get Extension|untypedExtensionInstanceField() → dynamic;
-external static set Extension|untypedExtensionInstanceField(dynamic #t21) → void;
+external static set Extension|untypedExtensionInstanceField(dynamic #externalFieldValue) → void;
 external static get Extension|untypedFinalExtensionInstanceField() → dynamic;
 external static get Extension|untypedExtensionStaticField() → dynamic;
-external static set Extension|untypedExtensionStaticField(dynamic #t22) → void;
+external static set Extension|untypedExtensionStaticField(dynamic #externalFieldValue) → void;
 external static get Extension|untypedFinalExtensionStaticField() → dynamic;
 static method main() → dynamic {}
 
diff --git a/pkg/front_end/testcases/nnbd/external_fields.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/external_fields.dart.weak.transformed.expect
index 8f52a91..cbc138b 100644
--- a/pkg/front_end/testcases/nnbd/external_fields.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/external_fields.dart.weak.transformed.expect
@@ -14,52 +14,52 @@
   @#C1
   external get instanceField() → core::int;
   @#C1
-  external set instanceField(core::int #t1) → void;
+  external set instanceField(core::int #externalFieldValue) → void;
   @#C1
   external get finalInstanceField() → core::int;
   @#C1
   external get covariantInstanceField() → core::num;
   @#C1
-  external set covariantInstanceField(covariant core::num #t2) → void;
+  external set covariantInstanceField(covariant core::num #externalFieldValue) → void;
   @#C1
   external static get staticField() → core::int;
   @#C1
-  external static set staticField(core::int #t3) → void;
+  external static set staticField(core::int #externalFieldValue) → void;
   @#C1
   external static get finalStaticField() → core::int;
   external get untypedInstanceField() → dynamic;
-  external set untypedInstanceField(dynamic #t4) → void;
+  external set untypedInstanceField(dynamic #externalFieldValue) → void;
   external get untypedFinalInstanceField() → dynamic;
   external get untypedCovariantInstanceField() → dynamic;
-  external set untypedCovariantInstanceField(covariant dynamic #t5) → void;
+  external set untypedCovariantInstanceField(covariant dynamic #externalFieldValue) → void;
   external static get untypedStaticField() → dynamic;
-  external static set untypedStaticField(dynamic #t6) → void;
+  external static set untypedStaticField(dynamic #externalFieldValue) → void;
   external static get untypedFinalStaticField() → dynamic;
 }
 abstract class B extends core::Object /*isMixinDeclaration*/  {
   @#C1
   external get instanceField() → core::int;
   @#C1
-  external set instanceField(core::int #t7) → void;
+  external set instanceField(core::int #externalFieldValue) → void;
   @#C1
   external get finalInstanceField() → core::int;
   @#C1
   external get covariantInstanceField() → core::num;
   @#C1
-  external set covariantInstanceField(covariant core::num #t8) → void;
+  external set covariantInstanceField(covariant core::num #externalFieldValue) → void;
   @#C1
   external static get staticField() → core::int;
   @#C1
-  external static set staticField(core::int #t9) → void;
+  external static set staticField(core::int #externalFieldValue) → void;
   @#C1
   external static get finalStaticField() → core::int;
   external get untypedInstanceField() → dynamic;
-  external set untypedInstanceField(dynamic #t10) → void;
+  external set untypedInstanceField(dynamic #externalFieldValue) → void;
   external get untypedFinalInstanceField() → dynamic;
   external get untypedCovariantInstanceField() → dynamic;
-  external set untypedCovariantInstanceField(covariant dynamic #t11) → void;
+  external set untypedCovariantInstanceField(covariant dynamic #externalFieldValue) → void;
   external static get untypedStaticField() → dynamic;
-  external static set untypedStaticField(dynamic #t12) → void;
+  external static set untypedStaticField(dynamic #externalFieldValue) → void;
   external static get untypedFinalStaticField() → dynamic;
 }
 class C extends core::Object implements self::A {
@@ -67,15 +67,15 @@
     : super core::Object::•()
     ;
   external get instanceField() → core::int;
-  external set instanceField(core::int #t13) → void;
+  external set instanceField(core::int #externalFieldValue) → void;
   external get finalInstanceField() → core::int;
   external get covariantInstanceField() → core::num;
-  external set covariantInstanceField(covariant core::num #t14) → void;
+  external set covariantInstanceField(covariant core::num #externalFieldValue) → void;
   external get untypedInstanceField() → dynamic;
-  external set untypedInstanceField(dynamic #t15) → void;
+  external set untypedInstanceField(dynamic #externalFieldValue) → void;
   external get untypedFinalInstanceField() → dynamic;
   external get untypedCovariantInstanceField() → dynamic;
-  external set untypedCovariantInstanceField(covariant dynamic #t16) → void;
+  external set untypedCovariantInstanceField(covariant dynamic #externalFieldValue) → void;
 }
 extension Extension on self::A {
   get extensionInstanceField = get self::Extension|extensionInstanceField;
@@ -94,29 +94,29 @@
 @#C1
 external static get topLevelField() → core::int;
 @#C1
-external static set topLevelField(core::int #t17) → void;
+external static set topLevelField(core::int #externalFieldValue) → void;
 @#C1
 external static get finalTopLevelField() → core::int;
 external static get untypedTopLevelField() → dynamic;
-external static set untypedTopLevelField(dynamic #t18) → void;
+external static set untypedTopLevelField(dynamic #externalFieldValue) → void;
 external static get untypedFinalTopLevelField() → dynamic;
 @#C1
 external static get Extension|extensionInstanceField() → core::int;
 @#C1
-external static set Extension|extensionInstanceField(core::int #t19) → void;
+external static set Extension|extensionInstanceField(core::int #externalFieldValue) → void;
 @#C1
 external static get Extension|finalExtensionInstanceField() → core::int;
 @#C1
 external static get Extension|extensionStaticField() → core::int;
 @#C1
-external static set Extension|extensionStaticField(core::int #t20) → void;
+external static set Extension|extensionStaticField(core::int #externalFieldValue) → void;
 @#C1
 external static get Extension|finalExtensionStaticField() → core::int;
 external static get Extension|untypedExtensionInstanceField() → dynamic;
-external static set Extension|untypedExtensionInstanceField(dynamic #t21) → void;
+external static set Extension|untypedExtensionInstanceField(dynamic #externalFieldValue) → void;
 external static get Extension|untypedFinalExtensionInstanceField() → dynamic;
 external static get Extension|untypedExtensionStaticField() → dynamic;
-external static set Extension|untypedExtensionStaticField(dynamic #t22) → void;
+external static set Extension|untypedExtensionStaticField(dynamic #externalFieldValue) → void;
 external static get Extension|untypedFinalExtensionStaticField() → dynamic;
 static method main() → dynamic {}
 
diff --git a/pkg/front_end/testcases/nnbd/external_fields_spec.dart.outline.expect b/pkg/front_end/testcases/nnbd/external_fields_spec.dart.outline.expect
index 832b31d..bdaf36f 100644
--- a/pkg/front_end/testcases/nnbd/external_fields_spec.dart.outline.expect
+++ b/pkg/front_end/testcases/nnbd/external_fields_spec.dart.outline.expect
@@ -6,15 +6,15 @@
   synthetic constructor •() → self::A
     ;
   external get i1() → core::int;
-  external set i1(core::int #t1) → void;
+  external set i1(core::int #externalFieldValue) → void;
   external get cx() → dynamic;
-  external set cx(covariant dynamic #t2) → void;
+  external set cx(covariant dynamic #externalFieldValue) → void;
   external static get s1() → core::int;
-  external static set s1(core::int #t3) → void;
+  external static set s1(core::int #externalFieldValue) → void;
   external static get fx() → dynamic;
 }
 external static get s1() → core::int;
-external static set s1(core::int #t4) → void;
+external static set s1(core::int #externalFieldValue) → void;
 external static get fx() → dynamic;
 static method main() → dynamic
   ;
diff --git a/pkg/front_end/testcases/nnbd/external_fields_spec.dart.strong.expect b/pkg/front_end/testcases/nnbd/external_fields_spec.dart.strong.expect
index 57dc59d..f39a6bb 100644
--- a/pkg/front_end/testcases/nnbd/external_fields_spec.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/external_fields_spec.dart.strong.expect
@@ -7,14 +7,14 @@
     : super core::Object::•()
     ;
   external get i1() → core::int;
-  external set i1(core::int #t1) → void;
+  external set i1(core::int #externalFieldValue) → void;
   external get cx() → dynamic;
-  external set cx(covariant dynamic #t2) → void;
+  external set cx(covariant dynamic #externalFieldValue) → void;
   external static get s1() → core::int;
-  external static set s1(core::int #t3) → void;
+  external static set s1(core::int #externalFieldValue) → void;
   external static get fx() → dynamic;
 }
 external static get s1() → core::int;
-external static set s1(core::int #t4) → void;
+external static set s1(core::int #externalFieldValue) → void;
 external static get fx() → dynamic;
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/external_fields_spec.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/external_fields_spec.dart.strong.transformed.expect
index 57dc59d..f39a6bb 100644
--- a/pkg/front_end/testcases/nnbd/external_fields_spec.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/external_fields_spec.dart.strong.transformed.expect
@@ -7,14 +7,14 @@
     : super core::Object::•()
     ;
   external get i1() → core::int;
-  external set i1(core::int #t1) → void;
+  external set i1(core::int #externalFieldValue) → void;
   external get cx() → dynamic;
-  external set cx(covariant dynamic #t2) → void;
+  external set cx(covariant dynamic #externalFieldValue) → void;
   external static get s1() → core::int;
-  external static set s1(core::int #t3) → void;
+  external static set s1(core::int #externalFieldValue) → void;
   external static get fx() → dynamic;
 }
 external static get s1() → core::int;
-external static set s1(core::int #t4) → void;
+external static set s1(core::int #externalFieldValue) → void;
 external static get fx() → dynamic;
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/external_fields_spec.dart.weak.expect b/pkg/front_end/testcases/nnbd/external_fields_spec.dart.weak.expect
index 57dc59d..f39a6bb 100644
--- a/pkg/front_end/testcases/nnbd/external_fields_spec.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/external_fields_spec.dart.weak.expect
@@ -7,14 +7,14 @@
     : super core::Object::•()
     ;
   external get i1() → core::int;
-  external set i1(core::int #t1) → void;
+  external set i1(core::int #externalFieldValue) → void;
   external get cx() → dynamic;
-  external set cx(covariant dynamic #t2) → void;
+  external set cx(covariant dynamic #externalFieldValue) → void;
   external static get s1() → core::int;
-  external static set s1(core::int #t3) → void;
+  external static set s1(core::int #externalFieldValue) → void;
   external static get fx() → dynamic;
 }
 external static get s1() → core::int;
-external static set s1(core::int #t4) → void;
+external static set s1(core::int #externalFieldValue) → void;
 external static get fx() → dynamic;
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/external_fields_spec.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/external_fields_spec.dart.weak.transformed.expect
index 57dc59d..f39a6bb 100644
--- a/pkg/front_end/testcases/nnbd/external_fields_spec.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/external_fields_spec.dart.weak.transformed.expect
@@ -7,14 +7,14 @@
     : super core::Object::•()
     ;
   external get i1() → core::int;
-  external set i1(core::int #t1) → void;
+  external set i1(core::int #externalFieldValue) → void;
   external get cx() → dynamic;
-  external set cx(covariant dynamic #t2) → void;
+  external set cx(covariant dynamic #externalFieldValue) → void;
   external static get s1() → core::int;
-  external static set s1(core::int #t3) → void;
+  external static set s1(core::int #externalFieldValue) → void;
   external static get fx() → dynamic;
 }
 external static get s1() → core::int;
-external static set s1(core::int #t4) → void;
+external static set s1(core::int #externalFieldValue) → void;
 external static get fx() → dynamic;
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue40951.dart b/pkg/front_end/testcases/nnbd/issue40951.dart
new file mode 100644
index 0000000..0f168e8
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue40951.dart
@@ -0,0 +1,45 @@
+// 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.
+
+class A {
+  num field1;
+  num field2;
+
+  A() {}
+  A.foo() {}
+  A.bar(this.field1) {}
+  A.baz(this.field1, this.field2) {}
+}
+
+abstract class B {
+  num field1;
+  num field2;
+
+  B() {}
+  B.foo() {}
+  B.bar(this.field1) {}
+  B.baz(this.field1, this.field2) {}
+}
+
+class C {
+  final num? field1;
+  final num? field2;
+
+  C() {}
+  C.foo() {}
+  C.bar(this.field1) {}
+  C.baz(this.field1, this.field2) {}
+}
+
+abstract class D {
+  final num? field1;
+  final num? field2;
+
+  D() {}
+  D.foo() {}
+  D.bar(this.field1) {}
+  D.baz(this.field1, this.field2) {}
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue40951.dart.outline.expect b/pkg/front_end/testcases/nnbd/issue40951.dart.outline.expect
new file mode 100644
index 0000000..e850cd8
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue40951.dart.outline.expect
@@ -0,0 +1,54 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  field core::num field1;
+  field core::num field2;
+  constructor •() → self::A
+    ;
+  constructor foo() → self::A
+    ;
+  constructor bar(core::num field1) → self::A
+    ;
+  constructor baz(core::num field1, core::num field2) → self::A
+    ;
+}
+abstract class B extends core::Object {
+  field core::num field1;
+  field core::num field2;
+  constructor •() → self::B
+    ;
+  constructor foo() → self::B
+    ;
+  constructor bar(core::num field1) → self::B
+    ;
+  constructor baz(core::num field1, core::num field2) → self::B
+    ;
+}
+class C extends core::Object {
+  final field core::num? field1;
+  final field core::num? field2;
+  constructor •() → self::C
+    ;
+  constructor foo() → self::C
+    ;
+  constructor bar(core::num? field1) → self::C
+    ;
+  constructor baz(core::num? field1, core::num? field2) → self::C
+    ;
+}
+abstract class D extends core::Object {
+  final field core::num? field1;
+  final field core::num? field2;
+  constructor •() → self::D
+    ;
+  constructor foo() → self::D
+    ;
+  constructor bar(core::num? field1) → self::D
+    ;
+  constructor baz(core::num? field1, core::num? field2) → self::D
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/nnbd/issue40951.dart.strong.expect b/pkg/front_end/testcases/nnbd/issue40951.dart.strong.expect
new file mode 100644
index 0000000..42868d7
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue40951.dart.strong.expect
@@ -0,0 +1,206 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:9:3: Error: This constructor should initialize field 'field1' because its type 'num' doesn't allow null.
+//   A() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:6:7: Context: 'field1' is defined here.
+//   num field1;
+//       ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:9:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+//   A() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:7:7: Context: 'field2' is defined here.
+//   num field2;
+//       ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:10:3: Error: This constructor should initialize field 'field1' because its type 'num' doesn't allow null.
+//   A.foo() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:6:7: Context: 'field1' is defined here.
+//   num field1;
+//       ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:10:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+//   A.foo() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:7:7: Context: 'field2' is defined here.
+//   num field2;
+//       ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:11:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+//   A.bar(this.field1) {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:7:7: Context: 'field2' is defined here.
+//   num field2;
+//       ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:19:3: Error: This constructor should initialize field 'field1' because its type 'num' doesn't allow null.
+//   B() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:16:7: Context: 'field1' is defined here.
+//   num field1;
+//       ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:19:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+//   B() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:17:7: Context: 'field2' is defined here.
+//   num field2;
+//       ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:20:3: Error: This constructor should initialize field 'field1' because its type 'num' doesn't allow null.
+//   B.foo() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:16:7: Context: 'field1' is defined here.
+//   num field1;
+//       ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:20:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+//   B.foo() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:17:7: Context: 'field2' is defined here.
+//   num field2;
+//       ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:21:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+//   B.bar(this.field1) {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:17:7: Context: 'field2' is defined here.
+//   num field2;
+//       ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:29:3: Error: Final field 'field1' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+//   C() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:26:14: Context: 'field1' is defined here.
+//   final num? field1;
+//              ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:29:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+//   C() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:27:14: Context: 'field2' is defined here.
+//   final num? field2;
+//              ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:30:3: Error: Final field 'field1' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+//   C.foo() {}
+//   ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:26:14: Context: 'field1' is defined here.
+//   final num? field1;
+//              ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:30:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+//   C.foo() {}
+//   ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:27:14: Context: 'field2' is defined here.
+//   final num? field2;
+//              ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:31:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+//   C.bar(this.field1) {}
+//   ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:27:14: Context: 'field2' is defined here.
+//   final num? field2;
+//              ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:39:3: Error: Final field 'field1' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+//   D() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:36:14: Context: 'field1' is defined here.
+//   final num? field1;
+//              ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:39:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+//   D() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:37:14: Context: 'field2' is defined here.
+//   final num? field2;
+//              ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:40:3: Error: Final field 'field1' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+//   D.foo() {}
+//   ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:36:14: Context: 'field1' is defined here.
+//   final num? field1;
+//              ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:40:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+//   D.foo() {}
+//   ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:37:14: Context: 'field2' is defined here.
+//   final num? field2;
+//              ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:41:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+//   D.bar(this.field1) {}
+//   ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:37:14: Context: 'field2' is defined here.
+//   final num? field2;
+//              ^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  field core::num field1;
+  field core::num field2;
+  constructor •() → self::A
+    : self::A::field2 = null, self::A::field1 = null, super core::Object::•() {}
+  constructor foo() → self::A
+    : self::A::field2 = null, self::A::field1 = null, super core::Object::•() {}
+  constructor bar(core::num field1) → self::A
+    : self::A::field2 = null, self::A::field1 = field1, super core::Object::•() {}
+  constructor baz(core::num field1, core::num field2) → self::A
+    : self::A::field1 = field1, self::A::field2 = field2, super core::Object::•() {}
+}
+abstract class B extends core::Object {
+  field core::num field1;
+  field core::num field2;
+  constructor •() → self::B
+    : self::B::field2 = null, self::B::field1 = null, super core::Object::•() {}
+  constructor foo() → self::B
+    : self::B::field2 = null, self::B::field1 = null, super core::Object::•() {}
+  constructor bar(core::num field1) → self::B
+    : self::B::field2 = null, self::B::field1 = field1, super core::Object::•() {}
+  constructor baz(core::num field1, core::num field2) → self::B
+    : self::B::field1 = field1, self::B::field2 = field2, super core::Object::•() {}
+}
+class C extends core::Object {
+  final field core::num? field1;
+  final field core::num? field2;
+  constructor •() → self::C
+    : self::C::field2 = null, self::C::field1 = null, super core::Object::•() {}
+  constructor foo() → self::C
+    : self::C::field2 = null, self::C::field1 = null, super core::Object::•() {}
+  constructor bar(core::num? field1) → self::C
+    : self::C::field2 = null, self::C::field1 = field1, super core::Object::•() {}
+  constructor baz(core::num? field1, core::num? field2) → self::C
+    : self::C::field1 = field1, self::C::field2 = field2, super core::Object::•() {}
+}
+abstract class D extends core::Object {
+  final field core::num? field1;
+  final field core::num? field2;
+  constructor •() → self::D
+    : self::D::field2 = null, self::D::field1 = null, super core::Object::•() {}
+  constructor foo() → self::D
+    : self::D::field2 = null, self::D::field1 = null, super core::Object::•() {}
+  constructor bar(core::num? field1) → self::D
+    : self::D::field2 = null, self::D::field1 = field1, super core::Object::•() {}
+  constructor baz(core::num? field1, core::num? field2) → self::D
+    : self::D::field1 = field1, self::D::field2 = field2, super core::Object::•() {}
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue40951.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/issue40951.dart.strong.transformed.expect
new file mode 100644
index 0000000..42868d7
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue40951.dart.strong.transformed.expect
@@ -0,0 +1,206 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:9:3: Error: This constructor should initialize field 'field1' because its type 'num' doesn't allow null.
+//   A() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:6:7: Context: 'field1' is defined here.
+//   num field1;
+//       ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:9:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+//   A() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:7:7: Context: 'field2' is defined here.
+//   num field2;
+//       ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:10:3: Error: This constructor should initialize field 'field1' because its type 'num' doesn't allow null.
+//   A.foo() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:6:7: Context: 'field1' is defined here.
+//   num field1;
+//       ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:10:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+//   A.foo() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:7:7: Context: 'field2' is defined here.
+//   num field2;
+//       ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:11:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+//   A.bar(this.field1) {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:7:7: Context: 'field2' is defined here.
+//   num field2;
+//       ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:19:3: Error: This constructor should initialize field 'field1' because its type 'num' doesn't allow null.
+//   B() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:16:7: Context: 'field1' is defined here.
+//   num field1;
+//       ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:19:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+//   B() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:17:7: Context: 'field2' is defined here.
+//   num field2;
+//       ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:20:3: Error: This constructor should initialize field 'field1' because its type 'num' doesn't allow null.
+//   B.foo() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:16:7: Context: 'field1' is defined here.
+//   num field1;
+//       ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:20:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+//   B.foo() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:17:7: Context: 'field2' is defined here.
+//   num field2;
+//       ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:21:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+//   B.bar(this.field1) {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:17:7: Context: 'field2' is defined here.
+//   num field2;
+//       ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:29:3: Error: Final field 'field1' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+//   C() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:26:14: Context: 'field1' is defined here.
+//   final num? field1;
+//              ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:29:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+//   C() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:27:14: Context: 'field2' is defined here.
+//   final num? field2;
+//              ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:30:3: Error: Final field 'field1' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+//   C.foo() {}
+//   ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:26:14: Context: 'field1' is defined here.
+//   final num? field1;
+//              ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:30:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+//   C.foo() {}
+//   ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:27:14: Context: 'field2' is defined here.
+//   final num? field2;
+//              ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:31:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+//   C.bar(this.field1) {}
+//   ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:27:14: Context: 'field2' is defined here.
+//   final num? field2;
+//              ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:39:3: Error: Final field 'field1' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+//   D() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:36:14: Context: 'field1' is defined here.
+//   final num? field1;
+//              ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:39:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+//   D() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:37:14: Context: 'field2' is defined here.
+//   final num? field2;
+//              ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:40:3: Error: Final field 'field1' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+//   D.foo() {}
+//   ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:36:14: Context: 'field1' is defined here.
+//   final num? field1;
+//              ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:40:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+//   D.foo() {}
+//   ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:37:14: Context: 'field2' is defined here.
+//   final num? field2;
+//              ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:41:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+//   D.bar(this.field1) {}
+//   ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:37:14: Context: 'field2' is defined here.
+//   final num? field2;
+//              ^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  field core::num field1;
+  field core::num field2;
+  constructor •() → self::A
+    : self::A::field2 = null, self::A::field1 = null, super core::Object::•() {}
+  constructor foo() → self::A
+    : self::A::field2 = null, self::A::field1 = null, super core::Object::•() {}
+  constructor bar(core::num field1) → self::A
+    : self::A::field2 = null, self::A::field1 = field1, super core::Object::•() {}
+  constructor baz(core::num field1, core::num field2) → self::A
+    : self::A::field1 = field1, self::A::field2 = field2, super core::Object::•() {}
+}
+abstract class B extends core::Object {
+  field core::num field1;
+  field core::num field2;
+  constructor •() → self::B
+    : self::B::field2 = null, self::B::field1 = null, super core::Object::•() {}
+  constructor foo() → self::B
+    : self::B::field2 = null, self::B::field1 = null, super core::Object::•() {}
+  constructor bar(core::num field1) → self::B
+    : self::B::field2 = null, self::B::field1 = field1, super core::Object::•() {}
+  constructor baz(core::num field1, core::num field2) → self::B
+    : self::B::field1 = field1, self::B::field2 = field2, super core::Object::•() {}
+}
+class C extends core::Object {
+  final field core::num? field1;
+  final field core::num? field2;
+  constructor •() → self::C
+    : self::C::field2 = null, self::C::field1 = null, super core::Object::•() {}
+  constructor foo() → self::C
+    : self::C::field2 = null, self::C::field1 = null, super core::Object::•() {}
+  constructor bar(core::num? field1) → self::C
+    : self::C::field2 = null, self::C::field1 = field1, super core::Object::•() {}
+  constructor baz(core::num? field1, core::num? field2) → self::C
+    : self::C::field1 = field1, self::C::field2 = field2, super core::Object::•() {}
+}
+abstract class D extends core::Object {
+  final field core::num? field1;
+  final field core::num? field2;
+  constructor •() → self::D
+    : self::D::field2 = null, self::D::field1 = null, super core::Object::•() {}
+  constructor foo() → self::D
+    : self::D::field2 = null, self::D::field1 = null, super core::Object::•() {}
+  constructor bar(core::num? field1) → self::D
+    : self::D::field2 = null, self::D::field1 = field1, super core::Object::•() {}
+  constructor baz(core::num? field1, core::num? field2) → self::D
+    : self::D::field1 = field1, self::D::field2 = field2, super core::Object::•() {}
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue40951.dart.textual_outline.expect b/pkg/front_end/testcases/nnbd/issue40951.dart.textual_outline.expect
new file mode 100644
index 0000000..611b634
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue40951.dart.textual_outline.expect
@@ -0,0 +1,37 @@
+class A {
+  num field1;
+  num field2;
+  A() {}
+  A.foo() {}
+  A.bar(this.field1) {}
+  A.baz(this.field1, this.field2) {}
+}
+
+abstract class B {
+  num field1;
+  num field2;
+  B() {}
+  B.foo() {}
+  B.bar(this.field1) {}
+  B.baz(this.field1, this.field2) {}
+}
+
+class C {
+  final num? field1;
+  final num? field2;
+  C() {}
+  C.foo() {}
+  C.bar(this.field1) {}
+  C.baz(this.field1, this.field2) {}
+}
+
+abstract class D {
+  final num? field1;
+  final num? field2;
+  D() {}
+  D.foo() {}
+  D.bar(this.field1) {}
+  D.baz(this.field1, this.field2) {}
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue40951.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd/issue40951.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..a12b8be
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue40951.dart.textual_outline_modelled.expect
@@ -0,0 +1,37 @@
+abstract class B {
+  B() {}
+  B.bar(this.field1) {}
+  B.baz(this.field1, this.field2) {}
+  B.foo() {}
+  num field1;
+  num field2;
+}
+
+abstract class D {
+  D() {}
+  D.bar(this.field1) {}
+  D.baz(this.field1, this.field2) {}
+  D.foo() {}
+  final num? field1;
+  final num? field2;
+}
+
+class A {
+  A() {}
+  A.bar(this.field1) {}
+  A.baz(this.field1, this.field2) {}
+  A.foo() {}
+  num field1;
+  num field2;
+}
+
+class C {
+  C() {}
+  C.bar(this.field1) {}
+  C.baz(this.field1, this.field2) {}
+  C.foo() {}
+  final num? field1;
+  final num? field2;
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue40951.dart.weak.expect b/pkg/front_end/testcases/nnbd/issue40951.dart.weak.expect
new file mode 100644
index 0000000..42868d7
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue40951.dart.weak.expect
@@ -0,0 +1,206 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:9:3: Error: This constructor should initialize field 'field1' because its type 'num' doesn't allow null.
+//   A() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:6:7: Context: 'field1' is defined here.
+//   num field1;
+//       ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:9:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+//   A() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:7:7: Context: 'field2' is defined here.
+//   num field2;
+//       ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:10:3: Error: This constructor should initialize field 'field1' because its type 'num' doesn't allow null.
+//   A.foo() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:6:7: Context: 'field1' is defined here.
+//   num field1;
+//       ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:10:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+//   A.foo() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:7:7: Context: 'field2' is defined here.
+//   num field2;
+//       ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:11:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+//   A.bar(this.field1) {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:7:7: Context: 'field2' is defined here.
+//   num field2;
+//       ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:19:3: Error: This constructor should initialize field 'field1' because its type 'num' doesn't allow null.
+//   B() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:16:7: Context: 'field1' is defined here.
+//   num field1;
+//       ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:19:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+//   B() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:17:7: Context: 'field2' is defined here.
+//   num field2;
+//       ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:20:3: Error: This constructor should initialize field 'field1' because its type 'num' doesn't allow null.
+//   B.foo() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:16:7: Context: 'field1' is defined here.
+//   num field1;
+//       ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:20:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+//   B.foo() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:17:7: Context: 'field2' is defined here.
+//   num field2;
+//       ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:21:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+//   B.bar(this.field1) {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:17:7: Context: 'field2' is defined here.
+//   num field2;
+//       ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:29:3: Error: Final field 'field1' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+//   C() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:26:14: Context: 'field1' is defined here.
+//   final num? field1;
+//              ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:29:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+//   C() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:27:14: Context: 'field2' is defined here.
+//   final num? field2;
+//              ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:30:3: Error: Final field 'field1' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+//   C.foo() {}
+//   ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:26:14: Context: 'field1' is defined here.
+//   final num? field1;
+//              ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:30:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+//   C.foo() {}
+//   ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:27:14: Context: 'field2' is defined here.
+//   final num? field2;
+//              ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:31:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+//   C.bar(this.field1) {}
+//   ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:27:14: Context: 'field2' is defined here.
+//   final num? field2;
+//              ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:39:3: Error: Final field 'field1' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+//   D() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:36:14: Context: 'field1' is defined here.
+//   final num? field1;
+//              ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:39:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+//   D() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:37:14: Context: 'field2' is defined here.
+//   final num? field2;
+//              ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:40:3: Error: Final field 'field1' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+//   D.foo() {}
+//   ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:36:14: Context: 'field1' is defined here.
+//   final num? field1;
+//              ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:40:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+//   D.foo() {}
+//   ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:37:14: Context: 'field2' is defined here.
+//   final num? field2;
+//              ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:41:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+//   D.bar(this.field1) {}
+//   ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:37:14: Context: 'field2' is defined here.
+//   final num? field2;
+//              ^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  field core::num field1;
+  field core::num field2;
+  constructor •() → self::A
+    : self::A::field2 = null, self::A::field1 = null, super core::Object::•() {}
+  constructor foo() → self::A
+    : self::A::field2 = null, self::A::field1 = null, super core::Object::•() {}
+  constructor bar(core::num field1) → self::A
+    : self::A::field2 = null, self::A::field1 = field1, super core::Object::•() {}
+  constructor baz(core::num field1, core::num field2) → self::A
+    : self::A::field1 = field1, self::A::field2 = field2, super core::Object::•() {}
+}
+abstract class B extends core::Object {
+  field core::num field1;
+  field core::num field2;
+  constructor •() → self::B
+    : self::B::field2 = null, self::B::field1 = null, super core::Object::•() {}
+  constructor foo() → self::B
+    : self::B::field2 = null, self::B::field1 = null, super core::Object::•() {}
+  constructor bar(core::num field1) → self::B
+    : self::B::field2 = null, self::B::field1 = field1, super core::Object::•() {}
+  constructor baz(core::num field1, core::num field2) → self::B
+    : self::B::field1 = field1, self::B::field2 = field2, super core::Object::•() {}
+}
+class C extends core::Object {
+  final field core::num? field1;
+  final field core::num? field2;
+  constructor •() → self::C
+    : self::C::field2 = null, self::C::field1 = null, super core::Object::•() {}
+  constructor foo() → self::C
+    : self::C::field2 = null, self::C::field1 = null, super core::Object::•() {}
+  constructor bar(core::num? field1) → self::C
+    : self::C::field2 = null, self::C::field1 = field1, super core::Object::•() {}
+  constructor baz(core::num? field1, core::num? field2) → self::C
+    : self::C::field1 = field1, self::C::field2 = field2, super core::Object::•() {}
+}
+abstract class D extends core::Object {
+  final field core::num? field1;
+  final field core::num? field2;
+  constructor •() → self::D
+    : self::D::field2 = null, self::D::field1 = null, super core::Object::•() {}
+  constructor foo() → self::D
+    : self::D::field2 = null, self::D::field1 = null, super core::Object::•() {}
+  constructor bar(core::num? field1) → self::D
+    : self::D::field2 = null, self::D::field1 = field1, super core::Object::•() {}
+  constructor baz(core::num? field1, core::num? field2) → self::D
+    : self::D::field1 = field1, self::D::field2 = field2, super core::Object::•() {}
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue40951.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/issue40951.dart.weak.transformed.expect
new file mode 100644
index 0000000..42868d7
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue40951.dart.weak.transformed.expect
@@ -0,0 +1,206 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:9:3: Error: This constructor should initialize field 'field1' because its type 'num' doesn't allow null.
+//   A() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:6:7: Context: 'field1' is defined here.
+//   num field1;
+//       ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:9:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+//   A() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:7:7: Context: 'field2' is defined here.
+//   num field2;
+//       ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:10:3: Error: This constructor should initialize field 'field1' because its type 'num' doesn't allow null.
+//   A.foo() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:6:7: Context: 'field1' is defined here.
+//   num field1;
+//       ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:10:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+//   A.foo() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:7:7: Context: 'field2' is defined here.
+//   num field2;
+//       ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:11:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+//   A.bar(this.field1) {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:7:7: Context: 'field2' is defined here.
+//   num field2;
+//       ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:19:3: Error: This constructor should initialize field 'field1' because its type 'num' doesn't allow null.
+//   B() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:16:7: Context: 'field1' is defined here.
+//   num field1;
+//       ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:19:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+//   B() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:17:7: Context: 'field2' is defined here.
+//   num field2;
+//       ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:20:3: Error: This constructor should initialize field 'field1' because its type 'num' doesn't allow null.
+//   B.foo() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:16:7: Context: 'field1' is defined here.
+//   num field1;
+//       ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:20:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+//   B.foo() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:17:7: Context: 'field2' is defined here.
+//   num field2;
+//       ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:21:3: Error: This constructor should initialize field 'field2' because its type 'num' doesn't allow null.
+//   B.bar(this.field1) {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:17:7: Context: 'field2' is defined here.
+//   num field2;
+//       ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:29:3: Error: Final field 'field1' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+//   C() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:26:14: Context: 'field1' is defined here.
+//   final num? field1;
+//              ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:29:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+//   C() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:27:14: Context: 'field2' is defined here.
+//   final num? field2;
+//              ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:30:3: Error: Final field 'field1' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+//   C.foo() {}
+//   ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:26:14: Context: 'field1' is defined here.
+//   final num? field1;
+//              ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:30:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+//   C.foo() {}
+//   ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:27:14: Context: 'field2' is defined here.
+//   final num? field2;
+//              ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:31:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+//   C.bar(this.field1) {}
+//   ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:27:14: Context: 'field2' is defined here.
+//   final num? field2;
+//              ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:39:3: Error: Final field 'field1' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+//   D() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:36:14: Context: 'field1' is defined here.
+//   final num? field1;
+//              ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:39:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+//   D() {}
+//   ^
+// pkg/front_end/testcases/nnbd/issue40951.dart:37:14: Context: 'field2' is defined here.
+//   final num? field2;
+//              ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:40:3: Error: Final field 'field1' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+//   D.foo() {}
+//   ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:36:14: Context: 'field1' is defined here.
+//   final num? field1;
+//              ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:40:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+//   D.foo() {}
+//   ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:37:14: Context: 'field2' is defined here.
+//   final num? field2;
+//              ^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue40951.dart:41:3: Error: Final field 'field2' is not initialized by this constructor.
+// Try to initialize the field using an initializing formal or a field initializer.
+//   D.bar(this.field1) {}
+//   ^^^
+// pkg/front_end/testcases/nnbd/issue40951.dart:37:14: Context: 'field2' is defined here.
+//   final num? field2;
+//              ^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  field core::num field1;
+  field core::num field2;
+  constructor •() → self::A
+    : self::A::field2 = null, self::A::field1 = null, super core::Object::•() {}
+  constructor foo() → self::A
+    : self::A::field2 = null, self::A::field1 = null, super core::Object::•() {}
+  constructor bar(core::num field1) → self::A
+    : self::A::field2 = null, self::A::field1 = field1, super core::Object::•() {}
+  constructor baz(core::num field1, core::num field2) → self::A
+    : self::A::field1 = field1, self::A::field2 = field2, super core::Object::•() {}
+}
+abstract class B extends core::Object {
+  field core::num field1;
+  field core::num field2;
+  constructor •() → self::B
+    : self::B::field2 = null, self::B::field1 = null, super core::Object::•() {}
+  constructor foo() → self::B
+    : self::B::field2 = null, self::B::field1 = null, super core::Object::•() {}
+  constructor bar(core::num field1) → self::B
+    : self::B::field2 = null, self::B::field1 = field1, super core::Object::•() {}
+  constructor baz(core::num field1, core::num field2) → self::B
+    : self::B::field1 = field1, self::B::field2 = field2, super core::Object::•() {}
+}
+class C extends core::Object {
+  final field core::num? field1;
+  final field core::num? field2;
+  constructor •() → self::C
+    : self::C::field2 = null, self::C::field1 = null, super core::Object::•() {}
+  constructor foo() → self::C
+    : self::C::field2 = null, self::C::field1 = null, super core::Object::•() {}
+  constructor bar(core::num? field1) → self::C
+    : self::C::field2 = null, self::C::field1 = field1, super core::Object::•() {}
+  constructor baz(core::num? field1, core::num? field2) → self::C
+    : self::C::field1 = field1, self::C::field2 = field2, super core::Object::•() {}
+}
+abstract class D extends core::Object {
+  final field core::num? field1;
+  final field core::num? field2;
+  constructor •() → self::D
+    : self::D::field2 = null, self::D::field1 = null, super core::Object::•() {}
+  constructor foo() → self::D
+    : self::D::field2 = null, self::D::field1 = null, super core::Object::•() {}
+  constructor bar(core::num? field1) → self::D
+    : self::D::field2 = null, self::D::field1 = field1, super core::Object::•() {}
+  constructor baz(core::num? field1, core::num? field2) → self::D
+    : self::D::field1 = field1, self::D::field2 = field2, super core::Object::•() {}
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue42844_1.dart b/pkg/front_end/testcases/nnbd/issue42844_1.dart
new file mode 100644
index 0000000..6f9e7d2
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42844_1.dart
@@ -0,0 +1,17 @@
+// 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.
+
+class C {
+  Never n; // Error.
+
+  factory C(Never n) = D;
+}
+
+class D implements C {
+  Never n;
+
+  D(this.n);
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue42844_1.dart.outline.expect b/pkg/front_end/testcases/nnbd/issue42844_1.dart.outline.expect
new file mode 100644
index 0000000..a52904f
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42844_1.dart.outline.expect
@@ -0,0 +1,17 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  field Never n;
+  static field dynamic _redirecting# = <dynamic>[self::C::•]/*isNullableByDefault*/;
+  static factory •(Never n) → self::C
+    let dynamic #redirecting_factory = self::D::• in invalid-expression;
+}
+class D extends core::Object implements self::C {
+  field Never n;
+  constructor •(Never n) → self::D
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/nnbd/issue42844_1.dart.strong.expect b/pkg/front_end/testcases/nnbd/issue42844_1.dart.strong.expect
new file mode 100644
index 0000000..9f1d04c
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42844_1.dart.strong.expect
@@ -0,0 +1,24 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/issue42844_1.dart:6:9: Error: Field 'n' should be initialized because its type 'Never' doesn't allow null.
+//   Never n; // Error.
+//         ^
+//
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  field Never n = null;
+  static field dynamic _redirecting# = <dynamic>[self::C::•]/*isNullableByDefault*/;
+  static factory •(Never n) → self::C
+    let dynamic #redirecting_factory = self::D::• in invalid-expression;
+}
+class D extends core::Object implements self::C {
+  field Never n;
+  constructor •(Never n) → self::D
+    : self::D::n = n, super core::Object::•()
+    ;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue42844_1.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/issue42844_1.dart.strong.transformed.expect
new file mode 100644
index 0000000..7a9d7ad
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42844_1.dart.strong.transformed.expect
@@ -0,0 +1,24 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/issue42844_1.dart:6:9: Error: Field 'n' should be initialized because its type 'Never' doesn't allow null.
+//   Never n; // Error.
+//         ^
+//
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  field Never n = null;
+  static field dynamic _redirecting# = <dynamic>[self::C::•]/*isNullableByDefault*/;
+  static factory •(Never n) → self::C
+    let<BottomType> #redirecting_factory = self::D::• in invalid-expression;
+}
+class D extends core::Object implements self::C {
+  field Never n;
+  constructor •(Never n) → self::D
+    : self::D::n = n, super core::Object::•()
+    ;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue42844_1.dart.textual_outline.expect b/pkg/front_end/testcases/nnbd/issue42844_1.dart.textual_outline.expect
new file mode 100644
index 0000000..5449b69
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42844_1.dart.textual_outline.expect
@@ -0,0 +1,11 @@
+class C {
+  Never n;
+  factory C(Never n) = D;
+}
+
+class D implements C {
+  Never n;
+  D(this.n);
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue42844_1.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd/issue42844_1.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..df335e7
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42844_1.dart.textual_outline_modelled.expect
@@ -0,0 +1,11 @@
+class C {
+  Never n;
+  factory C(Never n) = D;
+}
+
+class D implements C {
+  D(this.n);
+  Never n;
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue42844_1.dart.weak.expect b/pkg/front_end/testcases/nnbd/issue42844_1.dart.weak.expect
new file mode 100644
index 0000000..9f1d04c
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42844_1.dart.weak.expect
@@ -0,0 +1,24 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/issue42844_1.dart:6:9: Error: Field 'n' should be initialized because its type 'Never' doesn't allow null.
+//   Never n; // Error.
+//         ^
+//
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  field Never n = null;
+  static field dynamic _redirecting# = <dynamic>[self::C::•]/*isNullableByDefault*/;
+  static factory •(Never n) → self::C
+    let dynamic #redirecting_factory = self::D::• in invalid-expression;
+}
+class D extends core::Object implements self::C {
+  field Never n;
+  constructor •(Never n) → self::D
+    : self::D::n = n, super core::Object::•()
+    ;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue42844_1.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/issue42844_1.dart.weak.transformed.expect
new file mode 100644
index 0000000..7a9d7ad
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42844_1.dart.weak.transformed.expect
@@ -0,0 +1,24 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/issue42844_1.dart:6:9: Error: Field 'n' should be initialized because its type 'Never' doesn't allow null.
+//   Never n; // Error.
+//         ^
+//
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  field Never n = null;
+  static field dynamic _redirecting# = <dynamic>[self::C::•]/*isNullableByDefault*/;
+  static factory •(Never n) → self::C
+    let<BottomType> #redirecting_factory = self::D::• in invalid-expression;
+}
+class D extends core::Object implements self::C {
+  field Never n;
+  constructor •(Never n) → self::D
+    : self::D::n = n, super core::Object::•()
+    ;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue42844_2.dart b/pkg/front_end/testcases/nnbd/issue42844_2.dart
new file mode 100644
index 0000000..544e1aa
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42844_2.dart
@@ -0,0 +1,17 @@
+// 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.
+
+class C {
+  final dynamic n; // Error.
+
+  factory C(dynamic n) = D;
+}
+
+class D implements C {
+  final dynamic n;
+
+  D(this.n);
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue42844_2.dart.outline.expect b/pkg/front_end/testcases/nnbd/issue42844_2.dart.outline.expect
new file mode 100644
index 0000000..40df7c4
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42844_2.dart.outline.expect
@@ -0,0 +1,17 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  final field dynamic n;
+  static field dynamic _redirecting# = <dynamic>[self::C::•]/*isNullableByDefault*/;
+  static factory •(dynamic n) → self::C
+    let dynamic #redirecting_factory = self::D::• in invalid-expression;
+}
+class D extends core::Object implements self::C {
+  final field dynamic n;
+  constructor •(dynamic n) → self::D
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/nnbd/issue42844_2.dart.strong.expect b/pkg/front_end/testcases/nnbd/issue42844_2.dart.strong.expect
new file mode 100644
index 0000000..afaa082
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42844_2.dart.strong.expect
@@ -0,0 +1,25 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/issue42844_2.dart:6:17: Error: Final field 'n' is not initialized.
+// Try to initialize the field in the declaration or in every constructor.
+//   final dynamic n; // Error.
+//                 ^
+//
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  final field dynamic n = null;
+  static field dynamic _redirecting# = <dynamic>[self::C::•]/*isNullableByDefault*/;
+  static factory •(dynamic n) → self::C
+    let dynamic #redirecting_factory = self::D::• in invalid-expression;
+}
+class D extends core::Object implements self::C {
+  final field dynamic n;
+  constructor •(dynamic n) → self::D
+    : self::D::n = n, super core::Object::•()
+    ;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue42844_2.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/issue42844_2.dart.strong.transformed.expect
new file mode 100644
index 0000000..4e1efe4
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42844_2.dart.strong.transformed.expect
@@ -0,0 +1,25 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/issue42844_2.dart:6:17: Error: Final field 'n' is not initialized.
+// Try to initialize the field in the declaration or in every constructor.
+//   final dynamic n; // Error.
+//                 ^
+//
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  final field dynamic n = null;
+  static field dynamic _redirecting# = <dynamic>[self::C::•]/*isNullableByDefault*/;
+  static factory •(dynamic n) → self::C
+    let<BottomType> #redirecting_factory = self::D::• in invalid-expression;
+}
+class D extends core::Object implements self::C {
+  final field dynamic n;
+  constructor •(dynamic n) → self::D
+    : self::D::n = n, super core::Object::•()
+    ;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue42844_2.dart.textual_outline.expect b/pkg/front_end/testcases/nnbd/issue42844_2.dart.textual_outline.expect
new file mode 100644
index 0000000..dc93ebc
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42844_2.dart.textual_outline.expect
@@ -0,0 +1,11 @@
+class C {
+  final dynamic n;
+  factory C(dynamic n) = D;
+}
+
+class D implements C {
+  final dynamic n;
+  D(this.n);
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue42844_2.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd/issue42844_2.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..8402c4d
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42844_2.dart.textual_outline_modelled.expect
@@ -0,0 +1,11 @@
+class C {
+  factory C(dynamic n) = D;
+  final dynamic n;
+}
+
+class D implements C {
+  D(this.n);
+  final dynamic n;
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue42844_2.dart.weak.expect b/pkg/front_end/testcases/nnbd/issue42844_2.dart.weak.expect
new file mode 100644
index 0000000..afaa082
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42844_2.dart.weak.expect
@@ -0,0 +1,25 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/issue42844_2.dart:6:17: Error: Final field 'n' is not initialized.
+// Try to initialize the field in the declaration or in every constructor.
+//   final dynamic n; // Error.
+//                 ^
+//
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  final field dynamic n = null;
+  static field dynamic _redirecting# = <dynamic>[self::C::•]/*isNullableByDefault*/;
+  static factory •(dynamic n) → self::C
+    let dynamic #redirecting_factory = self::D::• in invalid-expression;
+}
+class D extends core::Object implements self::C {
+  final field dynamic n;
+  constructor •(dynamic n) → self::D
+    : self::D::n = n, super core::Object::•()
+    ;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue42844_2.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/issue42844_2.dart.weak.transformed.expect
new file mode 100644
index 0000000..4e1efe4
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42844_2.dart.weak.transformed.expect
@@ -0,0 +1,25 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/issue42844_2.dart:6:17: Error: Final field 'n' is not initialized.
+// Try to initialize the field in the declaration or in every constructor.
+//   final dynamic n; // Error.
+//                 ^
+//
+import self as self;
+import "dart:core" as core;
+
+class C extends core::Object {
+  final field dynamic n = null;
+  static field dynamic _redirecting# = <dynamic>[self::C::•]/*isNullableByDefault*/;
+  static factory •(dynamic n) → self::C
+    let<BottomType> #redirecting_factory = self::D::• in invalid-expression;
+}
+class D extends core::Object implements self::C {
+  final field dynamic n;
+  constructor •(dynamic n) → self::D
+    : self::D::n = n, super core::Object::•()
+    ;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue42967.dart b/pkg/front_end/testcases/nnbd/issue42967.dart
new file mode 100644
index 0000000..e2e39a7
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42967.dart
@@ -0,0 +1,56 @@
+// 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.
+
+// Class A has no constructors.
+class A {
+  num fieldNonNullableOfA; // Error.
+  late num fieldLateNonNullableOfA; // Ok.
+
+  final dynamic fieldFinalDynamicOfA; // Error.
+  late final dynamic fieldLateFinalDynamicOfA; // Ok.
+}
+
+// Class AbstractA has no constructors.
+abstract class AbstractA {
+  external num fieldExternalNonNullableOfAbstractA; // Ok.
+  abstract num fieldAbstractNonNullableOfAbstractA; // Ok.
+
+  external final dynamic fieldExternalFinalDynamicOfAbstractA; // Ok.
+  abstract final dynamic fieldAbstractFinalDynamicOfAbstractA; // Ok.
+}
+
+
+// Class B has only factory constructors.
+class B {
+  num fieldNonNullableOfB; // Error.
+  late num fieldLateNonNullableOfB; // Ok.
+
+  final dynamic fieldFinalDynamicOfB; // Error.
+  late final dynamic fieldLateFinalDynamicOfB; // Ok.
+
+  factory B() => throw 42;
+}
+
+// Class AbstractB has only factory constructors.
+abstract class AbstractB {
+  external num fieldExternalNonNullableOfAbstractB; // Ok.
+  abstract num fieldAbstractNonNullableOfAbstractB; // Ok.
+
+  external final dynamic fieldExternalFinalDynamicOfAbstractB; // Ok.
+  abstract final dynamic fieldAbstractFinalDynamicOfAbstractB; // Ok.
+}
+
+mixin M {
+  num fieldNonNullableOfM; // Error.
+  late num fieldLateNonNullableOfM; // Ok.
+  external num fieldExternalNonNullableOfM; // Ok.
+  abstract num fieldAbstractNonNullableOfM; // Ok.
+
+  final dynamic fieldFinalDynamicOfM; // Error.
+  late final dynamic fieldLateFinalDynamicOfM; // Ok.
+  external final dynamic fieldExternalFinalDynamicOfM; // Ok.
+  abstract final dynamic fieldAbstractFinalDynamicOfM; // Ok.
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue42967.dart.outline.expect b/pkg/front_end/testcases/nnbd/issue42967.dart.outline.expect
new file mode 100644
index 0000000..12ac249
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42967.dart.outline.expect
@@ -0,0 +1,54 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  field core::num fieldNonNullableOfA;
+  late field core::num fieldLateNonNullableOfA;
+  final field dynamic fieldFinalDynamicOfA;
+  late final [setter] field dynamic fieldLateFinalDynamicOfA;
+  synthetic constructor •() → self::A
+    ;
+}
+abstract class AbstractA extends core::Object {
+  synthetic constructor •() → self::AbstractA
+    ;
+  external get fieldExternalNonNullableOfAbstractA() → core::num;
+  external set fieldExternalNonNullableOfAbstractA(core::num #externalFieldValue) → void;
+  abstract get fieldAbstractNonNullableOfAbstractA() → core::num;
+  abstract set fieldAbstractNonNullableOfAbstractA(core::num #externalFieldValue) → void;
+  external get fieldExternalFinalDynamicOfAbstractA() → dynamic;
+  abstract get fieldAbstractFinalDynamicOfAbstractA() → dynamic;
+}
+class B extends core::Object {
+  field core::num fieldNonNullableOfB;
+  late field core::num fieldLateNonNullableOfB;
+  final field dynamic fieldFinalDynamicOfB;
+  late final [setter] field dynamic fieldLateFinalDynamicOfB;
+  static factory •() → self::B
+    ;
+}
+abstract class AbstractB extends core::Object {
+  synthetic constructor •() → self::AbstractB
+    ;
+  external get fieldExternalNonNullableOfAbstractB() → core::num;
+  external set fieldExternalNonNullableOfAbstractB(core::num #externalFieldValue) → void;
+  abstract get fieldAbstractNonNullableOfAbstractB() → core::num;
+  abstract set fieldAbstractNonNullableOfAbstractB(core::num #externalFieldValue) → void;
+  external get fieldExternalFinalDynamicOfAbstractB() → dynamic;
+  abstract get fieldAbstractFinalDynamicOfAbstractB() → dynamic;
+}
+abstract class M extends core::Object /*isMixinDeclaration*/  {
+  field core::num fieldNonNullableOfM;
+  late field core::num fieldLateNonNullableOfM;
+  final field dynamic fieldFinalDynamicOfM;
+  late final [setter] field dynamic fieldLateFinalDynamicOfM;
+  external get fieldExternalNonNullableOfM() → core::num;
+  external set fieldExternalNonNullableOfM(core::num #externalFieldValue) → void;
+  abstract get fieldAbstractNonNullableOfM() → core::num;
+  abstract set fieldAbstractNonNullableOfM(core::num #externalFieldValue) → void;
+  external get fieldExternalFinalDynamicOfM() → dynamic;
+  abstract get fieldAbstractFinalDynamicOfM() → dynamic;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/nnbd/issue42967.dart.strong.expect b/pkg/front_end/testcases/nnbd/issue42967.dart.strong.expect
new file mode 100644
index 0000000..3995dbf
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42967.dart.strong.expect
@@ -0,0 +1,86 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:7:7: Error: Field 'fieldNonNullableOfA' should be initialized because its type 'num' doesn't allow null.
+//   num fieldNonNullableOfA; // Error.
+//       ^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:10:17: Error: Final field 'fieldFinalDynamicOfA' is not initialized.
+// Try to initialize the field in the declaration or in every constructor.
+//   final dynamic fieldFinalDynamicOfA; // Error.
+//                 ^^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:26:7: Error: Field 'fieldNonNullableOfB' should be initialized because its type 'num' doesn't allow null.
+//   num fieldNonNullableOfB; // Error.
+//       ^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:29:17: Error: Final field 'fieldFinalDynamicOfB' is not initialized.
+// Try to initialize the field in the declaration or in every constructor.
+//   final dynamic fieldFinalDynamicOfB; // Error.
+//                 ^^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:45:7: Error: Field 'fieldNonNullableOfM' should be initialized because its type 'num' doesn't allow null.
+//   num fieldNonNullableOfM; // Error.
+//       ^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:50:17: Error: Final field 'fieldFinalDynamicOfM' is not initialized.
+// Try to initialize the field in the declaration or in every constructor.
+//   final dynamic fieldFinalDynamicOfM; // Error.
+//                 ^^^^^^^^^^^^^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  field core::num fieldNonNullableOfA = null;
+  late field core::num fieldLateNonNullableOfA;
+  final field dynamic fieldFinalDynamicOfA = null;
+  late final [setter] field dynamic fieldLateFinalDynamicOfA;
+  synthetic constructor •() → self::A
+    : super core::Object::•()
+    ;
+}
+abstract class AbstractA extends core::Object {
+  synthetic constructor •() → self::AbstractA
+    : super core::Object::•()
+    ;
+  external get fieldExternalNonNullableOfAbstractA() → core::num;
+  external set fieldExternalNonNullableOfAbstractA(core::num #externalFieldValue) → void;
+  abstract get fieldAbstractNonNullableOfAbstractA() → core::num;
+  abstract set fieldAbstractNonNullableOfAbstractA(core::num #externalFieldValue) → void;
+  external get fieldExternalFinalDynamicOfAbstractA() → dynamic;
+  abstract get fieldAbstractFinalDynamicOfAbstractA() → dynamic;
+}
+class B extends core::Object {
+  field core::num fieldNonNullableOfB = null;
+  late field core::num fieldLateNonNullableOfB;
+  final field dynamic fieldFinalDynamicOfB = null;
+  late final [setter] field dynamic fieldLateFinalDynamicOfB;
+  static factory •() → self::B
+    return throw 42;
+}
+abstract class AbstractB extends core::Object {
+  synthetic constructor •() → self::AbstractB
+    : super core::Object::•()
+    ;
+  external get fieldExternalNonNullableOfAbstractB() → core::num;
+  external set fieldExternalNonNullableOfAbstractB(core::num #externalFieldValue) → void;
+  abstract get fieldAbstractNonNullableOfAbstractB() → core::num;
+  abstract set fieldAbstractNonNullableOfAbstractB(core::num #externalFieldValue) → void;
+  external get fieldExternalFinalDynamicOfAbstractB() → dynamic;
+  abstract get fieldAbstractFinalDynamicOfAbstractB() → dynamic;
+}
+abstract class M extends core::Object /*isMixinDeclaration*/  {
+  field core::num fieldNonNullableOfM = null;
+  late field core::num fieldLateNonNullableOfM;
+  final field dynamic fieldFinalDynamicOfM = null;
+  late final [setter] field dynamic fieldLateFinalDynamicOfM;
+  external get fieldExternalNonNullableOfM() → core::num;
+  external set fieldExternalNonNullableOfM(core::num #externalFieldValue) → void;
+  abstract get fieldAbstractNonNullableOfM() → core::num;
+  abstract set fieldAbstractNonNullableOfM(core::num #externalFieldValue) → void;
+  external get fieldExternalFinalDynamicOfM() → dynamic;
+  abstract get fieldAbstractFinalDynamicOfM() → dynamic;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue42967.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/issue42967.dart.strong.transformed.expect
new file mode 100644
index 0000000..3995dbf
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42967.dart.strong.transformed.expect
@@ -0,0 +1,86 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:7:7: Error: Field 'fieldNonNullableOfA' should be initialized because its type 'num' doesn't allow null.
+//   num fieldNonNullableOfA; // Error.
+//       ^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:10:17: Error: Final field 'fieldFinalDynamicOfA' is not initialized.
+// Try to initialize the field in the declaration or in every constructor.
+//   final dynamic fieldFinalDynamicOfA; // Error.
+//                 ^^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:26:7: Error: Field 'fieldNonNullableOfB' should be initialized because its type 'num' doesn't allow null.
+//   num fieldNonNullableOfB; // Error.
+//       ^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:29:17: Error: Final field 'fieldFinalDynamicOfB' is not initialized.
+// Try to initialize the field in the declaration or in every constructor.
+//   final dynamic fieldFinalDynamicOfB; // Error.
+//                 ^^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:45:7: Error: Field 'fieldNonNullableOfM' should be initialized because its type 'num' doesn't allow null.
+//   num fieldNonNullableOfM; // Error.
+//       ^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:50:17: Error: Final field 'fieldFinalDynamicOfM' is not initialized.
+// Try to initialize the field in the declaration or in every constructor.
+//   final dynamic fieldFinalDynamicOfM; // Error.
+//                 ^^^^^^^^^^^^^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  field core::num fieldNonNullableOfA = null;
+  late field core::num fieldLateNonNullableOfA;
+  final field dynamic fieldFinalDynamicOfA = null;
+  late final [setter] field dynamic fieldLateFinalDynamicOfA;
+  synthetic constructor •() → self::A
+    : super core::Object::•()
+    ;
+}
+abstract class AbstractA extends core::Object {
+  synthetic constructor •() → self::AbstractA
+    : super core::Object::•()
+    ;
+  external get fieldExternalNonNullableOfAbstractA() → core::num;
+  external set fieldExternalNonNullableOfAbstractA(core::num #externalFieldValue) → void;
+  abstract get fieldAbstractNonNullableOfAbstractA() → core::num;
+  abstract set fieldAbstractNonNullableOfAbstractA(core::num #externalFieldValue) → void;
+  external get fieldExternalFinalDynamicOfAbstractA() → dynamic;
+  abstract get fieldAbstractFinalDynamicOfAbstractA() → dynamic;
+}
+class B extends core::Object {
+  field core::num fieldNonNullableOfB = null;
+  late field core::num fieldLateNonNullableOfB;
+  final field dynamic fieldFinalDynamicOfB = null;
+  late final [setter] field dynamic fieldLateFinalDynamicOfB;
+  static factory •() → self::B
+    return throw 42;
+}
+abstract class AbstractB extends core::Object {
+  synthetic constructor •() → self::AbstractB
+    : super core::Object::•()
+    ;
+  external get fieldExternalNonNullableOfAbstractB() → core::num;
+  external set fieldExternalNonNullableOfAbstractB(core::num #externalFieldValue) → void;
+  abstract get fieldAbstractNonNullableOfAbstractB() → core::num;
+  abstract set fieldAbstractNonNullableOfAbstractB(core::num #externalFieldValue) → void;
+  external get fieldExternalFinalDynamicOfAbstractB() → dynamic;
+  abstract get fieldAbstractFinalDynamicOfAbstractB() → dynamic;
+}
+abstract class M extends core::Object /*isMixinDeclaration*/  {
+  field core::num fieldNonNullableOfM = null;
+  late field core::num fieldLateNonNullableOfM;
+  final field dynamic fieldFinalDynamicOfM = null;
+  late final [setter] field dynamic fieldLateFinalDynamicOfM;
+  external get fieldExternalNonNullableOfM() → core::num;
+  external set fieldExternalNonNullableOfM(core::num #externalFieldValue) → void;
+  abstract get fieldAbstractNonNullableOfM() → core::num;
+  abstract set fieldAbstractNonNullableOfM(core::num #externalFieldValue) → void;
+  external get fieldExternalFinalDynamicOfM() → dynamic;
+  abstract get fieldAbstractFinalDynamicOfM() → dynamic;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue42967.dart.textual_outline.expect b/pkg/front_end/testcases/nnbd/issue42967.dart.textual_outline.expect
new file mode 100644
index 0000000..003e9d3
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42967.dart.textual_outline.expect
@@ -0,0 +1,42 @@
+class A {
+  num fieldNonNullableOfA;
+  late num ;
+  fieldLateNonNullableOfA;
+  final dynamic fieldFinalDynamicOfA;
+  late ;
+  final dynamic fieldLateFinalDynamicOfA;
+}
+abstract class AbstractA {
+  external num fieldExternalNonNullableOfAbstractA;
+  abstract num fieldAbstractNonNullableOfAbstractA;
+  external final dynamic fieldExternalFinalDynamicOfAbstractA;
+  abstract final dynamic fieldAbstractFinalDynamicOfAbstractA;
+}
+class B {
+  num fieldNonNullableOfB;
+  late num ;
+  fieldLateNonNullableOfB;
+  final dynamic fieldFinalDynamicOfB;
+  late ;
+  final dynamic fieldLateFinalDynamicOfB;
+  factory B() => throw 42;
+}
+abstract class AbstractB {
+  external num fieldExternalNonNullableOfAbstractB;
+  abstract num fieldAbstractNonNullableOfAbstractB;
+  external final dynamic fieldExternalFinalDynamicOfAbstractB;
+  abstract final dynamic fieldAbstractFinalDynamicOfAbstractB;
+}
+mixin M {
+  num fieldNonNullableOfM;
+  late num ;
+  fieldLateNonNullableOfM;
+  external num fieldExternalNonNullableOfM;
+  abstract num fieldAbstractNonNullableOfM;
+  final dynamic fieldFinalDynamicOfM;
+  late ;
+  final dynamic fieldLateFinalDynamicOfM;
+  external final dynamic fieldExternalFinalDynamicOfM;
+  abstract final dynamic fieldAbstractFinalDynamicOfM;
+}
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue42967.dart.weak.expect b/pkg/front_end/testcases/nnbd/issue42967.dart.weak.expect
new file mode 100644
index 0000000..3995dbf
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42967.dart.weak.expect
@@ -0,0 +1,86 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:7:7: Error: Field 'fieldNonNullableOfA' should be initialized because its type 'num' doesn't allow null.
+//   num fieldNonNullableOfA; // Error.
+//       ^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:10:17: Error: Final field 'fieldFinalDynamicOfA' is not initialized.
+// Try to initialize the field in the declaration or in every constructor.
+//   final dynamic fieldFinalDynamicOfA; // Error.
+//                 ^^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:26:7: Error: Field 'fieldNonNullableOfB' should be initialized because its type 'num' doesn't allow null.
+//   num fieldNonNullableOfB; // Error.
+//       ^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:29:17: Error: Final field 'fieldFinalDynamicOfB' is not initialized.
+// Try to initialize the field in the declaration or in every constructor.
+//   final dynamic fieldFinalDynamicOfB; // Error.
+//                 ^^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:45:7: Error: Field 'fieldNonNullableOfM' should be initialized because its type 'num' doesn't allow null.
+//   num fieldNonNullableOfM; // Error.
+//       ^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:50:17: Error: Final field 'fieldFinalDynamicOfM' is not initialized.
+// Try to initialize the field in the declaration or in every constructor.
+//   final dynamic fieldFinalDynamicOfM; // Error.
+//                 ^^^^^^^^^^^^^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  field core::num fieldNonNullableOfA = null;
+  late field core::num fieldLateNonNullableOfA;
+  final field dynamic fieldFinalDynamicOfA = null;
+  late final [setter] field dynamic fieldLateFinalDynamicOfA;
+  synthetic constructor •() → self::A
+    : super core::Object::•()
+    ;
+}
+abstract class AbstractA extends core::Object {
+  synthetic constructor •() → self::AbstractA
+    : super core::Object::•()
+    ;
+  external get fieldExternalNonNullableOfAbstractA() → core::num;
+  external set fieldExternalNonNullableOfAbstractA(core::num #externalFieldValue) → void;
+  abstract get fieldAbstractNonNullableOfAbstractA() → core::num;
+  abstract set fieldAbstractNonNullableOfAbstractA(core::num #externalFieldValue) → void;
+  external get fieldExternalFinalDynamicOfAbstractA() → dynamic;
+  abstract get fieldAbstractFinalDynamicOfAbstractA() → dynamic;
+}
+class B extends core::Object {
+  field core::num fieldNonNullableOfB = null;
+  late field core::num fieldLateNonNullableOfB;
+  final field dynamic fieldFinalDynamicOfB = null;
+  late final [setter] field dynamic fieldLateFinalDynamicOfB;
+  static factory •() → self::B
+    return throw 42;
+}
+abstract class AbstractB extends core::Object {
+  synthetic constructor •() → self::AbstractB
+    : super core::Object::•()
+    ;
+  external get fieldExternalNonNullableOfAbstractB() → core::num;
+  external set fieldExternalNonNullableOfAbstractB(core::num #externalFieldValue) → void;
+  abstract get fieldAbstractNonNullableOfAbstractB() → core::num;
+  abstract set fieldAbstractNonNullableOfAbstractB(core::num #externalFieldValue) → void;
+  external get fieldExternalFinalDynamicOfAbstractB() → dynamic;
+  abstract get fieldAbstractFinalDynamicOfAbstractB() → dynamic;
+}
+abstract class M extends core::Object /*isMixinDeclaration*/  {
+  field core::num fieldNonNullableOfM = null;
+  late field core::num fieldLateNonNullableOfM;
+  final field dynamic fieldFinalDynamicOfM = null;
+  late final [setter] field dynamic fieldLateFinalDynamicOfM;
+  external get fieldExternalNonNullableOfM() → core::num;
+  external set fieldExternalNonNullableOfM(core::num #externalFieldValue) → void;
+  abstract get fieldAbstractNonNullableOfM() → core::num;
+  abstract set fieldAbstractNonNullableOfM(core::num #externalFieldValue) → void;
+  external get fieldExternalFinalDynamicOfM() → dynamic;
+  abstract get fieldAbstractFinalDynamicOfM() → dynamic;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue42967.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/issue42967.dart.weak.transformed.expect
new file mode 100644
index 0000000..3995dbf
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue42967.dart.weak.transformed.expect
@@ -0,0 +1,86 @@
+library /*isNonNullableByDefault*/;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:7:7: Error: Field 'fieldNonNullableOfA' should be initialized because its type 'num' doesn't allow null.
+//   num fieldNonNullableOfA; // Error.
+//       ^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:10:17: Error: Final field 'fieldFinalDynamicOfA' is not initialized.
+// Try to initialize the field in the declaration or in every constructor.
+//   final dynamic fieldFinalDynamicOfA; // Error.
+//                 ^^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:26:7: Error: Field 'fieldNonNullableOfB' should be initialized because its type 'num' doesn't allow null.
+//   num fieldNonNullableOfB; // Error.
+//       ^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:29:17: Error: Final field 'fieldFinalDynamicOfB' is not initialized.
+// Try to initialize the field in the declaration or in every constructor.
+//   final dynamic fieldFinalDynamicOfB; // Error.
+//                 ^^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:45:7: Error: Field 'fieldNonNullableOfM' should be initialized because its type 'num' doesn't allow null.
+//   num fieldNonNullableOfM; // Error.
+//       ^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/nnbd/issue42967.dart:50:17: Error: Final field 'fieldFinalDynamicOfM' is not initialized.
+// Try to initialize the field in the declaration or in every constructor.
+//   final dynamic fieldFinalDynamicOfM; // Error.
+//                 ^^^^^^^^^^^^^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  field core::num fieldNonNullableOfA = null;
+  late field core::num fieldLateNonNullableOfA;
+  final field dynamic fieldFinalDynamicOfA = null;
+  late final [setter] field dynamic fieldLateFinalDynamicOfA;
+  synthetic constructor •() → self::A
+    : super core::Object::•()
+    ;
+}
+abstract class AbstractA extends core::Object {
+  synthetic constructor •() → self::AbstractA
+    : super core::Object::•()
+    ;
+  external get fieldExternalNonNullableOfAbstractA() → core::num;
+  external set fieldExternalNonNullableOfAbstractA(core::num #externalFieldValue) → void;
+  abstract get fieldAbstractNonNullableOfAbstractA() → core::num;
+  abstract set fieldAbstractNonNullableOfAbstractA(core::num #externalFieldValue) → void;
+  external get fieldExternalFinalDynamicOfAbstractA() → dynamic;
+  abstract get fieldAbstractFinalDynamicOfAbstractA() → dynamic;
+}
+class B extends core::Object {
+  field core::num fieldNonNullableOfB = null;
+  late field core::num fieldLateNonNullableOfB;
+  final field dynamic fieldFinalDynamicOfB = null;
+  late final [setter] field dynamic fieldLateFinalDynamicOfB;
+  static factory •() → self::B
+    return throw 42;
+}
+abstract class AbstractB extends core::Object {
+  synthetic constructor •() → self::AbstractB
+    : super core::Object::•()
+    ;
+  external get fieldExternalNonNullableOfAbstractB() → core::num;
+  external set fieldExternalNonNullableOfAbstractB(core::num #externalFieldValue) → void;
+  abstract get fieldAbstractNonNullableOfAbstractB() → core::num;
+  abstract set fieldAbstractNonNullableOfAbstractB(core::num #externalFieldValue) → void;
+  external get fieldExternalFinalDynamicOfAbstractB() → dynamic;
+  abstract get fieldAbstractFinalDynamicOfAbstractB() → dynamic;
+}
+abstract class M extends core::Object /*isMixinDeclaration*/  {
+  field core::num fieldNonNullableOfM = null;
+  late field core::num fieldLateNonNullableOfM;
+  final field dynamic fieldFinalDynamicOfM = null;
+  late final [setter] field dynamic fieldLateFinalDynamicOfM;
+  external get fieldExternalNonNullableOfM() → core::num;
+  external set fieldExternalNonNullableOfM(core::num #externalFieldValue) → void;
+  abstract get fieldAbstractNonNullableOfM() → core::num;
+  abstract set fieldAbstractNonNullableOfM(core::num #externalFieldValue) → void;
+  external get fieldExternalFinalDynamicOfM() → dynamic;
+  abstract get fieldAbstractFinalDynamicOfM() → dynamic;
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.strong.expect b/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.strong.expect
index bd5dcc7..a318c48 100644
--- a/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.strong.expect
@@ -14,15 +14,24 @@
 //   static int staticFieldOfM; // Error.
 //              ^^^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:11:7: Error: This constructor should initialize field 'fieldOfA' because its type 'int' doesn't allow null.
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:12:3: Error: This constructor should initialize field 'fieldOfA' because its type 'int' doesn't allow null.
+//   A.foo();
+//   ^
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:11:7: Context: 'fieldOfA' is defined here.
 //   int fieldOfA; // Error.
 //       ^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:17:5: Error: This constructor should initialize field 'fieldOfB' because its type 'X' doesn't allow null.
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:19:3: Error: This constructor should initialize field 'fieldOfB' because its type 'X' doesn't allow null.
+//   B.foo();
+//   ^
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:17:5: Context: 'fieldOfB' is defined here.
 //   X fieldOfB; // Error.
 //     ^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:18:5: Error: This constructor should initialize field 'fieldOfB2' because its type 'Y' doesn't allow null.
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:19:3: Error: This constructor should initialize field 'fieldOfB2' because its type 'Y' doesn't allow null.
+//   B.foo();
+//   ^
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:18:5: Context: 'fieldOfB2' is defined here.
 //   Y fieldOfB2; // Error.
 //     ^^^^^^^^^
 //
diff --git a/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.strong.transformed.expect
index bd5dcc7..a318c48 100644
--- a/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.strong.transformed.expect
@@ -14,15 +14,24 @@
 //   static int staticFieldOfM; // Error.
 //              ^^^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:11:7: Error: This constructor should initialize field 'fieldOfA' because its type 'int' doesn't allow null.
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:12:3: Error: This constructor should initialize field 'fieldOfA' because its type 'int' doesn't allow null.
+//   A.foo();
+//   ^
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:11:7: Context: 'fieldOfA' is defined here.
 //   int fieldOfA; // Error.
 //       ^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:17:5: Error: This constructor should initialize field 'fieldOfB' because its type 'X' doesn't allow null.
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:19:3: Error: This constructor should initialize field 'fieldOfB' because its type 'X' doesn't allow null.
+//   B.foo();
+//   ^
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:17:5: Context: 'fieldOfB' is defined here.
 //   X fieldOfB; // Error.
 //     ^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:18:5: Error: This constructor should initialize field 'fieldOfB2' because its type 'Y' doesn't allow null.
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:19:3: Error: This constructor should initialize field 'fieldOfB2' because its type 'Y' doesn't allow null.
+//   B.foo();
+//   ^
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:18:5: Context: 'fieldOfB2' is defined here.
 //   Y fieldOfB2; // Error.
 //     ^^^^^^^^^
 //
diff --git a/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.weak.expect b/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.weak.expect
index bd5dcc7..a318c48 100644
--- a/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.weak.expect
@@ -14,15 +14,24 @@
 //   static int staticFieldOfM; // Error.
 //              ^^^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:11:7: Error: This constructor should initialize field 'fieldOfA' because its type 'int' doesn't allow null.
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:12:3: Error: This constructor should initialize field 'fieldOfA' because its type 'int' doesn't allow null.
+//   A.foo();
+//   ^
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:11:7: Context: 'fieldOfA' is defined here.
 //   int fieldOfA; // Error.
 //       ^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:17:5: Error: This constructor should initialize field 'fieldOfB' because its type 'X' doesn't allow null.
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:19:3: Error: This constructor should initialize field 'fieldOfB' because its type 'X' doesn't allow null.
+//   B.foo();
+//   ^
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:17:5: Context: 'fieldOfB' is defined here.
 //   X fieldOfB; // Error.
 //     ^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:18:5: Error: This constructor should initialize field 'fieldOfB2' because its type 'Y' doesn't allow null.
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:19:3: Error: This constructor should initialize field 'fieldOfB2' because its type 'Y' doesn't allow null.
+//   B.foo();
+//   ^
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:18:5: Context: 'fieldOfB2' is defined here.
 //   Y fieldOfB2; // Error.
 //     ^^^^^^^^^
 //
diff --git a/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.weak.transformed.expect
index bd5dcc7..a318c48 100644
--- a/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart.weak.transformed.expect
@@ -14,15 +14,24 @@
 //   static int staticFieldOfM; // Error.
 //              ^^^^^^^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:11:7: Error: This constructor should initialize field 'fieldOfA' because its type 'int' doesn't allow null.
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:12:3: Error: This constructor should initialize field 'fieldOfA' because its type 'int' doesn't allow null.
+//   A.foo();
+//   ^
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:11:7: Context: 'fieldOfA' is defined here.
 //   int fieldOfA; // Error.
 //       ^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:17:5: Error: This constructor should initialize field 'fieldOfB' because its type 'X' doesn't allow null.
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:19:3: Error: This constructor should initialize field 'fieldOfB' because its type 'X' doesn't allow null.
+//   B.foo();
+//   ^
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:17:5: Context: 'fieldOfB' is defined here.
 //   X fieldOfB; // Error.
 //     ^^^^^^^^
 //
-// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:18:5: Error: This constructor should initialize field 'fieldOfB2' because its type 'Y' doesn't allow null.
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:19:3: Error: This constructor should initialize field 'fieldOfB2' because its type 'Y' doesn't allow null.
+//   B.foo();
+//   ^
+// pkg/front_end/testcases/nnbd/non_nullable_field_initialization.dart:18:5: Context: 'fieldOfB2' is defined here.
 //   Y fieldOfB2; // Error.
 //     ^^^^^^^^^
 //
diff --git a/pkg/front_end/testcases/nnbd/platform_nonnullable_fields/main.dart.strong.expect b/pkg/front_end/testcases/nnbd/platform_nonnullable_fields/main.dart.strong.expect
index 873a553..8aa11f6 100644
--- a/pkg/front_end/testcases/nnbd/platform_nonnullable_fields/main.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/platform_nonnullable_fields/main.dart.strong.expect
@@ -21,7 +21,10 @@
 //   int field;
 //       ^^^^^
 //
-// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/patch_lib2.dart:37:7: Error: This constructor should initialize field 'field' because its type 'int' doesn't allow null.
+// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/origin_lib.dart:8:3: Error: This constructor should initialize field 'field' because its type 'int' doesn't allow null.
+//   Class2.constructor1();
+//   ^
+// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/patch_lib2.dart:37:7: Context: 'field' is defined here.
 //   int field;
 //       ^^^^^
 //
diff --git a/pkg/front_end/testcases/nnbd/platform_nonnullable_fields/main.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/platform_nonnullable_fields/main.dart.strong.transformed.expect
index 873a553..8aa11f6 100644
--- a/pkg/front_end/testcases/nnbd/platform_nonnullable_fields/main.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/platform_nonnullable_fields/main.dart.strong.transformed.expect
@@ -21,7 +21,10 @@
 //   int field;
 //       ^^^^^
 //
-// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/patch_lib2.dart:37:7: Error: This constructor should initialize field 'field' because its type 'int' doesn't allow null.
+// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/origin_lib.dart:8:3: Error: This constructor should initialize field 'field' because its type 'int' doesn't allow null.
+//   Class2.constructor1();
+//   ^
+// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/patch_lib2.dart:37:7: Context: 'field' is defined here.
 //   int field;
 //       ^^^^^
 //
diff --git a/pkg/front_end/testcases/nnbd/platform_nonnullable_fields/main.dart.weak.expect b/pkg/front_end/testcases/nnbd/platform_nonnullable_fields/main.dart.weak.expect
index 873a553..8aa11f6 100644
--- a/pkg/front_end/testcases/nnbd/platform_nonnullable_fields/main.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/platform_nonnullable_fields/main.dart.weak.expect
@@ -21,7 +21,10 @@
 //   int field;
 //       ^^^^^
 //
-// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/patch_lib2.dart:37:7: Error: This constructor should initialize field 'field' because its type 'int' doesn't allow null.
+// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/origin_lib.dart:8:3: Error: This constructor should initialize field 'field' because its type 'int' doesn't allow null.
+//   Class2.constructor1();
+//   ^
+// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/patch_lib2.dart:37:7: Context: 'field' is defined here.
 //   int field;
 //       ^^^^^
 //
diff --git a/pkg/front_end/testcases/nnbd/platform_nonnullable_fields/main.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/platform_nonnullable_fields/main.dart.weak.transformed.expect
index 873a553..8aa11f6 100644
--- a/pkg/front_end/testcases/nnbd/platform_nonnullable_fields/main.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/platform_nonnullable_fields/main.dart.weak.transformed.expect
@@ -21,7 +21,10 @@
 //   int field;
 //       ^^^^^
 //
-// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/patch_lib2.dart:37:7: Error: This constructor should initialize field 'field' because its type 'int' doesn't allow null.
+// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/origin_lib.dart:8:3: Error: This constructor should initialize field 'field' because its type 'int' doesn't allow null.
+//   Class2.constructor1();
+//   ^
+// pkg/front_end/testcases/nnbd/platform_nonnullable_fields/patch_lib2.dart:37:7: Context: 'field' is defined here.
 //   int field;
 //       ^^^^^
 //
diff --git a/pkg/front_end/testcases/static_field_lowering/opt_in.dart.weak.expect b/pkg/front_end/testcases/static_field_lowering/opt_in.dart.weak.expect
index 1fcac9d..da6a3f4 100644
--- a/pkg/front_end/testcases/static_field_lowering/opt_in.dart.weak.expect
+++ b/pkg/front_end/testcases/static_field_lowering/opt_in.dart.weak.expect
@@ -75,8 +75,16 @@
     self::Class::_#nullableStaticFieldWithInitializer2#isSet = true;
     self::Class::_#nullableStaticFieldWithInitializer2 = #t6;
   }
-  static get nonNullableStaticFinalFieldWithInitializer1() → core::int
-    return let final core::int? #t7 = self::Class::_#nonNullableStaticFinalFieldWithInitializer1 in #t7.==(null) ?{core::int} let final core::int #t8 = self::init<core::int>(73) in self::Class::_#nonNullableStaticFinalFieldWithInitializer1.==(null) ?{core::int} self::Class::_#nonNullableStaticFinalFieldWithInitializer1 = #t8 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableStaticFinalFieldWithInitializer1' has been assigned during initialization.") : #t7{core::int};
+  static get nonNullableStaticFinalFieldWithInitializer1() → core::int {
+    if(!self::Class::_#nonNullableStaticFinalFieldWithInitializer1#isSet) {
+      final core::int #t7 = self::init<core::int>(73);
+      if(self::Class::_#nonNullableStaticFinalFieldWithInitializer1#isSet)
+        throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableStaticFinalFieldWithInitializer1' has been assigned during initialization.");
+      self::Class::_#nonNullableStaticFinalFieldWithInitializer1 = #t7;
+      self::Class::_#nonNullableStaticFinalFieldWithInitializer1#isSet = true;
+    }
+    return let final core::int? #t8 = self::Class::_#nonNullableStaticFinalFieldWithInitializer1 in #t8{core::int};
+  }
   static get nullableStaticFinalFieldWithInitializer1() → core::int? {
     if(!self::Class::_#nullableStaticFinalFieldWithInitializer1#isSet) {
       final core::int? #t9 = self::init<core::int?>(19);
@@ -98,8 +106,16 @@
     self::Class::_#nonNullableStaticFinalFieldWithInitializer2Init#isSet = true;
     self::Class::_#nonNullableStaticFinalFieldWithInitializer2Init = #t11;
   }
-  static get nonNullableStaticFinalFieldWithInitializer2() → core::int
-    return let final core::int? #t12 = self::Class::_#nonNullableStaticFinalFieldWithInitializer2 in #t12.==(null) ?{core::int} let final core::int #t13 = (let final core::int #t14 = self::Class::nonNullableStaticFinalFieldWithInitializer2Init in let final core::int #t15 = self::Class::nonNullableStaticFinalFieldWithInitializer2Init = #t14.{core::num::+}(1) in #t14).{core::num::==}(0) ?{core::int} self::Class::nonNullableStaticFinalFieldWithInitializer2.{core::num::+}(1) : 87 in self::Class::_#nonNullableStaticFinalFieldWithInitializer2.==(null) ?{core::int} self::Class::_#nonNullableStaticFinalFieldWithInitializer2 = #t13 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableStaticFinalFieldWithInitializer2' has been assigned during initialization.") : #t12{core::int};
+  static get nonNullableStaticFinalFieldWithInitializer2() → core::int {
+    if(!self::Class::_#nonNullableStaticFinalFieldWithInitializer2#isSet) {
+      final core::int #t12 = (let final core::int #t13 = self::Class::nonNullableStaticFinalFieldWithInitializer2Init in let final core::int #t14 = self::Class::nonNullableStaticFinalFieldWithInitializer2Init = #t13.{core::num::+}(1) in #t13).{core::num::==}(0) ?{core::int} self::Class::nonNullableStaticFinalFieldWithInitializer2.{core::num::+}(1) : 87;
+      if(self::Class::_#nonNullableStaticFinalFieldWithInitializer2#isSet)
+        throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableStaticFinalFieldWithInitializer2' has been assigned during initialization.");
+      self::Class::_#nonNullableStaticFinalFieldWithInitializer2 = #t12;
+      self::Class::_#nonNullableStaticFinalFieldWithInitializer2#isSet = true;
+    }
+    return let final core::int? #t15 = self::Class::_#nonNullableStaticFinalFieldWithInitializer2 in #t15{core::int};
+  }
   static get nullableStaticFinalFieldWithInitializer2Init() → core::int {
     if(!self::Class::_#nullableStaticFinalFieldWithInitializer2Init#isSet) {
       self::Class::_#nullableStaticFinalFieldWithInitializer2Init = 0;
@@ -193,8 +209,16 @@
   self::_#nullableTopLevelFieldWithInitializer2#isSet = true;
   self::_#nullableTopLevelFieldWithInitializer2 = #t26;
 }
-static get nonNullableFinalTopLevelFieldWithInitializer1() → core::int
-  return let final core::int? #t27 = self::_#nonNullableFinalTopLevelFieldWithInitializer1 in #t27.==(null) ?{core::int} let final core::int #t28 = self::init<core::int>(87) in self::_#nonNullableFinalTopLevelFieldWithInitializer1.==(null) ?{core::int} self::_#nonNullableFinalTopLevelFieldWithInitializer1 = #t28 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableFinalTopLevelFieldWithInitializer1' has been assigned during initialization.") : #t27{core::int};
+static get nonNullableFinalTopLevelFieldWithInitializer1() → core::int {
+  if(!self::_#nonNullableFinalTopLevelFieldWithInitializer1#isSet) {
+    final core::int #t27 = self::init<core::int>(87);
+    if(self::_#nonNullableFinalTopLevelFieldWithInitializer1#isSet)
+      throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableFinalTopLevelFieldWithInitializer1' has been assigned during initialization.");
+    self::_#nonNullableFinalTopLevelFieldWithInitializer1 = #t27;
+    self::_#nonNullableFinalTopLevelFieldWithInitializer1#isSet = true;
+  }
+  return let final core::int? #t28 = self::_#nonNullableFinalTopLevelFieldWithInitializer1 in #t28{core::int};
+}
 static get nullableFinalTopLevelFieldWithInitializer1() → core::int? {
   if(!self::_#nullableFinalTopLevelFieldWithInitializer1#isSet) {
     final core::int? #t29 = self::init<core::int?>(32);
@@ -216,8 +240,16 @@
   self::_#nonNullableFinalTopLevelFieldWithInitializer2Init#isSet = true;
   self::_#nonNullableFinalTopLevelFieldWithInitializer2Init = #t31;
 }
-static get nonNullableFinalTopLevelFieldWithInitializer2() → core::int
-  return let final core::int? #t32 = self::_#nonNullableFinalTopLevelFieldWithInitializer2 in #t32.==(null) ?{core::int} let final core::int #t33 = (let final core::int #t34 = self::nonNullableFinalTopLevelFieldWithInitializer2Init in let final core::int #t35 = self::nonNullableFinalTopLevelFieldWithInitializer2Init = #t34.{core::num::+}(1) in #t34).{core::num::==}(0) ?{core::int} self::nonNullableFinalTopLevelFieldWithInitializer2.{core::num::+}(1) : 87 in self::_#nonNullableFinalTopLevelFieldWithInitializer2.==(null) ?{core::int} self::_#nonNullableFinalTopLevelFieldWithInitializer2 = #t33 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableFinalTopLevelFieldWithInitializer2' has been assigned during initialization.") : #t32{core::int};
+static get nonNullableFinalTopLevelFieldWithInitializer2() → core::int {
+  if(!self::_#nonNullableFinalTopLevelFieldWithInitializer2#isSet) {
+    final core::int #t32 = (let final core::int #t33 = self::nonNullableFinalTopLevelFieldWithInitializer2Init in let final core::int #t34 = self::nonNullableFinalTopLevelFieldWithInitializer2Init = #t33.{core::num::+}(1) in #t33).{core::num::==}(0) ?{core::int} self::nonNullableFinalTopLevelFieldWithInitializer2.{core::num::+}(1) : 87;
+    if(self::_#nonNullableFinalTopLevelFieldWithInitializer2#isSet)
+      throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableFinalTopLevelFieldWithInitializer2' has been assigned during initialization.");
+    self::_#nonNullableFinalTopLevelFieldWithInitializer2 = #t32;
+    self::_#nonNullableFinalTopLevelFieldWithInitializer2#isSet = true;
+  }
+  return let final core::int? #t35 = self::_#nonNullableFinalTopLevelFieldWithInitializer2 in #t35{core::int};
+}
 static get nullableFinalTopLevelFieldWithInitializer2Init() → core::int {
   if(!self::_#nullableFinalTopLevelFieldWithInitializer2Init#isSet) {
     self::_#nullableFinalTopLevelFieldWithInitializer2Init = 0;
diff --git a/pkg/front_end/testcases/static_field_lowering/opt_in.dart.weak.transformed.expect b/pkg/front_end/testcases/static_field_lowering/opt_in.dart.weak.transformed.expect
index 1fcac9d..da6a3f4 100644
--- a/pkg/front_end/testcases/static_field_lowering/opt_in.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/static_field_lowering/opt_in.dart.weak.transformed.expect
@@ -75,8 +75,16 @@
     self::Class::_#nullableStaticFieldWithInitializer2#isSet = true;
     self::Class::_#nullableStaticFieldWithInitializer2 = #t6;
   }
-  static get nonNullableStaticFinalFieldWithInitializer1() → core::int
-    return let final core::int? #t7 = self::Class::_#nonNullableStaticFinalFieldWithInitializer1 in #t7.==(null) ?{core::int} let final core::int #t8 = self::init<core::int>(73) in self::Class::_#nonNullableStaticFinalFieldWithInitializer1.==(null) ?{core::int} self::Class::_#nonNullableStaticFinalFieldWithInitializer1 = #t8 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableStaticFinalFieldWithInitializer1' has been assigned during initialization.") : #t7{core::int};
+  static get nonNullableStaticFinalFieldWithInitializer1() → core::int {
+    if(!self::Class::_#nonNullableStaticFinalFieldWithInitializer1#isSet) {
+      final core::int #t7 = self::init<core::int>(73);
+      if(self::Class::_#nonNullableStaticFinalFieldWithInitializer1#isSet)
+        throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableStaticFinalFieldWithInitializer1' has been assigned during initialization.");
+      self::Class::_#nonNullableStaticFinalFieldWithInitializer1 = #t7;
+      self::Class::_#nonNullableStaticFinalFieldWithInitializer1#isSet = true;
+    }
+    return let final core::int? #t8 = self::Class::_#nonNullableStaticFinalFieldWithInitializer1 in #t8{core::int};
+  }
   static get nullableStaticFinalFieldWithInitializer1() → core::int? {
     if(!self::Class::_#nullableStaticFinalFieldWithInitializer1#isSet) {
       final core::int? #t9 = self::init<core::int?>(19);
@@ -98,8 +106,16 @@
     self::Class::_#nonNullableStaticFinalFieldWithInitializer2Init#isSet = true;
     self::Class::_#nonNullableStaticFinalFieldWithInitializer2Init = #t11;
   }
-  static get nonNullableStaticFinalFieldWithInitializer2() → core::int
-    return let final core::int? #t12 = self::Class::_#nonNullableStaticFinalFieldWithInitializer2 in #t12.==(null) ?{core::int} let final core::int #t13 = (let final core::int #t14 = self::Class::nonNullableStaticFinalFieldWithInitializer2Init in let final core::int #t15 = self::Class::nonNullableStaticFinalFieldWithInitializer2Init = #t14.{core::num::+}(1) in #t14).{core::num::==}(0) ?{core::int} self::Class::nonNullableStaticFinalFieldWithInitializer2.{core::num::+}(1) : 87 in self::Class::_#nonNullableStaticFinalFieldWithInitializer2.==(null) ?{core::int} self::Class::_#nonNullableStaticFinalFieldWithInitializer2 = #t13 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableStaticFinalFieldWithInitializer2' has been assigned during initialization.") : #t12{core::int};
+  static get nonNullableStaticFinalFieldWithInitializer2() → core::int {
+    if(!self::Class::_#nonNullableStaticFinalFieldWithInitializer2#isSet) {
+      final core::int #t12 = (let final core::int #t13 = self::Class::nonNullableStaticFinalFieldWithInitializer2Init in let final core::int #t14 = self::Class::nonNullableStaticFinalFieldWithInitializer2Init = #t13.{core::num::+}(1) in #t13).{core::num::==}(0) ?{core::int} self::Class::nonNullableStaticFinalFieldWithInitializer2.{core::num::+}(1) : 87;
+      if(self::Class::_#nonNullableStaticFinalFieldWithInitializer2#isSet)
+        throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableStaticFinalFieldWithInitializer2' has been assigned during initialization.");
+      self::Class::_#nonNullableStaticFinalFieldWithInitializer2 = #t12;
+      self::Class::_#nonNullableStaticFinalFieldWithInitializer2#isSet = true;
+    }
+    return let final core::int? #t15 = self::Class::_#nonNullableStaticFinalFieldWithInitializer2 in #t15{core::int};
+  }
   static get nullableStaticFinalFieldWithInitializer2Init() → core::int {
     if(!self::Class::_#nullableStaticFinalFieldWithInitializer2Init#isSet) {
       self::Class::_#nullableStaticFinalFieldWithInitializer2Init = 0;
@@ -193,8 +209,16 @@
   self::_#nullableTopLevelFieldWithInitializer2#isSet = true;
   self::_#nullableTopLevelFieldWithInitializer2 = #t26;
 }
-static get nonNullableFinalTopLevelFieldWithInitializer1() → core::int
-  return let final core::int? #t27 = self::_#nonNullableFinalTopLevelFieldWithInitializer1 in #t27.==(null) ?{core::int} let final core::int #t28 = self::init<core::int>(87) in self::_#nonNullableFinalTopLevelFieldWithInitializer1.==(null) ?{core::int} self::_#nonNullableFinalTopLevelFieldWithInitializer1 = #t28 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableFinalTopLevelFieldWithInitializer1' has been assigned during initialization.") : #t27{core::int};
+static get nonNullableFinalTopLevelFieldWithInitializer1() → core::int {
+  if(!self::_#nonNullableFinalTopLevelFieldWithInitializer1#isSet) {
+    final core::int #t27 = self::init<core::int>(87);
+    if(self::_#nonNullableFinalTopLevelFieldWithInitializer1#isSet)
+      throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableFinalTopLevelFieldWithInitializer1' has been assigned during initialization.");
+    self::_#nonNullableFinalTopLevelFieldWithInitializer1 = #t27;
+    self::_#nonNullableFinalTopLevelFieldWithInitializer1#isSet = true;
+  }
+  return let final core::int? #t28 = self::_#nonNullableFinalTopLevelFieldWithInitializer1 in #t28{core::int};
+}
 static get nullableFinalTopLevelFieldWithInitializer1() → core::int? {
   if(!self::_#nullableFinalTopLevelFieldWithInitializer1#isSet) {
     final core::int? #t29 = self::init<core::int?>(32);
@@ -216,8 +240,16 @@
   self::_#nonNullableFinalTopLevelFieldWithInitializer2Init#isSet = true;
   self::_#nonNullableFinalTopLevelFieldWithInitializer2Init = #t31;
 }
-static get nonNullableFinalTopLevelFieldWithInitializer2() → core::int
-  return let final core::int? #t32 = self::_#nonNullableFinalTopLevelFieldWithInitializer2 in #t32.==(null) ?{core::int} let final core::int #t33 = (let final core::int #t34 = self::nonNullableFinalTopLevelFieldWithInitializer2Init in let final core::int #t35 = self::nonNullableFinalTopLevelFieldWithInitializer2Init = #t34.{core::num::+}(1) in #t34).{core::num::==}(0) ?{core::int} self::nonNullableFinalTopLevelFieldWithInitializer2.{core::num::+}(1) : 87 in self::_#nonNullableFinalTopLevelFieldWithInitializer2.==(null) ?{core::int} self::_#nonNullableFinalTopLevelFieldWithInitializer2 = #t33 : throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableFinalTopLevelFieldWithInitializer2' has been assigned during initialization.") : #t32{core::int};
+static get nonNullableFinalTopLevelFieldWithInitializer2() → core::int {
+  if(!self::_#nonNullableFinalTopLevelFieldWithInitializer2#isSet) {
+    final core::int #t32 = (let final core::int #t33 = self::nonNullableFinalTopLevelFieldWithInitializer2Init in let final core::int #t34 = self::nonNullableFinalTopLevelFieldWithInitializer2Init = #t33.{core::num::+}(1) in #t33).{core::num::==}(0) ?{core::int} self::nonNullableFinalTopLevelFieldWithInitializer2.{core::num::+}(1) : 87;
+    if(self::_#nonNullableFinalTopLevelFieldWithInitializer2#isSet)
+      throw new _in::LateInitializationErrorImpl::•("Field 'nonNullableFinalTopLevelFieldWithInitializer2' has been assigned during initialization.");
+    self::_#nonNullableFinalTopLevelFieldWithInitializer2 = #t32;
+    self::_#nonNullableFinalTopLevelFieldWithInitializer2#isSet = true;
+  }
+  return let final core::int? #t35 = self::_#nonNullableFinalTopLevelFieldWithInitializer2 in #t35{core::int};
+}
 static get nullableFinalTopLevelFieldWithInitializer2Init() → core::int {
   if(!self::_#nullableFinalTopLevelFieldWithInitializer2Init#isSet) {
     self::_#nullableFinalTopLevelFieldWithInitializer2Init = 0;
diff --git a/pkg/front_end/testcases/strong.status b/pkg/front_end/testcases/strong.status
index 955761c..6c237da 100644
--- a/pkg/front_end/testcases/strong.status
+++ b/pkg/front_end/testcases/strong.status
@@ -171,6 +171,7 @@
 instantiate_to_bound/non_simple_class_parametrized_typedef_cycle: RuntimeError # Expected
 instantiate_to_bound/non_simple_generic_function_in_bound_regress: RuntimeError # Expected
 late_lowering/covariant_late_field: TypeCheckError
+late_lowering/initializer_rewrite_from_opt_out: RuntimeError # Test is inherently mixed mode
 late_lowering/non_nullable_from_opt_out: RuntimeError # Test is inherently mixed mode
 nnbd/covariant_late_field: TypeCheckError
 nnbd/issue41180: RuntimeError # Strong mode runtime checking fails due to mixed strong mode.
diff --git a/pkg/front_end/testcases/text_serialization.status b/pkg/front_end/testcases/text_serialization.status
index ccd0d03..825cdf1 100644
--- a/pkg/front_end/testcases/text_serialization.status
+++ b/pkg/front_end/testcases/text_serialization.status
@@ -169,6 +169,7 @@
 instantiate_to_bound/non_simple_class_parametrized_typedef_cycle: RuntimeError
 instantiate_to_bound/non_simple_generic_function_in_bound_regress: RuntimeError
 late_lowering/covariant_late_field: TypeCheckError
+late_lowering/initializer_rewrite_from_opt_out: RuntimeError # Test is inherently mixed mode
 late_lowering/non_nullable_from_opt_out: RuntimeError # Test is inherently mixed mode
 nnbd/covariant_late_field: TypeCheckError
 nnbd/issue41180: RuntimeError
diff --git a/pkg/front_end/testcases/textual_outline.status b/pkg/front_end/testcases/textual_outline.status
index 5565670..bc6e72f 100644
--- a/pkg/front_end/testcases/textual_outline.status
+++ b/pkg/front_end/testcases/textual_outline.status
@@ -131,6 +131,7 @@
 late_lowering/covariant_late_field: FormatterCrash
 late_lowering/infer_late_field_type: FormatterCrash
 late_lowering/initializer_rewrite: FormatterCrash
+late_lowering/initializer_rewrite_from_opt_out: FormatterCrash
 late_lowering/instance_field_with_initializer: FormatterCrash
 late_lowering/instance_field_without_initializer: FormatterCrash
 late_lowering/instance_final_field_without_initializer: FormatterCrash
@@ -157,6 +158,7 @@
 late_lowering/later: FormatterCrash
 late_lowering/override: FormatterCrash
 late_lowering/override_getter_setter: FormatterCrash
+late_lowering_sentinel/late_fields: FormatterCrash
 late_lowering/uninitialized_non_nullable_late_fields: FormatterCrash
 nnbd/abstract_field_errors: FormatterCrash
 nnbd/covariant_late_field: FormatterCrash
@@ -170,6 +172,7 @@
 nnbd/issue40805: FormatterCrash
 nnbd/issue41349: FormatterCrash
 nnbd/issue41597: FormatterCrash
+nnbd/issue42967: FormatterCrash
 nnbd/issue43278: FormatterCrash
 nnbd/late: FormatterCrash
 nnbd/later: FormatterCrash
@@ -234,4 +237,3 @@
 variance/generic_covariance_sound_variance: FormatterCrash
 variance/mixin_type_parameter_modifier: FormatterCrash
 variance/unconstrained_inference: FormatterCrash
-
diff --git a/pkg/frontend_server/lib/frontend_server.dart b/pkg/frontend_server/lib/frontend_server.dart
index c95b0a2..9e583c2 100644
--- a/pkg/frontend_server/lib/frontend_server.dart
+++ b/pkg/frontend_server/lib/frontend_server.dart
@@ -342,6 +342,7 @@
 
   CompilerOptions _compilerOptions;
   BytecodeOptions _bytecodeOptions;
+  ProcessedOptions _processedOptions;
   FileSystem _fileSystem;
   Uri _mainSource;
   ArgResults _options;
@@ -516,6 +517,7 @@
 
     _compilerOptions = compilerOptions;
     _bytecodeOptions = bytecodeOptions;
+    _processedOptions = ProcessedOptions(options: compilerOptions);
 
     KernelCompilationResults results;
     IncrementalSerializer incrementalSerializer;
@@ -972,14 +974,21 @@
     final String boundaryKey = Uuid().generateV4();
     _outputStream.writeln('result $boundaryKey');
 
+    _processedOptions.ticker.logMs('Compiling expression to JavaScript');
+
     var kernel2jsCompiler = _bundler.compilers[moduleName];
     Component component = _generator.lastKnownGoodComponent;
     component.computeCanonicalNames();
+
+    _processedOptions.ticker.logMs('Computed component');
+
     var evaluator = new ExpressionCompiler(
-        _generator.generator, kernel2jsCompiler, component,
-        verbose: _compilerOptions.verbose,
-        onDiagnostic: _compilerOptions.onDiagnostic,
-        errors: errors);
+      _compilerOptions,
+      errors,
+      _generator.generator,
+      kernel2jsCompiler,
+      component,
+    );
 
     var procedure = await evaluator.compileExpressionToJs(libraryUri, line,
         column, jsModules, jsFrameValues, moduleName, expression);
@@ -990,6 +999,8 @@
     // rename to _outputFileName?
     await File(_kernelBinaryFilename).writeAsString(result);
 
+    _processedOptions.ticker.logMs('Compiled expression to JavaScript');
+
     _outputStream
         .writeln('$boundaryKey $_kernelBinaryFilename ${errors.length}');
 
diff --git a/pkg/kernel/lib/core_types.dart b/pkg/kernel/lib/core_types.dart
index cc60986..832f966 100644
--- a/pkg/kernel/lib/core_types.dart
+++ b/pkg/kernel/lib/core_types.dart
@@ -71,6 +71,8 @@
   Procedure _iterableGetIterator;
   Procedure _iteratorMoveNext;
   Procedure _iteratorGetCurrent;
+  Procedure _isSentinelMethod;
+  Procedure _createSentinelMethod;
 
   Class _internalSymbolClass;
 
@@ -497,6 +499,16 @@
         index.getMember('dart:core', 'bool', 'fromEnvironment');
   }
 
+  Procedure get createSentinelMethod {
+    return _createSentinelMethod ??=
+        index.getTopLevelMember('dart:_internal', 'createSentinel');
+  }
+
+  Procedure get isSentinelMethod {
+    return _isSentinelMethod ??=
+        index.getTopLevelMember('dart:_internal', 'isSentinel');
+  }
+
   InterfaceType get objectLegacyRawType {
     return _objectLegacyRawType ??= _legacyRawTypes[objectClass] ??=
         new InterfaceType(objectClass, Nullability.legacy, const <DartType>[]);
diff --git a/pkg/kernel/lib/default_language_version.dart b/pkg/kernel/lib/default_language_version.dart
index 6b7b18c..eb90980 100644
--- a/pkg/kernel/lib/default_language_version.dart
+++ b/pkg/kernel/lib/default_language_version.dart
@@ -9,4 +9,4 @@
 
 import "ast.dart";
 
-Version defaultLanguageVersion = const Version(2, 10);
+Version defaultLanguageVersion = const Version(2, 11);
diff --git a/pkg/kernel/lib/target/targets.dart b/pkg/kernel/lib/target/targets.dart
index 1aa2f44..93ea3c9 100644
--- a/pkg/kernel/lib/target/targets.dart
+++ b/pkg/kernel/lib/target/targets.dart
@@ -14,6 +14,7 @@
 class TargetFlags {
   final bool trackWidgetCreation;
   final bool forceLateLoweringForTesting;
+  final bool forceLateLoweringSentinelForTesting;
   final bool forceStaticFieldLoweringForTesting;
   final bool forceNoExplicitGetterCallsForTesting;
   final bool enableNullSafety;
@@ -21,6 +22,7 @@
   const TargetFlags(
       {this.trackWidgetCreation = false,
       this.forceLateLoweringForTesting = false,
+      this.forceLateLoweringSentinelForTesting = false,
       this.forceStaticFieldLoweringForTesting = false,
       this.forceNoExplicitGetterCallsForTesting = false,
       this.enableNullSafety = false});
@@ -30,6 +32,8 @@
     return other is TargetFlags &&
         trackWidgetCreation == other.trackWidgetCreation &&
         forceLateLoweringForTesting == other.forceLateLoweringForTesting &&
+        forceLateLoweringSentinelForTesting ==
+            other.forceLateLoweringSentinelForTesting &&
         forceStaticFieldLoweringForTesting ==
             other.forceStaticFieldLoweringForTesting &&
         forceNoExplicitGetterCallsForTesting ==
@@ -43,6 +47,8 @@
     hash = 0x3fffffff &
         (hash * 31 + (hash ^ forceLateLoweringForTesting.hashCode));
     hash = 0x3fffffff &
+        (hash * 31 + (hash ^ forceLateLoweringSentinelForTesting.hashCode));
+    hash = 0x3fffffff &
         (hash * 31 + (hash ^ forceStaticFieldLoweringForTesting.hashCode));
     hash = 0x3fffffff &
         (hash * 31 + (hash ^ forceNoExplicitGetterCallsForTesting.hashCode));
@@ -282,6 +288,13 @@
   /// details.
   bool get supportsLateFields;
 
+  /// If `true`, the backend supports creation and checking of a sentinel value
+  /// for uninitialized late fields and variables through the `createSentinel`
+  /// and `isSentinel` methods in `dart:_internal`.
+  ///
+  /// If `true` this is used when [supportsLateFields] is `false`.
+  bool get supportsLateLoweringSentinel;
+
   /// Whether static fields with initializers in nnbd libraries should be
   /// encoded using the late field lowering.
   bool get useStaticFieldLowering;
@@ -349,6 +362,10 @@
   bool get supportsLateFields => !flags.forceLateLoweringForTesting;
 
   @override
+  bool get supportsLateLoweringSentinel =>
+      flags.forceLateLoweringSentinelForTesting;
+
+  @override
   bool get useStaticFieldLowering => flags.forceStaticFieldLoweringForTesting;
 
   @override
diff --git a/pkg/meta/CHANGELOG.md b/pkg/meta/CHANGELOG.md
index 9e27c00..d80e12b 100644
--- a/pkg/meta/CHANGELOG.md
+++ b/pkg/meta/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 1.3.0-nullsafety.4
+
+* Introduce `@internal` to annotate elements that should not be used outside of
+  the package in which the element is declared.
+
 ## 1.3.0-nullsafety.3
 
 * Allow 2.10 stable and 2.11.0 dev SDK versions.
diff --git a/pkg/meta/lib/meta.dart b/pkg/meta/lib/meta.dart
index 11652e1..c6dff3b 100644
--- a/pkg/meta/lib/meta.dart
+++ b/pkg/meta/lib/meta.dart
@@ -126,6 +126,20 @@
 ///   class that has this annotation is not immutable.
 const Immutable immutable = Immutable();
 
+/// Used to annotate a declaration which should only be used from within the
+/// package in which it is declared, and which should not be exposed from said
+/// package's public API.
+///
+/// Tools, such as the analyzer, can provide feedback if
+///
+/// * the declaration is declared in a package's public API, or is exposed from
+///   a package's public API, or
+/// * the declaration is private, an unnamed extension, a static member of a
+///   private class, mixin, or extension, a value of a private enum, or a
+///   constructor of a private class, or
+/// * the declaration is referenced outside the package in which it is declared.
+const _Internal internal = _Internal();
+
 /// Used to annotate a test framework function that runs a single test.
 ///
 /// Tools, such as IDEs, can show invocations of such function in a file
@@ -257,15 +271,15 @@
 /// * the member is referenced outside of the defining library.
 const _VisibleForOverriding visibleForOverriding = _VisibleForOverriding();
 
-/// Used to annotate a declaration was made public, so that it is more visible
-/// than otherwise necessary, to make code testable.
+/// Used to annotate a declaration that was made public, so that it is more
+/// visible than otherwise necessary, to make code testable.
 ///
 /// Tools, such as the analyzer, can provide feedback if
 ///
 /// * the annotation is associated with a declaration not in the `lib` folder
 ///   of a package, or a private declaration, or a declaration in an unnamed
 ///   static extension, or
-/// * the declaration is referenced outside of its the defining library or a
+/// * the declaration is referenced outside of its defining library or a
 ///   library which is in the `test` folder of the defining package.
 const _VisibleForTesting visibleForTesting = _VisibleForTesting();
 
@@ -326,6 +340,10 @@
   const _Factory();
 }
 
+class _Internal {
+  const _Internal();
+}
+
 class _IsTest {
   const _IsTest();
 }
diff --git a/pkg/native_stack_traces/analysis_options.yaml b/pkg/native_stack_traces/analysis_options.yaml
index 84a5e26..486705d 100644
--- a/pkg/native_stack_traces/analysis_options.yaml
+++ b/pkg/native_stack_traces/analysis_options.yaml
@@ -1 +1 @@
-include: package:pedantic/analysis_options.1.8.0.yaml
+include: package:pedantic/analysis_options.1.9.0.yaml
diff --git a/pkg/native_stack_traces/bin/decode.dart b/pkg/native_stack_traces/bin/decode.dart
index 2458e16..9a7aee0 100644
--- a/pkg/native_stack_traces/bin/decode.dart
+++ b/pkg/native_stack_traces/bin/decode.dart
@@ -123,7 +123,7 @@
 Options specific to the find command:
 ${_findParser.usage}''';
 
-final _usages = <String, String>{
+final _usages = <String?, String>{
   null: _mainUsage,
   '': _mainUsage,
   'help': _helpUsage,
@@ -133,7 +133,7 @@
 
 const int _badUsageExitCode = 1;
 
-void errorWithUsage(String message, {String command}) {
+void errorWithUsage(String message, {String? command}) {
   print("Error: $message.\n");
   print(_usages[command]);
   io.exitCode = _badUsageExitCode;
@@ -156,7 +156,7 @@
   }
 }
 
-Dwarf _loadFromFile(String original, Function(String) usageError) {
+Dwarf? _loadFromFile(String? original, Function(String) usageError) {
   if (original == null) {
     usageError('must provide -d/--debug');
     return null;
@@ -178,7 +178,7 @@
   final bool forceHexadecimal = options['force_hexadecimal'];
 
   void usageError(String message) => errorWithUsage(message, command: 'find');
-  int parseIntAddress(String s) {
+  int? tryParseIntAddress(String s) {
     if (!forceHexadecimal && !s.startsWith("0x")) {
       final decimal = int.tryParse(s);
       if (decimal != null) return decimal;
@@ -186,11 +186,11 @@
     return int.tryParse(s.startsWith("0x") ? s.substring(2) : s, radix: 16);
   }
 
-  PCOffset convertAddress(StackTraceHeader header, String s) {
+  PCOffset? convertAddress(StackTraceHeader header, String s) {
     final parsedOffset = tryParseSymbolOffset(s, forceHexadecimal);
     if (parsedOffset != null) return parsedOffset;
 
-    final address = parseIntAddress(s);
+    final address = tryParseIntAddress(s);
     if (address != null) return header.offsetOf(address);
 
     return null;
@@ -209,20 +209,22 @@
 
   int vmStart = dwarf.vmStartAddress;
   if (options['vm_start'] != null) {
-    vmStart = parseIntAddress(options['vm_start']);
-    if (vmStart == null) {
+    final address = tryParseIntAddress(options['vm_start']);
+    if (address == null) {
       return usageError('could not parse VM start address '
           '${options['vm_start']}');
     }
+    vmStart = address;
   }
 
   int isolateStart = dwarf.isolateStartAddress;
   if (options['isolate_start'] != null) {
-    isolateStart = parseIntAddress(options['isolate_start']);
-    if (isolateStart == null) {
+    final address = tryParseIntAddress(options['isolate_start']);
+    if (address == null) {
       return usageError('could not parse isolate start address '
           '${options['isolate_start']}');
     }
+    isolateStart = address;
   }
 
   final header = StackTraceHeader(isolateStart, vmStart);
diff --git a/pkg/native_stack_traces/lib/src/convert.dart b/pkg/native_stack_traces/lib/src/convert.dart
index 8f81c17..b6d96b4 100644
--- a/pkg/native_stack_traces/lib/src/convert.dart
+++ b/pkg/native_stack_traces/lib/src/convert.dart
@@ -27,11 +27,11 @@
 //
 // Returns a new [StackTraceHeader] if [line] contains the needed header
 // information, otherwise returns `null`.
-StackTraceHeader _parseInstructionsLine(String line) {
+StackTraceHeader? _parseInstructionsLine(String line) {
   final match = _headerEndRE.firstMatch(line);
   if (match == null) return null;
-  final isolateAddr = int.parse(match[1], radix: 16);
-  final vmAddr = int.parse(match[2], radix: 16);
+  final isolateAddr = int.parse(match[1]!, radix: 16);
+  final vmAddr = int.parse(match[2]!, radix: 16);
   return StackTraceHeader(isolateAddr, vmAddr);
 }
 
@@ -81,12 +81,12 @@
 /// any hexdecimal digits will be parsed as decimal.
 ///
 /// Returns null if the string is not of the expected format.
-PCOffset tryParseSymbolOffset(String s, [bool forceHexadecimal = false]) {
+PCOffset? tryParseSymbolOffset(String s, [bool forceHexadecimal = false]) {
   final match = _symbolOffsetRE.firstMatch(s);
   if (match == null) return null;
-  final symbolString = match.namedGroup('symbol');
-  final offsetString = match.namedGroup('offset');
-  int offset;
+  final symbolString = match.namedGroup('symbol')!;
+  final offsetString = match.namedGroup('offset')!;
+  int? offset;
   if (!forceHexadecimal && !offsetString.startsWith("0x")) {
     offset = int.tryParse(offsetString);
   }
@@ -108,9 +108,9 @@
   return null;
 }
 
-PCOffset _retrievePCOffset(StackTraceHeader header, RegExpMatch match) {
+PCOffset? _retrievePCOffset(StackTraceHeader? header, RegExpMatch? match) {
   if (match == null) return null;
-  final restString = match.namedGroup('rest');
+  final restString = match.namedGroup('rest')!;
   // Try checking for symbol information first, since we don't need the header
   // information to translate it.
   if (restString.isNotEmpty) {
@@ -120,8 +120,8 @@
   // If we're parsing the absolute address, we can only convert it into
   // a PCOffset if we saw the instructions line of the stack trace header.
   if (header != null) {
-    final addressString = match.namedGroup('absolute');
-    final address = int.tryParse(addressString, radix: 16);
+    final addressString = match.namedGroup('absolute')!;
+    final address = int.parse(addressString, radix: 16);
     return header.offsetOf(address);
   }
   // If all other cases failed, check for a virtual address. Until this package
@@ -130,7 +130,7 @@
   // debugging information, the other methods should be tried first.
   final virtualString = match.namedGroup('virtual');
   if (virtualString != null) {
-    final address = int.tryParse(virtualString, radix: 16);
+    final address = int.parse(virtualString, radix: 16);
     return PCOffset(address, InstructionsSection.none);
   }
   return null;
@@ -138,7 +138,7 @@
 
 /// The [PCOffset]s for frames of the non-symbolic stack traces in [lines].
 Iterable<PCOffset> collectPCOffsets(Iterable<String> lines) sync* {
-  StackTraceHeader header;
+  StackTraceHeader? header;
   for (var line in lines) {
     final parsedHeader = _parseInstructionsLine(line);
     if (parsedHeader != null) {
@@ -184,7 +184,7 @@
 
   Stream<String> bind(Stream<String> stream) async* {
     int depth = 0;
-    StackTraceHeader header;
+    StackTraceHeader? header;
     await for (final line in stream) {
       final parsedHeader = _parseInstructionsLine(line);
       if (parsedHeader != null) {
@@ -207,7 +207,7 @@
       if (callInfo.isEmpty) continue;
       // Output the lines for the symbolic frame with the prefix found on the
       // original non-symbolic frame line.
-      final prefix = line.substring(0, lineMatch.start);
+      final prefix = line.substring(0, lineMatch!.start);
       for (final call in callInfo) {
         yield prefix + _stackTracePiece(call, depth++);
       }
diff --git a/pkg/native_stack_traces/lib/src/dwarf.dart b/pkg/native_stack_traces/lib/src/dwarf.dart
index fd0911b..e8d7ef1 100644
--- a/pkg/native_stack_traces/lib/src/dwarf.dart
+++ b/pkg/native_stack_traces/lib/src/dwarf.dart
@@ -122,7 +122,7 @@
 
   _Attribute._(this.name, this.form);
 
-  static _Attribute fromReader(Reader reader) {
+  static _Attribute? fromReader(Reader reader) {
     final nameInt = reader.readLEB128EncodedInteger();
     final formInt = reader.readLEB128EncodedInteger();
     if (nameInt == 0 && formInt == 0) return null;
@@ -132,7 +132,7 @@
     if (!_attributeForms.containsKey(formInt)) {
       throw FormatException("Unexpected DW_FORM value 0x${paddedHex(formInt)}");
     }
-    return _Attribute._(_attributeNames[nameInt], _attributeForms[formInt]);
+    return _Attribute._(_attributeNames[nameInt]!, _attributeForms[formInt]!);
   }
 
   Object read(Reader reader, CompilationUnitHeader header) {
@@ -148,25 +148,24 @@
       case _AttributeForm.reference4:
         return reader.readBytes(4);
     }
-    return null;
   }
 
-  String valueToString(Object value, [CompilationUnit unit]) {
+  String valueToString(Object value, [CompilationUnit? unit]) {
     switch (form) {
       case _AttributeForm.string:
         return value as String;
       case _AttributeForm.address:
-        return '0x' + paddedHex(value as int, unit?.header?.addressSize ?? 0);
+        return '0x' + paddedHex(value as int, unit?.header.addressSize ?? 0);
       case _AttributeForm.sectionOffset:
         return paddedHex(value as int, 4);
       case _AttributeForm.constant:
         return value.toString();
       case _AttributeForm.reference4:
-        final unresolvedValue = paddedHex(value as int, 4);
-        final name = unit?.nameOfOrigin(value as int) ?? "(unresolved)";
+        final intValue = value as int;
+        final unresolvedValue = paddedHex(intValue, 4);
+        final name = unit?.nameOfOrigin(intValue) ?? "<unresolved>";
         return '0x${unresolvedValue} (origin: ${name})';
     }
-    return "<unknown>";
   }
 }
 
@@ -182,14 +181,14 @@
   static const _DW_CHILDREN_no = 0x00;
   static const _DW_CHILDREN_yes = 0x01;
 
-  static _Abbreviation fromReader(Reader reader) {
+  static _Abbreviation? fromReader(Reader reader) {
     final code = reader.readLEB128EncodedInteger();
     if (code == 0) return null;
     final tagInt = reader.readLEB128EncodedInteger();
     if (!_tags.containsKey(tagInt)) {
       throw FormatException("Unexpected DW_TAG value 0x${paddedHex(tagInt)}");
     }
-    final tag = _tags[tagInt];
+    final tag = _tags[tagInt]!;
     final childrenByte = reader.readByte();
     if (childrenByte != _DW_CHILDREN_no && childrenByte != _DW_CHILDREN_yes) {
       throw FormatException("Expected DW_CHILDREN_no or DW_CHILDREN_yes: "
@@ -210,9 +209,9 @@
     for (final attribute in attributes) {
       buffer
         ..write('      ')
-        ..write(_attributeNameStrings[attribute.name])
+        ..write(_attributeNameStrings[attribute.name]!)
         ..write(': ')
-        ..writeln(_attributeFormStrings[attribute.form]);
+        ..writeln(_attributeFormStrings[attribute.form]!);
     }
   }
 
@@ -230,9 +229,9 @@
   _AbbreviationsTable._(this._abbreviations);
 
   bool containsKey(int code) => _abbreviations.containsKey(code);
-  _Abbreviation operator [](int code) => _abbreviations[code];
+  _Abbreviation? operator [](int code) => _abbreviations[code];
 
-  static _AbbreviationsTable fromReader(Reader reader) {
+  static _AbbreviationsTable? fromReader(Reader reader) {
     final abbreviations = Map.fromEntries(reader
         .readRepeated(_Abbreviation.fromReader)
         .map((abbr) => MapEntry(abbr.code, abbr)));
@@ -241,14 +240,14 @@
 
   void writeToStringBuffer(StringBuffer buffer) {
     buffer..writeln('Abbreviations table:')..writeln();
-    for (final key in _abbreviations.keys) {
+    _abbreviations.forEach((key, abbreviation) {
       buffer
         ..write('  ')
         ..write(key)
         ..writeln(':');
-      _abbreviations[key].writeToStringBuffer(buffer);
+      abbreviation.writeToStringBuffer(buffer);
       buffer..writeln();
-    }
+    });
   }
 
   @override
@@ -268,7 +267,7 @@
 
   DebugInformationEntry._(this.code, this.attributes, this.children);
 
-  static DebugInformationEntry fromReader(
+  static DebugInformationEntry? fromReader(
       Reader reader, CompilationUnitHeader header) {
     final code = reader.readLEB128EncodedInteger();
     // DIEs with an abbreviation table index of 0 are list end markers.
@@ -276,81 +275,83 @@
     if (!header.abbreviations.containsKey(code)) {
       throw FormatException("Unknown abbreviation code 0x${paddedHex(code)}");
     }
-    final abbreviation = header.abbreviations[code];
+    final abbreviation = header.abbreviations[code]!;
     final attributes = <_Attribute, Object>{};
     for (final attribute in abbreviation.attributes) {
       attributes[attribute] = attribute.read(reader, header);
     }
-    Map<int, DebugInformationEntry> children;
+    final children = <int, DebugInformationEntry>{};
     if (abbreviation.children) {
-      children = Map.fromEntries(reader.readRepeatedWithOffsets(
+      children.addEntries(reader.readRepeatedWithOffsets(
           (r) => DebugInformationEntry.fromReader(r, header),
           absolute: true));
     }
-    assert((children != null) == abbreviation.children);
     return DebugInformationEntry._(code, attributes, children);
   }
 
-  _Attribute _namedAttribute(_AttributeName name) => attributes.keys
-      .firstWhere((_Attribute k) => k.name == name, orElse: () => null);
+  _Attribute? _namedAttribute(_AttributeName name) {
+    for (final attribute in attributes.keys) {
+      if (attribute.name == name) {
+        return attribute;
+      }
+    }
+    return null;
+  }
 
   bool containsKey(_AttributeName name) => _namedAttribute(name) != null;
 
-  Object operator [](_AttributeName name) => attributes[_namedAttribute(name)];
+  Object? operator [](_AttributeName name) => attributes[_namedAttribute(name)];
 
-  int get abstractOrigin => this[_AttributeName.abstractOrigin] as int;
+  int? get sectionOffset => this[_AttributeName.statementList] as int?;
 
-  int get lowPC => this[_AttributeName.lowProgramCounter] as int;
+  int? get abstractOrigin => this[_AttributeName.abstractOrigin] as int?;
 
-  int get highPC => this[_AttributeName.highProgramCounter] as int;
+  int? get lowPC => this[_AttributeName.lowProgramCounter] as int?;
+
+  int? get highPC => this[_AttributeName.highProgramCounter] as int?;
 
   bool containsPC(int virtualAddress) =>
-      lowPC != null && lowPC <= virtualAddress && virtualAddress < highPC;
+      (lowPC ?? 0) <= virtualAddress && virtualAddress < (highPC ?? -1);
 
-  String get name => this[_AttributeName.name] as String;
+  String? get name => this[_AttributeName.name] as String?;
 
-  int get callFileIndex => this[_AttributeName.callFile] as int;
+  int? get callFileIndex => this[_AttributeName.callFile] as int?;
 
-  int get callLine => this[_AttributeName.callLine] as int;
+  int? get callLine => this[_AttributeName.callLine] as int?;
 
-  // We don't assume that call columns are present for backwards compatibility.
-  int get callColumn => containsKey(_AttributeName.callColumn)
-      ? this[_AttributeName.callColumn] as int
-      : 0;
+  int? get callColumn => this[_AttributeName.callColumn] as int?;
 
-  List<CallInfo> callInfo(
+  List<CallInfo>? callInfo(
       CompilationUnit unit, LineNumberProgram lineNumberProgram, int address) {
     String callFilename(int index) =>
-        lineNumberProgram.header.filesInfo[index].name;
+        lineNumberProgram.header.filesInfo[index]?.name ?? '<unknown file>';
     if (!containsPC(address)) return null;
 
-    final tag = unit.header.abbreviations[code].tag;
+    final tag = unit.header.abbreviations[code]!.tag;
     final inlined = tag == _Tag.inlinedSubroutine;
-    if (children != null) {
-      for (final child in children.values) {
-        final callInfo = child.callInfo(unit, lineNumberProgram, address);
-        if (callInfo == null) continue;
+    for (final child in children.values) {
+      final callInfo = child.callInfo(unit, lineNumberProgram, address);
+      if (callInfo == null) continue;
 
-        if (tag == _Tag.compileUnit) return callInfo;
+      if (tag == _Tag.compileUnit) return callInfo;
 
-        return callInfo
-          ..add(DartCallInfo(
-              function: unit.nameOfOrigin(abstractOrigin),
-              inlined: inlined,
-              filename: callFilename(child.callFileIndex),
-              line: child.callLine,
-              column: child.callColumn));
-      }
+      return callInfo
+        ..add(DartCallInfo(
+            function: unit.nameOfOrigin(abstractOrigin ?? -1),
+            inlined: inlined,
+            filename: callFilename(child.callFileIndex ?? -1),
+            line: child.callLine ?? 0,
+            column: child.callColumn ?? 0));
     }
 
     if (tag == _Tag.compileUnit) return null;
 
-    final filename = lineNumberProgram.filename(address);
-    final line = lineNumberProgram.lineNumber(address);
-    final column = lineNumberProgram.column(address);
+    final filename = lineNumberProgram.filename(address)!;
+    final line = lineNumberProgram.lineNumber(address)!;
+    final column = lineNumberProgram.column(address)!;
     return [
       DartCallInfo(
-          function: unit.nameOfOrigin(abstractOrigin),
+          function: unit.nameOfOrigin(abstractOrigin ?? -1),
           inlined: inlined,
           filename: filename,
           line: line,
@@ -359,21 +360,21 @@
   }
 
   void writeToStringBuffer(StringBuffer buffer,
-      {CompilationUnit unit, String indent = ''}) {
+      {CompilationUnit? unit, String indent = ''}) {
     buffer
       ..write(indent)
       ..write('Abbreviation code: ')
       ..write(code)
       ..writeln('):');
-    for (final attribute in attributes.keys) {
+    attributes.forEach((attribute, value) {
       buffer
         ..write(indent)
         ..write('  ')
-        ..write(_attributeNameStrings[attribute.name])
+        ..write(_attributeNameStrings[attribute.name]!)
         ..write(' => ')
-        ..writeln(attribute.valueToString(attributes[attribute], unit));
-    }
-    if (children != null) {
+        ..writeln(attribute.valueToString(value, unit));
+    });
+    if (children.isNotEmpty) {
       buffer
         ..write(indent)
         ..write('Children (')
@@ -413,7 +414,7 @@
   CompilationUnitHeader._(this.size, this.version, this.abbreviationsOffset,
       this.addressSize, this.abbreviations);
 
-  static CompilationUnitHeader fromReader(
+  static CompilationUnitHeader? fromReader(
       Reader reader, Map<int, _AbbreviationsTable> abbreviationsTables) {
     final size = _initialLengthValue(reader);
     // An empty unit is an ending marker.
@@ -423,13 +424,14 @@
       throw FormatException("Expected DWARF version 2, got $version");
     }
     final abbreviationsOffset = reader.readBytes(4);
-    if (!abbreviationsTables.containsKey(abbreviationsOffset)) {
+    final abbreviationsTable = abbreviationsTables[abbreviationsOffset];
+    if (abbreviationsTable == null) {
       throw FormatException("No abbreviation table found for offset "
           "0x${paddedHex(abbreviationsOffset, 4)}");
     }
     final addressSize = reader.readByte();
-    return CompilationUnitHeader._(size, version, abbreviationsOffset,
-        addressSize, abbreviationsTables[abbreviationsOffset]);
+    return CompilationUnitHeader._(
+        size, version, abbreviationsOffset, addressSize, abbreviationsTable);
   }
 
   void writeToStringBuffer(StringBuffer buffer) {
@@ -461,7 +463,7 @@
 
   CompilationUnit._(this.header, this.referenceTable);
 
-  static CompilationUnit fromReader(
+  static CompilationUnit? fromReader(
       Reader reader, Map<int, _AbbreviationsTable> abbreviationsTables) {
     final header =
         CompilationUnitHeader.fromReader(reader, abbreviationsTables);
@@ -477,25 +479,21 @@
   static void _addChildEntries(Map<int, DebugInformationEntry> table) {
     final workList = Queue<MapEntry<int, DebugInformationEntry>>();
     for (final die in table.values) {
-      if (die.children != null) {
-        workList.addAll(die.children.entries);
-      }
+      workList.addAll(die.children.entries);
     }
     while (workList.isNotEmpty) {
       final kv = workList.removeFirst();
       final offset = kv.key;
       final child = kv.value;
       table[offset] = child;
-      if (child.children != null) {
-        workList.addAll(child.children.entries);
-      }
+      workList.addAll(child.children.entries);
     }
   }
 
-  Iterable<CallInfo> callInfo(LineNumberInfo lineNumberInfo, int address) {
+  Iterable<CallInfo>? callInfo(LineNumberInfo lineNumberInfo, int address) {
     for (final die in referenceTable.values) {
-      final lineNumberProgram =
-          lineNumberInfo[die[_AttributeName.statementList]];
+      final lineNumberProgram = lineNumberInfo[die.sectionOffset ?? -1];
+      if (lineNumberProgram == null) continue;
       final callInfo = die.callInfo(this, lineNumberProgram, address);
       if (callInfo != null) return callInfo;
     }
@@ -503,26 +501,24 @@
   }
 
   String nameOfOrigin(int offset) {
-    if (!referenceTable.containsKey(offset)) {
+    final origin = referenceTable[offset];
+    if (origin == null) {
       throw ArgumentError(
           "${paddedHex(offset)} is not the offset of an abbreviated unit");
     }
-    final origin = referenceTable[offset];
-    assert(origin.containsKey(_AttributeName.name));
     return origin[_AttributeName.name] as String;
   }
 
   void writeToStringBuffer(StringBuffer buffer) {
     header.writeToStringBuffer(buffer);
-    for (final offset in referenceTable.keys) {
-      final die = referenceTable[offset];
+    referenceTable.forEach((offset, die) {
       buffer
         ..write('Debug information entry at offset 0x')
         ..write(paddedHex(offset))
         ..writeln(':');
       die.writeToStringBuffer(buffer, unit: this);
       buffer.writeln();
-    }
+    });
   }
 
   @override
@@ -548,7 +544,7 @@
     return DebugInfo._(units);
   }
 
-  Iterable<CallInfo> callInfo(LineNumberInfo lineNumberInfo, int address) {
+  Iterable<CallInfo>? callInfo(LineNumberInfo lineNumberInfo, int address) {
     for (final unit in units) {
       final callInfo = unit.callInfo(lineNumberInfo, address);
       if (callInfo != null) return callInfo;
@@ -578,7 +574,7 @@
 
   FileEntry._(this.name, this.directoryIndex, this.lastModified, this.size);
 
-  static FileEntry fromReader(Reader reader) {
+  static FileEntry? fromReader(Reader reader) {
     final name = reader.readNullTerminatedString();
     // An empty null-terminated string marks the table end.
     if (name == "") return null;
@@ -611,7 +607,7 @@
   }
 
   bool containsKey(int index) => _files.containsKey(index);
-  FileEntry operator [](int index) => _files[index];
+  FileEntry? operator [](int index) => _files[index];
 
   void writeToStringBuffer(StringBuffer buffer) {
     if (_files.isEmpty) {
@@ -654,17 +650,17 @@
       ..writeln(nameHeader);
 
     for (final index in _files.keys) {
-      buffer..write(" ")..write(indexStrings[index].padRight(maxIndexLength));
+      buffer..write(" ")..write(indexStrings[index]!.padRight(maxIndexLength));
       buffer
         ..write(" ")
-        ..write(dirIndexStrings[index].padRight(maxDirIndexLength));
+        ..write(dirIndexStrings[index]!.padRight(maxDirIndexLength));
       buffer
         ..write(" ")
-        ..write(modifiedStrings[index].padRight(maxModifiedLength));
-      buffer..write(" ")..write(sizeStrings[index].padRight(maxSizeLength));
+        ..write(modifiedStrings[index]!.padRight(maxModifiedLength));
+      buffer..write(" ")..write(sizeStrings[index]!.padRight(maxSizeLength));
       buffer
         ..write(" ")
-        ..writeln(_files[index].name);
+        ..writeln(_files[index]!.name);
     }
   }
 
@@ -679,13 +675,13 @@
 class LineNumberState {
   final defaultIsStatement;
 
-  int address;
-  int fileIndex;
-  int line;
-  int column;
-  bool isStatement;
-  bool basicBlock;
-  bool endSequence;
+  late int address;
+  late int fileIndex;
+  late int line;
+  late int column;
+  late bool isStatement;
+  late bool basicBlock;
+  late bool endSequence;
 
   LineNumberState(this.defaultIsStatement) {
     reset();
@@ -749,7 +745,7 @@
       this.includeDirectories,
       this.filesInfo);
 
-  static LineNumberProgramHeader fromReader(Reader reader) {
+  static LineNumberProgramHeader? fromReader(Reader reader) {
     final size = _initialLengthValue(reader);
     if (size == 0) return null;
     final version = reader.readBytes(2);
@@ -861,7 +857,7 @@
 
   LineNumberProgram._(this.header, this.calculatedMatrix) : cachedLookups = {};
 
-  static LineNumberProgram fromReader(Reader reader) {
+  static LineNumberProgram? fromReader(Reader reader) {
     final header = LineNumberProgramHeader.fromReader(reader);
     if (header == null) return null;
     final calculatedMatrix = _readOpcodes(reader, header).toList();
@@ -955,14 +951,14 @@
         address < calculatedMatrix.last.address;
   }
 
-  LineNumberState operator [](int address) {
+  LineNumberState? operator [](int address) {
     if (cachedLookups.containsKey(address)) return cachedLookups[address];
 
     if (!containsKey(address)) return null;
 
     // Since the addresses are generated in increasing order, we can do a
     // binary search to find the right state.
-    assert(calculatedMatrix != null && calculatedMatrix.isNotEmpty);
+    assert(calculatedMatrix.isNotEmpty);
     var minIndex = 0;
     var maxIndex = calculatedMatrix.length - 1;
     while (true) {
@@ -983,12 +979,12 @@
     }
   }
 
-  String filename(int address) =>
-      header.filesInfo[this[address]?.fileIndex]?.name;
+  String? filename(int address) =>
+      header.filesInfo[this[address]?.fileIndex ?? -1]?.name;
 
-  int lineNumber(int address) => this[address]?.line;
+  int? lineNumber(int address) => this[address]?.line;
 
-  int column(int address) => this[address]?.column;
+  int? column(int address) => this[address]?.column;
 
   void writeToStringBuffer(StringBuffer buffer) {
     header.writeToStringBuffer(buffer);
@@ -1019,15 +1015,15 @@
   }
 
   bool containsKey(int address) => programs.containsKey(address);
-  LineNumberProgram operator [](int address) => programs[address];
+  LineNumberProgram? operator [](int address) => programs[address];
 
   void writeToStringBuffer(StringBuffer buffer) {
-    for (final offset in programs.keys) {
+    programs.forEach((offset, program) {
       buffer
         ..write('Line number program @ 0x')
         ..writeln(paddedHex(offset));
-      programs[offset].writeToStringBuffer(buffer);
-    }
+      program.writeToStringBuffer(buffer);
+    });
   }
 
   String toString() {
@@ -1068,10 +1064,10 @@
 
   DartCallInfo(
       {this.inlined = false,
-      this.function,
-      this.filename,
-      this.line,
-      this.column});
+      required this.function,
+      required this.filename,
+      required this.line,
+      required this.column});
 
   @override
   bool get isInternal => false;
@@ -1122,7 +1118,7 @@
   final String name;
   final int offset;
 
-  StubCallInfo({this.name, this.offset});
+  StubCallInfo({required this.name, required this.offset});
 
   @override
   int get hashCode => _hashFinish(
@@ -1156,9 +1152,11 @@
 
   /// The call information found for this [PCOffset] in [dwarf].
   ///
+  /// Returns null if the PCOffset is invalid for the given DWARF information.
+  ///
   /// If [includeInternalFrames] is false, then only information corresponding
   /// to user or library code is returned.
-  Iterable<CallInfo> callInfoFrom(Dwarf dwarf,
+  Iterable<CallInfo>? callInfoFrom(Dwarf dwarf,
           {bool includeInternalFrames = false}) =>
       dwarf.callInfoFor(dwarf.virtualAddressOf(this),
           includeInternalFrames: includeInternalFrames);
@@ -1180,7 +1178,7 @@
 /// The DWARF debugging information for a Dart snapshot.
 class Dwarf {
   final Elf _elf;
-  final Map<int, _AbbreviationsTable> _abbreviationTables;
+  final Map<int, _AbbreviationsTable> _abbreviationsTables;
   final DebugInfo _debugInfo;
   final LineNumberInfo _lineNumberInfo;
 
@@ -1192,13 +1190,13 @@
   /// DWARF information.
   final int isolateStartAddress;
 
-  Dwarf._(this._elf, this._abbreviationTables, this._debugInfo,
+  Dwarf._(this._elf, this._abbreviationsTables, this._debugInfo,
       this._lineNumberInfo, this.vmStartAddress, this.isolateStartAddress);
 
   /// Attempts to load the DWARF debugging information from the reader.
   ///
   /// Returns a [Dwarf] object if the load succeeds, otherwise returns null.
-  static Dwarf fromReader(Reader reader) {
+  static Dwarf? fromReader(Reader reader) {
     // Currently, the only DWARF-containing format we recognize is ELF.
     final elf = Elf.fromReader(reader);
     if (elf == null) return null;
@@ -1208,18 +1206,19 @@
   /// Attempts to load the DWARF debugging information from the given bytes.
   ///
   /// Returns a [Dwarf] object if the load succeeds, otherwise returns null.
-  static Dwarf fromBytes(Uint8List bytes) =>
+  static Dwarf? fromBytes(Uint8List bytes) =>
       Dwarf.fromReader(Reader.fromTypedData(bytes));
 
   /// Attempts to load the DWARF debugging information from the file at [path].
   ///
   /// Returns a [Dwarf] object if the load succeeds, otherwise returns null.
-  static Dwarf fromFile(String path) => Dwarf.fromReader(Reader.fromFile(path));
+  static Dwarf? fromFile(String path) =>
+      Dwarf.fromReader(Reader.fromFile(path));
 
   static Dwarf _loadSectionsFromElf(Reader reader, Elf elf) {
     final abbrevSection = elf.namedSections(".debug_abbrev").single;
     final abbrevReader = abbrevSection.refocusedCopy(reader);
-    final abbreviationTables = Map.fromEntries(
+    final abbreviationsTables = Map.fromEntries(
         abbrevReader.readRepeatedWithOffsets(_AbbreviationsTable.fromReader));
 
     final lineNumberSection = elf.namedSections(".debug_line").single;
@@ -1228,7 +1227,7 @@
 
     final infoSection = elf.namedSections(".debug_info").single;
     final debugInfo = DebugInfo.fromReader(
-        infoSection.refocusedCopy(reader), abbreviationTables);
+        infoSection.refocusedCopy(reader), abbreviationsTables);
 
     final vmStartSymbol = elf.dynamicSymbolFor(constants.vmSymbolName);
     if (vmStartSymbol == null) {
@@ -1245,29 +1244,33 @@
     }
     final isolateStartAddress = isolateStartSymbol.value;
 
-    return Dwarf._(elf, abbreviationTables, debugInfo, lineNumberInfo,
+    return Dwarf._(elf, abbreviationsTables, debugInfo, lineNumberInfo,
         vmStartAddress, isolateStartAddress);
   }
 
   /// The build ID for the debugging information.
   ///
   /// Returns null if there is no build ID information recorded.
-  String get buildId {
+  String? get buildId {
     final sections = _elf.namedSections(constants.buildIdSectionName);
     if (sections.isEmpty) return null;
-    final Note note = sections.single;
+    final note = sections.single as Note;
     if (note.type != constants.buildIdNoteType) return null;
     if (note.name != constants.buildIdNoteName) return null;
-    return note.description.map((i) => i.toRadixString(16)).join();
+    return note.description
+        .map((i) => i.toRadixString(16).padLeft(2, '0'))
+        .join();
   }
 
   /// The call information for the given virtual address. There may be
   /// multiple [CallInfo] objects returned for a single virtual address when
   /// code has been inlined.
   ///
+  /// Returns null if the given address is invalid for the DWARF information.
+  ///
   /// If [includeInternalFrames] is false, then only information corresponding
   /// to user or library code is returned.
-  Iterable<CallInfo> callInfoFor(int address,
+  Iterable<CallInfo>? callInfoFor(int address,
       {bool includeInternalFrames = false}) {
     var calls = _debugInfo.callInfo(_lineNumberInfo, address);
     if (calls == null) {
@@ -1304,10 +1307,10 @@
       ..writeln('         Abbreviation tables')
       ..writeln('----------------------------------------')
       ..writeln();
-    for (final offset in _abbreviationTables.keys) {
+    _abbreviationsTables.forEach((offset, table) {
       buffer..write('(Offset ')..write(paddedHex(offset, 4))..write(') ');
-      _abbreviationTables[offset].writeToStringBuffer(buffer);
-    }
+      table.writeToStringBuffer(buffer);
+    });
     buffer
       ..writeln('----------------------------------------')
       ..writeln('          Debug information')
diff --git a/pkg/native_stack_traces/lib/src/elf.dart b/pkg/native_stack_traces/lib/src/elf.dart
index b0c7c54..e92fecd 100644
--- a/pkg/native_stack_traces/lib/src/elf.dart
+++ b/pkg/native_stack_traces/lib/src/elf.dart
@@ -95,7 +95,7 @@
       this.sectionHeaderEntrySize,
       this.sectionHeaderStringsIndex);
 
-  static ElfHeader fromReader(Reader reader) {
+  static ElfHeader? fromReader(Reader reader) {
     final fileSize = reader.length;
 
     for (final sigByte in _ELFMAG.codeUnits) {
@@ -275,10 +275,11 @@
       this.paddr, this.filesz, this.memsz, this.align, this.wordSize);
 
   static ProgramHeaderEntry fromReader(Reader reader) {
-    assert(reader.wordSize == 4 || reader.wordSize == 8);
+    int wordSize = reader.wordSize;
+    assert(wordSize == 4 || wordSize == 8);
     final type = _readElfWord(reader);
-    int flags;
-    if (reader.wordSize == 8) {
+    late int flags;
+    if (wordSize == 8) {
       flags = _readElfWord(reader);
     }
     final offset = _readElfOffset(reader);
@@ -286,12 +287,12 @@
     final paddr = _readElfAddress(reader);
     final filesz = _readElfNative(reader);
     final memsz = _readElfNative(reader);
-    if (reader.wordSize == 4) {
+    if (wordSize == 4) {
       flags = _readElfWord(reader);
     }
     final align = _readElfNative(reader);
-    return ProgramHeaderEntry._(type, flags, offset, vaddr, paddr, filesz,
-        memsz, align, reader.wordSize);
+    return ProgramHeaderEntry._(
+        type, flags, offset, vaddr, paddr, filesz, memsz, align, wordSize);
   }
 
   static const _typeStrings = <int, String>{
@@ -301,12 +302,8 @@
     _PT_PHDR: "PT_PHDR",
   };
 
-  static String _typeToString(int type) {
-    if (_typeStrings.containsKey(type)) {
-      return _typeStrings[type];
-    }
-    return "unknown (${paddedHex(type, 4)})";
-  }
+  static String _typeToString(int type) =>
+      _typeStrings[type] ?? "unknown (${paddedHex(type, 4)})";
 
   void writeToStringBuffer(StringBuffer buffer) {
     buffer
@@ -384,7 +381,7 @@
   final int addrAlign;
   final int entrySize;
   final int wordSize;
-  String _cachedName;
+  late String name;
 
   SectionHeaderEntry._(
       this.nameIndex,
@@ -426,11 +423,9 @@
   static const _SHT_DYNSYM = 11;
 
   void setName(StringTable nameTable) {
-    _cachedName = nameTable[nameIndex];
+    name = nameTable[nameIndex]!;
   }
 
-  String get name => _cachedName != null ? _cachedName : '<${nameIndex}>';
-
   static const _typeStrings = <int, String>{
     _SHT_NULL: "SHT_NULL",
     _SHT_PROGBITS: "SHT_PROGBITS",
@@ -443,25 +438,17 @@
     _SHT_DYNSYM: "SHT_DYNSYM",
   };
 
-  static String _typeToString(int type) {
-    if (_typeStrings.containsKey(type)) {
-      return _typeStrings[type];
-    }
-    return "unknown (${paddedHex(type, 4)})";
-  }
+  static String _typeToString(int type) =>
+      _typeStrings[type] ?? "unknown (${paddedHex(type, 4)})";
 
   void writeToStringBuffer(StringBuffer buffer) {
     buffer.write('Name: ');
-    if (_cachedName != null) {
-      buffer
-        ..write('"')
-        ..write(name)
-        ..write('" (@ ')
-        ..write(nameIndex)
-        ..writeln(')');
-    } else {
-      buffer.writeln(name);
-    }
+    buffer
+      ..write('"')
+      ..write(name)
+      ..write('" (@ ')
+      ..write(nameIndex)
+      ..writeln(')');
     buffer
       ..write('Type: ')
       ..writeln(_typeToString(type))
@@ -629,7 +616,7 @@
 
 /// A map from table offsets to strings, used to store names of ELF objects.
 class StringTable extends Section {
-  final _entries;
+  final Map<int, String> _entries;
 
   StringTable._(entry, this._entries) : super._(entry);
 
@@ -640,7 +627,7 @@
     return StringTable._(entry, entries);
   }
 
-  String operator [](int index) => _entries[index];
+  String? operator [](int index) => _entries[index];
   bool containsKey(int index) => _entries.containsKey(index);
 
   @override
@@ -685,40 +672,40 @@
   final int sectionIndex;
   final int value;
   final int size;
-
   final int _wordSize;
-
-  String name;
+  late String name;
 
   Symbol._(this.nameIndex, this.info, this.other, this.sectionIndex, this.value,
       this.size, this._wordSize);
 
   static Symbol fromReader(Reader reader) {
+    final wordSize = reader.wordSize;
     final nameIndex = _readElfWord(reader);
-    int info;
-    int other;
-    int sectionIndex;
-    if (reader.wordSize == 8) {
+    late int info;
+    late int other;
+    late int sectionIndex;
+    if (wordSize == 8) {
       info = reader.readByte();
       other = reader.readByte();
       sectionIndex = _readElfSection(reader);
     }
     final value = _readElfAddress(reader);
     final size = _readElfNative(reader);
-    if (reader.wordSize == 4) {
+    if (wordSize == 4) {
       info = reader.readByte();
       other = reader.readByte();
       sectionIndex = _readElfSection(reader);
     }
     return Symbol._(
-        nameIndex, info, other, sectionIndex, value, size, reader.wordSize);
+        nameIndex, info, other, sectionIndex, value, size, wordSize);
   }
 
   void _cacheNameFromStringTable(StringTable table) {
-    if (!table.containsKey(nameIndex)) {
+    final nameFromTable = table[nameIndex];
+    if (nameFromTable == null) {
       throw FormatException("Index $nameIndex not found in string table");
     }
-    name = table[nameIndex];
+    name = nameFromTable;
   }
 
   SymbolBinding get bind => SymbolBinding.values[info >> 4];
@@ -726,11 +713,7 @@
   SymbolVisibility get visibility => SymbolVisibility.values[other & 0x03];
 
   void writeToStringBuffer(StringBuffer buffer) {
-    if (name != null) {
-      buffer..write('"')..write(name)..write('" =>');
-    } else {
-      buffer..write('<')..write(nameIndex)..write('> =>');
-    }
+    buffer..write('"')..write(name)..write('" =>');
     switch (bind) {
       case SymbolBinding.STB_GLOBAL:
         buffer..write(' a global');
@@ -793,8 +776,8 @@
   }
 
   Iterable<String> get keys => _nameCache.keys;
-  Iterable<Symbol> get values => _nameCache.values;
-  Symbol operator [](String name) => _nameCache[name];
+  Iterable<Symbol> get values => _entries;
+  Symbol? operator [](String name) => _nameCache[name];
   bool containsKey(String name) => _nameCache.containsKey(name);
 
   @override
@@ -825,21 +808,23 @@
   /// Creates an [Elf] from [bytes].
   ///
   /// Returns null if the file does not start with the ELF magic number.
-  static Elf fromBuffer(Uint8List bytes) =>
+  static Elf? fromBuffer(Uint8List bytes) =>
       Elf.fromReader(Reader.fromTypedData(bytes));
 
   /// Creates an [Elf] from the file at [path].
   ///
   /// Returns null if the file does not start with the ELF magic number.
-  static Elf fromFile(String path) => Elf.fromReader(Reader.fromFile(path));
+  static Elf? fromFile(String path) => Elf.fromReader(Reader.fromFile(path));
 
-  Iterable<Section> namedSections(String name) => _sectionsByName[name];
+  Iterable<Section> namedSections(String name) =>
+      _sectionsByName[name] ?? <Section>[];
 
   /// Lookup of a dynamic symbol by name.
   ///
   /// Returns -1 if there is no dynamic symbol that matches [name].
-  Symbol dynamicSymbolFor(String name) {
-    for (final SymbolTable dynsym in namedSections(".dynsym")) {
+  Symbol? dynamicSymbolFor(String name) {
+    for (final section in namedSections(".dynsym")) {
+      final dynsym = section as SymbolTable;
       if (dynsym.containsKey(name)) return dynsym[name];
     }
     return null;
@@ -847,8 +832,9 @@
 
   /// Reverse lookup of the static symbol that contains the given virtual
   /// address. Returns null if no static symbol matching the address is found.
-  Symbol staticSymbolAt(int address) {
-    for (final SymbolTable table in namedSections('.symtab')) {
+  Symbol? staticSymbolAt(int address) {
+    for (final section in namedSections('.symtab')) {
+      final table = section as SymbolTable;
       for (final symbol in table.values) {
         final start = symbol.value;
         final end = start + symbol.size;
@@ -865,7 +851,7 @@
   /// of the reader will be unchanged.
   ///
   /// Returns null if the file does not start with the ELF magic number.
-  static Elf fromReader(Reader elfReader) {
+  static Elf? fromReader(Reader elfReader) {
     // ELF files contain absolute offsets from the start of the file, so
     // make sure we have a reader that a) makes no assumptions about the
     // endianness or word size, since we'll read those in the header and b)
@@ -887,24 +873,47 @@
     }
     // Now set up the by-name section table and cache the names in the section
     // header entries.
-    final StringTable sectionHeaderStringTable =
-        sections[sectionHeader.entries[header.sectionHeaderStringsIndex]];
+    if (header.sectionHeaderStringsIndex < 0 ||
+        header.sectionHeaderStringsIndex >= sectionHeader.entries.length) {
+      throw FormatException("Section header string table index invalid");
+    }
+    final sectionHeaderStringTableEntry =
+        sectionHeader.entries[header.sectionHeaderStringsIndex];
+    final sectionHeaderStringTable =
+        sections[sectionHeaderStringTableEntry] as StringTable?;
+    if (sectionHeaderStringTable == null) {
+      throw FormatException(
+          "No section for entry ${sectionHeaderStringTableEntry}");
+    }
     final sectionsByName = <String, Set<Section>>{};
     for (final entry in sectionHeader.entries) {
+      final section = sections[entry];
+      if (section == null) {
+        throw FormatException("No section found for entry ${entry}");
+      }
       entry.setName(sectionHeaderStringTable);
-      sectionsByName.putIfAbsent(entry.name, () => {}).add(sections[entry]);
+      sectionsByName.putIfAbsent(entry.name, () => {}).add(section);
     }
     void _cacheSymbolNames(String stringTableTag, String symbolTableTag) {
-      final stringTables = Map.fromEntries(sectionsByName[stringTableTag]
-          .map((s) => MapEntry(s.headerEntry, s)));
-      for (final SymbolTable symbolTable in sectionsByName[symbolTableTag]) {
+      final stringTables = sectionsByName[stringTableTag]?.cast<StringTable>();
+      if (stringTables == null) {
+        return;
+      }
+      final stringTableMap =
+          Map.fromEntries(stringTables.map((s) => MapEntry(s.headerEntry, s)));
+      final symbolTables = sectionsByName[symbolTableTag]?.cast<SymbolTable>();
+      if (symbolTables == null) {
+        return;
+      }
+      for (final symbolTable in symbolTables) {
         final link = symbolTable.headerEntry.link;
         final entry = sectionHeader.entries[link];
-        if (!stringTables.containsKey(entry)) {
+        final stringTable = stringTableMap[entry];
+        if (stringTable == null) {
           throw FormatException(
               "String table not found at section header entry ${link}");
         }
-        symbolTable._cacheNames(stringTables[entry]);
+        symbolTable._cacheNames(stringTable);
       }
     }
 
@@ -948,7 +957,7 @@
       ..writeln('-----------------------------------------------------')
       ..writeln();
     for (final entry in _sectionHeader.entries) {
-      _sections[entry].writeToStringBuffer(buffer);
+      _sections[entry]!.writeToStringBuffer(buffer);
       buffer.writeln();
     }
   }
diff --git a/pkg/native_stack_traces/lib/src/reader.dart b/pkg/native_stack_traces/lib/src/reader.dart
index 21f6297..9eb5be6 100644
--- a/pkg/native_stack_traces/lib/src/reader.dart
+++ b/pkg/native_stack_traces/lib/src/reader.dart
@@ -14,26 +14,35 @@
   final ByteData bdata;
   // These are mutable so we can update them, in case the endianness and
   // wordSize are read using the reader (e.g., ELF files).
-  Endian endian;
-  int wordSize;
+  Endian? _endian;
+  int? _wordSize;
 
   int _offset = 0;
 
+  Endian get endian => _endian as Endian;
+  void set endian(Endian value) => _endian = value;
+  int get wordSize => _wordSize as int;
+  void set wordSize(int value) => _wordSize = value;
+
   /// Unless provided, [wordSize] and [endian] are initialized to values that
   /// ensure no reads are made that depend on their value (e.g., readBytes).
-  Reader.fromTypedData(TypedData data, {this.wordSize = -1, this.endian})
-      : bdata =
+  Reader.fromTypedData(TypedData data, {int? wordSize, Endian? endian})
+      : _wordSize = wordSize,
+        _endian = endian,
+        bdata =
             ByteData.view(data.buffer, data.offsetInBytes, data.lengthInBytes);
 
-  Reader.fromFile(String path, {this.wordSize, this.endian})
-      : bdata = ByteData.sublistView(File(path).readAsBytesSync());
+  Reader.fromFile(String path, {int? wordSize, Endian? endian})
+      : _wordSize = wordSize,
+        _endian = endian,
+        bdata = ByteData.sublistView(File(path).readAsBytesSync());
 
   /// Returns a reader focused on a different portion of the underlying buffer.
   Reader refocusedCopy(int pos, int size) {
     assert(pos >= 0 && pos < bdata.buffer.lengthInBytes);
     assert(size >= 0 && (pos + size) <= bdata.buffer.lengthInBytes);
     return Reader.fromTypedData(ByteData.view(bdata.buffer, pos, size),
-        wordSize: wordSize, endian: endian);
+        wordSize: _wordSize, endian: _endian);
   }
 
   int get start => bdata.offsetInBytes;
@@ -65,7 +74,6 @@
         return signed
             ? bdata.getInt32(start, endian)
             : bdata.getUint32(start, endian);
-        break;
       case 8:
         return signed
             ? bdata.getInt64(start, endian)
@@ -116,7 +124,7 @@
   /// Stops either when the reader is empty or when a null item is returned
   /// from the callback.
   Iterable<MapEntry<int, S>> readRepeatedWithOffsets<S>(
-      S Function(Reader) callback,
+      S? Function(Reader) callback,
       {bool absolute = false}) sync* {
     final start = offset;
     while (!done) {
@@ -127,7 +135,7 @@
     }
   }
 
-  Iterable<S> readRepeated<S>(S Function(Reader) callback) =>
+  Iterable<S> readRepeated<S>(S? Function(Reader) callback) =>
       readRepeatedWithOffsets(callback).map((kv) => kv.value);
 
   void writeCurrentReaderPosition(StringBuffer buffer,
@@ -160,27 +168,27 @@
     final buffer = StringBuffer();
     buffer
       ..write("Word size: ")
-      ..write(wordSize)
+      ..write(_wordSize)
       ..writeln();
     buffer
       ..write("Endianness: ")
-      ..write(endian)
+      ..write(_endian)
       ..writeln();
     buffer
       ..write("Start:  0x")
-      ..write(paddedHex(start, wordSize ?? 0))
+      ..write(paddedHex(start, _wordSize ?? 0))
       ..write(" (")
       ..write(start)
       ..writeln(")");
     buffer
       ..write("Offset: 0x")
-      ..write(paddedHex(offset, wordSize ?? 0))
+      ..write(paddedHex(offset, _wordSize ?? 0))
       ..write(" (")
       ..write(offset)
       ..writeln(")");
     buffer
       ..write("Length: 0x")
-      ..write(paddedHex(length, wordSize ?? 0))
+      ..write(paddedHex(length, _wordSize ?? 0))
       ..write(" (")
       ..write(length)
       ..writeln(")");
diff --git a/pkg/native_stack_traces/pubspec.yaml b/pkg/native_stack_traces/pubspec.yaml
index cc0d214..f831df6 100644
--- a/pkg/native_stack_traces/pubspec.yaml
+++ b/pkg/native_stack_traces/pubspec.yaml
@@ -1,18 +1,19 @@
 name: native_stack_traces
 description: Utilities for working with non-symbolic stack traces.
-version: 0.3.8
+version: 0.4.0-nullsafety
 
 homepage: https://github.com/dart-lang/sdk/tree/master/pkg/native_stack_traces
 
 environment:
-  sdk: '>=2.8.0 <3.0.0'
+  # This must remain a tight constraint until nnbd is stable
+  sdk: '>=2.10.0-0 <2.10.0'
 
 executables:
   decode:
 
 dependencies:
-  args: ^1.5.2
-  path: ^1.6.4
+  args: ^1.6.0
+  path: ^1.8.0-nullsafety
 
 dev_dependencies:
-  pedantic: ^1.8.0
+  pedantic: ^1.9.2
diff --git a/pkg/nnbd_migration/lib/src/decorated_type_operations.dart b/pkg/nnbd_migration/lib/src/decorated_type_operations.dart
index 13e52db..4c776c8 100644
--- a/pkg/nnbd_migration/lib/src/decorated_type_operations.dart
+++ b/pkg/nnbd_migration/lib/src/decorated_type_operations.dart
@@ -59,13 +59,6 @@
   }
 
   @override
-  bool isLocalVariableWithoutDeclaredType(PromotableElement variable) {
-    return variable is LocalVariableElement &&
-        variable.hasImplicitType &&
-        !variable.hasInitializer;
-  }
-
-  @override
   bool isNever(DecoratedType type) {
     return false;
   }
diff --git a/pkg/vm/lib/target/vm.dart b/pkg/vm/lib/target/vm.dart
index 4920fce..8c74da4 100644
--- a/pkg/vm/lib/target/vm.dart
+++ b/pkg/vm/lib/target/vm.dart
@@ -54,6 +54,10 @@
   bool get supportsLateFields => !flags.forceLateLoweringForTesting;
 
   @override
+  bool get supportsLateLoweringSentinel =>
+      flags.forceLateLoweringSentinelForTesting;
+
+  @override
   bool get useStaticFieldLowering => flags.forceStaticFieldLoweringForTesting;
 
   @override
diff --git a/pkg/vm_service/CHANGELOG.md b/pkg/vm_service/CHANGELOG.md
index 0d06590..b049853 100644
--- a/pkg/vm_service/CHANGELOG.md
+++ b/pkg/vm_service/CHANGELOG.md
@@ -1,5 +1,10 @@
 # Changelog
 
+## 5.2.0
+- Added support for `dart:io` extensions version 1.3.
+- Added combination getter/setter `httpEnableTimelineLogging`.
+- Deprecated `getHttpEnableTimelineLogging` and `setHttpEnableTimelineLogging`.
+
 ## 5.1.0
 - Added support for `dart:io` extensions version 1.2.
 - Added `getOpenFiles`, `getOpenFileById`, `getSpawnedProcesses`, and `getSpawnedProcessById` RPCs.
diff --git a/pkg/vm_service/lib/src/dart_io_extensions.dart b/pkg/vm_service/lib/src/dart_io_extensions.dart
index ddecfc5..ce777d6 100644
--- a/pkg/vm_service/lib/src/dart_io_extensions.dart
+++ b/pkg/vm_service/lib/src/dart_io_extensions.dart
@@ -43,6 +43,7 @@
   ///
   /// Warning: The returned [Future] will not complete if the target isolate is paused
   /// and will only complete when the isolate is resumed.
+  @Deprecated('Use httpEnableTimelineLogging instead.')
   Future<HttpTimelineLoggingState> getHttpEnableTimelineLogging(
           String isolateId) =>
       _callHelper('ext.dart.io.getHttpEnableTimelineLogging', isolateId);
@@ -51,11 +52,18 @@
   ///
   /// Warning: The returned [Future] will not complete if the target isolate is paused
   /// and will only complete when the isolate is resumed.
+  @Deprecated('Use httpEnableTimelineLogging instead.')
   Future<Success> setHttpEnableTimelineLogging(String isolateId, bool enable) =>
       _callHelper('ext.dart.io.setHttpEnableTimelineLogging', isolateId, args: {
         'enable': enable,
       });
 
+  Future<HttpTimelineLoggingState> httpEnableTimelineLogging(String isolateId,
+          [bool enable]) =>
+      _callHelper('ext.dart.io.httpEnableTimelineLogging', isolateId, args: {
+        if (enable != null) 'enable': enable,
+      });
+
   /// The `getOpenFiles` RPC is used to retrieve the list of files currently
   /// opened files by `dart:io` from a given isolate.
   Future<OpenFileList> getOpenFiles(String isolateId) => _callHelper(
diff --git a/pkg/vm_service/pubspec.yaml b/pkg/vm_service/pubspec.yaml
index dd8502a..c2280d1 100644
--- a/pkg/vm_service/pubspec.yaml
+++ b/pkg/vm_service/pubspec.yaml
@@ -2,7 +2,7 @@
 description: >-
   A library to communicate with a service implementing the Dart VM
   service protocol.
-version: 5.1.0+1
+version: 5.2.0
 
 homepage: https://github.com/dart-lang/sdk/tree/master/pkg/vm_service
 
diff --git a/pkg/vm_service/test/http_enable_timeline_logging_service_test.dart b/pkg/vm_service/test/http_enable_timeline_logging_service_test.dart
index 0b849c6..b236cc4 100644
--- a/pkg/vm_service/test/http_enable_timeline_logging_service_test.dart
+++ b/pkg/vm_service/test/http_enable_timeline_logging_service_test.dart
@@ -2,6 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'dart:async';
+
 import 'package:vm_service/vm_service.dart';
 import 'package:vm_service/src/dart_io_extensions.dart';
 import 'package:test/test.dart';
@@ -12,8 +14,34 @@
     'ext.dart.io.setHttpEnableTimelineLogging';
 const String kGetHttpEnableTimelineLogging =
     'ext.dart.io.getHttpEnableTimelineLogging';
+const String kHttpEnableTimelineLogging =
+    'ext.dart.io.httpEnableTimelineLogging';
 Future<void> setup() async {}
 
+Future<void> waitForStreamEvent(
+    VmService service, IsolateRef isolateRef, bool state,
+    {bool useSetter = true}) async {
+  final completer = Completer<void>();
+  final isolateId = isolateRef.id;
+  StreamSubscription sub;
+  sub = service.onExtensionEvent.listen((event) {
+    expect(event.extensionKind, 'HttpTimelineLoggingStateChange');
+    expect(event.extensionData.data['isolateId'], isolateRef.id);
+    expect(event.extensionData.data['enabled'], state);
+    sub.cancel();
+    completer.complete();
+  });
+  await service.streamListen(EventStreams.kExtension);
+
+  if (useSetter) {
+    await service.setHttpEnableTimelineLogging(isolateId, state);
+  } else {
+    await service.httpEnableTimelineLogging(isolateId, state);
+  }
+  await completer.future;
+  await service.streamCancel(EventStreams.kExtension);
+}
+
 var tests = <IsolateTest>[
   (VmService service, IsolateRef isolateRef) async {
     final isolate = await service.getIsolate(isolateRef.id);
@@ -23,22 +51,34 @@
         isolate.extensionRPCs.contains(kGetHttpEnableTimelineLogging), isTrue);
     expect(
         isolate.extensionRPCs.contains(kSetHttpEnableTimelineLogging), isTrue);
+    expect(isolate.extensionRPCs.contains(kHttpEnableTimelineLogging), isTrue);
   },
   (VmService service, IsolateRef isolateRef) async {
     final isolateId = isolateRef.id;
     dynamic response = await service.getHttpEnableTimelineLogging(isolateId);
     expect(response.enabled, false);
 
-    await service.setHttpEnableTimelineLogging(isolateId, true);
-
+    await waitForStreamEvent(service, isolateRef, true);
     response = await service.getHttpEnableTimelineLogging(isolateId);
     expect(response.enabled, true);
 
-    await service.setHttpEnableTimelineLogging(isolateId, false);
-
+    await waitForStreamEvent(service, isolateRef, false);
     response = await service.getHttpEnableTimelineLogging(isolateId);
     expect(response.enabled, false);
   },
+  (VmService service, IsolateRef isolateRef) async {
+    final isolateId = isolateRef.id;
+    dynamic response = await service.httpEnableTimelineLogging(isolateId, null);
+    expect(response.enabled, false);
+
+    await waitForStreamEvent(service, isolateRef, true, useSetter: false);
+    response = await service.httpEnableTimelineLogging(isolateId, null);
+    expect(response.enabled, true);
+
+    await waitForStreamEvent(service, isolateRef, false, useSetter: false);
+    response = await service.httpEnableTimelineLogging(isolateId);
+    expect(response.enabled, false);
+  },
 ];
 
 main([args = const <String>[]]) async =>
diff --git a/runtime/bin/elf_loader.cc b/runtime/bin/elf_loader.cc
index c67f391..22c2cbc 100644
--- a/runtime/bin/elf_loader.cc
+++ b/runtime/bin/elf_loader.cc
@@ -476,7 +476,6 @@
                   ".bss does not have enough space.");
       vm_bss_ = reinterpret_cast<uword*>(base_->start() + header.memory_offset);
       isolate_bss_ = vm_bss_ + BSS::kVmEntryCount;
-      // We set applicable BSS entries in ResolveSymbols().
     }
   }
 
@@ -504,22 +503,10 @@
       output = vm_data;
     } else if (strcmp(name, kVmSnapshotInstructionsAsmSymbol) == 0) {
       output = vm_instrs;
-      if (output != nullptr) {
-        // Store the value of the symbol in the VM BSS, as it contains the
-        // address of the VM instructions section relative to the DSO base.
-        BSS::InitializeBSSEntry(BSS::Relocation::InstructionsRelocatedAddress,
-                                sym.value, vm_bss_);
-      }
     } else if (strcmp(name, kIsolateSnapshotDataAsmSymbol) == 0) {
       output = isolate_data;
     } else if (strcmp(name, kIsolateSnapshotInstructionsAsmSymbol) == 0) {
       output = isolate_instrs;
-      if (output != nullptr) {
-        // Store the value of the symbol in the isolate BSS, as it contains the
-        // address of the isolate instructions section relative to the DSO base.
-        BSS::InitializeBSSEntry(BSS::Relocation::InstructionsRelocatedAddress,
-                                sym.value, isolate_bss_);
-      }
     }
 
     if (output != nullptr) {
diff --git a/runtime/tests/vm/dart/causal_stacks/utils.dart b/runtime/tests/vm/dart/causal_stacks/utils.dart
index 4a56ae7..0b14b5c 100644
--- a/runtime/tests/vm/dart/causal_stacks/utils.dart
+++ b/runtime/tests/vm/dart/causal_stacks/utils.dart
@@ -187,7 +187,7 @@
   final decodeTrace = frames.first.startsWith('Warning:');
   if (decodeTrace) {
     Expect.isNotNull(debugInfoFilename);
-    final dwarf = Dwarf.fromFile(debugInfoFilename!);
+    final dwarf = Dwarf.fromFile(debugInfoFilename!)!;
     frames = await Stream.fromIterable(original)
         .transform(DwarfStackTraceDecoder(dwarf))
         .where(_lineRE.hasMatch)
diff --git a/runtime/tests/vm/dart/use_dwarf_stack_traces_flag_test.dart b/runtime/tests/vm/dart/use_dwarf_stack_traces_flag_test.dart
index 07a40c0..5d9fe49 100644
--- a/runtime/tests/vm/dart/use_dwarf_stack_traces_flag_test.dart
+++ b/runtime/tests/vm/dart/use_dwarf_stack_traces_flag_test.dart
@@ -112,8 +112,16 @@
 
     // Check that translating the DWARF stack trace (without internal frames)
     // matches the symbolic stack trace.
-    final dwarf = Dwarf.fromFile(scriptDwarfDebugInfo);
-    assert(dwarf != null);
+    final dwarf = Dwarf.fromFile(scriptDwarfDebugInfo)!;
+
+    // Check that build IDs match for traces.
+    final buildId1 = buildId(dwarfTrace1);
+    Expect.isFalse(buildId1.isEmpty);
+    Expect.equals(dwarf.buildId!, buildId1);
+    final buildId2 = buildId(dwarfTrace2);
+    Expect.isFalse(buildId2.isEmpty);
+    Expect.equals(dwarf.buildId!, buildId2);
+
     final translatedDwarfTrace1 = await Stream.fromIterable(dwarfTrace1)
         .transform(DwarfStackTraceDecoder(dwarf))
         .toList();
@@ -178,6 +186,17 @@
   });
 }
 
+final _buildIdRE = RegExp(r"build_id: '([a-f\d]+)'");
+String buildId(Iterable<String> lines) {
+  for (final line in lines) {
+    final match = _buildIdRE.firstMatch(line);
+    if (match != null) {
+      return match.group(1)!;
+    }
+  }
+  return '';
+}
+
 final _symbolicFrameRE = RegExp(r'^#\d+\s+');
 
 Iterable<String> onlySymbolicFrameLines(Iterable<String> lines) {
diff --git a/runtime/tests/vm/dart/use_save_debugging_info_flag_test.dart b/runtime/tests/vm/dart/use_save_debugging_info_flag_test.dart
index 5ed1c3a..cfc8f16 100644
--- a/runtime/tests/vm/dart/use_save_debugging_info_flag_test.dart
+++ b/runtime/tests/vm/dart/use_save_debugging_info_flag_test.dart
@@ -114,8 +114,8 @@
     print("Original stack trace:");
     strippedTrace.forEach(print);
 
-    final debugDwarf = Dwarf.fromFile(scriptDebuggingInfo);
-    final wholeDwarf = Dwarf.fromFile(scriptWholeSnapshot);
+    final debugDwarf = Dwarf.fromFile(scriptDebuggingInfo)!;
+    final wholeDwarf = Dwarf.fromFile(scriptWholeSnapshot)!;
 
     final fromDebug = await Stream.fromIterable(strippedTrace)
         .transform(DwarfStackTraceDecoder(debugDwarf))
diff --git a/runtime/tests/vm/dart_2/use_dwarf_stack_traces_flag_test.dart b/runtime/tests/vm/dart_2/use_dwarf_stack_traces_flag_test.dart
index 40aa94a..7f3557e 100644
--- a/runtime/tests/vm/dart_2/use_dwarf_stack_traces_flag_test.dart
+++ b/runtime/tests/vm/dart_2/use_dwarf_stack_traces_flag_test.dart
@@ -113,7 +113,17 @@
     // Check that translating the DWARF stack trace (without internal frames)
     // matches the symbolic stack trace.
     final dwarf = Dwarf.fromFile(scriptDwarfDebugInfo);
-    assert(dwarf != null);
+    Expect.isNotNull(dwarf);
+
+    // Check that build IDs match for traces.
+    Expect.isNotNull(dwarf.buildId);
+    final buildId1 = buildId(dwarfTrace1);
+    Expect.isFalse(buildId1.isEmpty);
+    Expect.equals(dwarf.buildId, buildId1);
+    final buildId2 = buildId(dwarfTrace2);
+    Expect.isFalse(buildId2.isEmpty);
+    Expect.equals(dwarf.buildId, buildId2);
+
     final translatedDwarfTrace1 = await Stream.fromIterable(dwarfTrace1)
         .transform(DwarfStackTraceDecoder(dwarf))
         .toList();
@@ -178,6 +188,17 @@
   });
 }
 
+final _buildIdRE = RegExp(r"build_id: '([a-f\d]+)'");
+String buildId(Iterable<String> lines) {
+  for (final line in lines) {
+    final match = _buildIdRE.firstMatch(line);
+    if (match != null) {
+      return match.group(1);
+    }
+  }
+  return '';
+}
+
 final _symbolicFrameRE = RegExp(r'^#\d+\s+');
 
 Iterable<String> onlySymbolicFrameLines(Iterable<String> lines) {
diff --git a/runtime/vm/benchmark_test.cc b/runtime/vm/benchmark_test.cc
index 1d00e78..2215c7d 100644
--- a/runtime/vm/benchmark_test.cc
+++ b/runtime/vm/benchmark_test.cc
@@ -17,6 +17,7 @@
 
 #include "vm/clustered_snapshot.h"
 #include "vm/dart_api_impl.h"
+#include "vm/datastream.h"
 #include "vm/stack_frame.h"
 #include "vm/timer.h"
 
@@ -500,12 +501,6 @@
   benchmark->set_score(elapsed_time);
 }
 
-static uint8_t* malloc_allocator(uint8_t* ptr,
-                                 intptr_t old_size,
-                                 intptr_t new_size) {
-  return reinterpret_cast<uint8_t*>(realloc(ptr, new_size));
-}
-
 BENCHMARK_SIZE(CoreSnapshotSize) {
   const char* kScriptChars =
       "import 'dart:async';\n"
@@ -519,8 +514,6 @@
       "\n";
 
   // Start an Isolate, load a script and create a full snapshot.
-  uint8_t* vm_snapshot_data_buffer;
-  uint8_t* isolate_snapshot_data_buffer;
   // Need to load the script into the dart: core library due to
   // the import of dart:_internal.
   TestCase::LoadCoreTestScript(kScriptChars, NULL);
@@ -532,17 +525,16 @@
   Api::CheckAndFinalizePendingClasses(thread);
 
   // Write snapshot with object content.
-  FullSnapshotWriter writer(Snapshot::kFull, &vm_snapshot_data_buffer,
-                            &isolate_snapshot_data_buffer, &malloc_allocator,
-                            NULL, NULL /* image_writer */);
+  MallocWriteStream vm_snapshot_data(FullSnapshotWriter::kInitialSize);
+  MallocWriteStream isolate_snapshot_data(FullSnapshotWriter::kInitialSize);
+  FullSnapshotWriter writer(
+      Snapshot::kFull, &vm_snapshot_data, &isolate_snapshot_data,
+      /*vm_image_writer=*/nullptr, /*iso_image_writer=*/nullptr);
   writer.WriteFullSnapshot();
   const Snapshot* snapshot =
-      Snapshot::SetupFromBuffer(isolate_snapshot_data_buffer);
+      Snapshot::SetupFromBuffer(isolate_snapshot_data.buffer());
   ASSERT(snapshot->kind() == Snapshot::kFull);
   benchmark->set_score(snapshot->length());
-
-  free(vm_snapshot_data_buffer);
-  free(isolate_snapshot_data_buffer);
 }
 
 BENCHMARK_SIZE(StandaloneSnapshotSize) {
@@ -560,8 +552,6 @@
       "\n";
 
   // Start an Isolate, load a script and create a full snapshot.
-  uint8_t* vm_snapshot_data_buffer;
-  uint8_t* isolate_snapshot_data_buffer;
   // Need to load the script into the dart: core library due to
   // the import of dart:_internal.
   TestCase::LoadCoreTestScript(kScriptChars, NULL);
@@ -573,17 +563,16 @@
   Api::CheckAndFinalizePendingClasses(thread);
 
   // Write snapshot with object content.
-  FullSnapshotWriter writer(Snapshot::kFull, &vm_snapshot_data_buffer,
-                            &isolate_snapshot_data_buffer, &malloc_allocator,
-                            NULL, NULL /* image_writer */);
+  MallocWriteStream vm_snapshot_data(FullSnapshotWriter::kInitialSize);
+  MallocWriteStream isolate_snapshot_data(FullSnapshotWriter::kInitialSize);
+  FullSnapshotWriter writer(
+      Snapshot::kFull, &vm_snapshot_data, &isolate_snapshot_data,
+      /*vm_image_writer=*/nullptr, /*iso_image_writer=*/nullptr);
   writer.WriteFullSnapshot();
   const Snapshot* snapshot =
-      Snapshot::SetupFromBuffer(isolate_snapshot_data_buffer);
+      Snapshot::SetupFromBuffer(isolate_snapshot_data.buffer());
   ASSERT(snapshot->kind() == Snapshot::kFull);
   benchmark->set_score(snapshot->length());
-
-  free(vm_snapshot_data_buffer);
-  free(isolate_snapshot_data_buffer);
 }
 
 BENCHMARK(CreateMirrorSystem) {
diff --git a/runtime/vm/bss_relocs.cc b/runtime/vm/bss_relocs.cc
index 80f50f5..2cb3157 100644
--- a/runtime/vm/bss_relocs.cc
+++ b/runtime/vm/bss_relocs.cc
@@ -31,8 +31,8 @@
   auto const instructions = reinterpret_cast<uword>(
       current->isolate_group()->source()->snapshot_instructions);
   uword dso_base;
-  // For non-natively loaded snapshots, this is instead initialized in
-  // LoadedElf::ResolveSymbols().
+  // Needed for assembly snapshots. For ELF snapshots, we set up the relocated
+  // address information directly in the text segment ImageHeader.
   if (NativeSymbolResolver::LookupSharedObject(instructions, &dso_base)) {
     InitializeBSSEntry(Relocation::InstructionsRelocatedAddress,
                        instructions - dso_base, bss_start);
diff --git a/runtime/vm/canonical_tables.h b/runtime/vm/canonical_tables.h
new file mode 100644
index 0000000..69b79eb
--- /dev/null
+++ b/runtime/vm/canonical_tables.h
@@ -0,0 +1,259 @@
+// Copyright (c) 2016, 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.
+
+#ifndef RUNTIME_VM_CANONICAL_TABLES_H_
+#define RUNTIME_VM_CANONICAL_TABLES_H_
+
+#include "platform/assert.h"
+#include "vm/hash_table.h"
+#include "vm/object.h"
+
+namespace dart {
+
+template <typename CharType>
+class CharArray {
+ public:
+  CharArray(const CharType* data, intptr_t len) : data_(data), len_(len) {
+    hash_ = String::Hash(data, len);
+  }
+  StringPtr ToSymbol() const {
+    String& result = String::Handle(StringFrom(data_, len_, Heap::kOld));
+    result.SetCanonical();
+    result.SetHash(hash_);
+    return result.raw();
+  }
+  bool Equals(const String& other) const {
+    ASSERT(other.HasHash());
+    if (other.Hash() != hash_) {
+      return false;
+    }
+    return other.Equals(data_, len_);
+  }
+  intptr_t Hash() const { return hash_; }
+
+ private:
+  const CharType* data_;
+  intptr_t len_;
+  intptr_t hash_;
+};
+typedef CharArray<uint8_t> Latin1Array;
+typedef CharArray<uint16_t> UTF16Array;
+typedef CharArray<int32_t> UTF32Array;
+
+class StringSlice {
+ public:
+  StringSlice(const String& str, intptr_t begin_index, intptr_t length)
+      : str_(str), begin_index_(begin_index), len_(length) {
+    hash_ = is_all() ? str.Hash() : String::Hash(str, begin_index, length);
+  }
+  StringPtr ToSymbol() const;
+  bool Equals(const String& other) const {
+    ASSERT(other.HasHash());
+    if (other.Hash() != hash_) {
+      return false;
+    }
+    return other.Equals(str_, begin_index_, len_);
+  }
+  intptr_t Hash() const { return hash_; }
+
+ private:
+  bool is_all() const { return begin_index_ == 0 && len_ == str_.Length(); }
+  const String& str_;
+  intptr_t begin_index_;
+  intptr_t len_;
+  intptr_t hash_;
+};
+
+class ConcatString {
+ public:
+  ConcatString(const String& str1, const String& str2)
+      : str1_(str1), str2_(str2), hash_(String::HashConcat(str1, str2)) {}
+  StringPtr ToSymbol() const;
+  bool Equals(const String& other) const {
+    ASSERT(other.HasHash());
+    if (other.Hash() != hash_) {
+      return false;
+    }
+    return other.EqualsConcat(str1_, str2_);
+  }
+  intptr_t Hash() const { return hash_; }
+
+ private:
+  const String& str1_;
+  const String& str2_;
+  intptr_t hash_;
+};
+
+class SymbolTraits {
+ public:
+  static const char* Name() { return "SymbolTraits"; }
+  static bool ReportStats() { return false; }
+
+  static bool IsMatch(const Object& a, const Object& b) {
+    const String& a_str = String::Cast(a);
+    const String& b_str = String::Cast(b);
+    ASSERT(a_str.HasHash());
+    ASSERT(b_str.HasHash());
+    if (a_str.Hash() != b_str.Hash()) {
+      return false;
+    }
+    intptr_t a_len = a_str.Length();
+    if (a_len != b_str.Length()) {
+      return false;
+    }
+    // Use a comparison which does not consider the state of the canonical bit.
+    return a_str.Equals(b_str, 0, a_len);
+  }
+  template <typename CharType>
+  static bool IsMatch(const CharArray<CharType>& array, const Object& obj) {
+    return array.Equals(String::Cast(obj));
+  }
+  static bool IsMatch(const StringSlice& slice, const Object& obj) {
+    return slice.Equals(String::Cast(obj));
+  }
+  static bool IsMatch(const ConcatString& concat, const Object& obj) {
+    return concat.Equals(String::Cast(obj));
+  }
+  static uword Hash(const Object& key) { return String::Cast(key).Hash(); }
+  template <typename CharType>
+  static uword Hash(const CharArray<CharType>& array) {
+    return array.Hash();
+  }
+  static uword Hash(const StringSlice& slice) { return slice.Hash(); }
+  static uword Hash(const ConcatString& concat) { return concat.Hash(); }
+  template <typename CharType>
+  static ObjectPtr NewKey(const CharArray<CharType>& array) {
+    return array.ToSymbol();
+  }
+  static ObjectPtr NewKey(const StringSlice& slice) { return slice.ToSymbol(); }
+  static ObjectPtr NewKey(const ConcatString& concat) {
+    return concat.ToSymbol();
+  }
+};
+typedef UnorderedHashSet<SymbolTraits> CanonicalStringSet;
+
+class CanonicalTypeKey {
+ public:
+  explicit CanonicalTypeKey(const Type& key) : key_(key) {}
+  bool Matches(const Type& arg) const { return key_.Equals(arg); }
+  uword Hash() const { return key_.Hash(); }
+  const Type& key_;
+
+ private:
+  DISALLOW_ALLOCATION();
+};
+
+// Traits for looking up Canonical Type based on its hash.
+class CanonicalTypeTraits {
+ public:
+  static const char* Name() { return "CanonicalTypeTraits"; }
+  static bool ReportStats() { return false; }
+
+  // Called when growing the table.
+  static bool IsMatch(const Object& a, const Object& b) {
+    ASSERT(a.IsType() && b.IsType());
+    const Type& arg1 = Type::Cast(a);
+    const Type& arg2 = Type::Cast(b);
+    return arg1.Equals(arg2) && (arg1.Hash() == arg2.Hash());
+  }
+  static bool IsMatch(const CanonicalTypeKey& a, const Object& b) {
+    ASSERT(b.IsType());
+    return a.Matches(Type::Cast(b));
+  }
+  static uword Hash(const Object& key) {
+    ASSERT(key.IsType());
+    return Type::Cast(key).Hash();
+  }
+  static uword Hash(const CanonicalTypeKey& key) { return key.Hash(); }
+  static ObjectPtr NewKey(const CanonicalTypeKey& obj) {
+    return obj.key_.raw();
+  }
+};
+typedef UnorderedHashSet<CanonicalTypeTraits> CanonicalTypeSet;
+
+class CanonicalTypeParameterKey {
+ public:
+  explicit CanonicalTypeParameterKey(const TypeParameter& key) : key_(key) {}
+  bool Matches(const TypeParameter& arg) const { return key_.Equals(arg); }
+  uword Hash() const { return key_.Hash(); }
+  const TypeParameter& key_;
+
+ private:
+  DISALLOW_ALLOCATION();
+};
+
+// Traits for looking up Canonical TypeParameter based on its hash.
+class CanonicalTypeParameterTraits {
+ public:
+  static const char* Name() { return "CanonicalTypeParameterTraits"; }
+  static bool ReportStats() { return false; }
+
+  // Called when growing the table.
+  static bool IsMatch(const Object& a, const Object& b) {
+    ASSERT(a.IsTypeParameter() && b.IsTypeParameter());
+    const TypeParameter& arg1 = TypeParameter::Cast(a);
+    const TypeParameter& arg2 = TypeParameter::Cast(b);
+    return arg1.Equals(arg2) && (arg1.Hash() == arg2.Hash());
+  }
+  static bool IsMatch(const CanonicalTypeParameterKey& a, const Object& b) {
+    ASSERT(b.IsTypeParameter());
+    return a.Matches(TypeParameter::Cast(b));
+  }
+  static uword Hash(const Object& key) {
+    ASSERT(key.IsTypeParameter());
+    return TypeParameter::Cast(key).Hash();
+  }
+  static uword Hash(const CanonicalTypeParameterKey& key) { return key.Hash(); }
+  static ObjectPtr NewKey(const CanonicalTypeParameterKey& obj) {
+    return obj.key_.raw();
+  }
+};
+typedef UnorderedHashSet<CanonicalTypeParameterTraits>
+    CanonicalTypeParameterSet;
+
+class CanonicalTypeArgumentsKey {
+ public:
+  explicit CanonicalTypeArgumentsKey(const TypeArguments& key) : key_(key) {}
+  bool Matches(const TypeArguments& arg) const {
+    return key_.Equals(arg) && (key_.Hash() == arg.Hash());
+  }
+  uword Hash() const { return key_.Hash(); }
+  const TypeArguments& key_;
+
+ private:
+  DISALLOW_ALLOCATION();
+};
+
+// Traits for looking up Canonical TypeArguments based on its hash.
+class CanonicalTypeArgumentsTraits {
+ public:
+  static const char* Name() { return "CanonicalTypeArgumentsTraits"; }
+  static bool ReportStats() { return false; }
+
+  // Called when growing the table.
+  static bool IsMatch(const Object& a, const Object& b) {
+    ASSERT(a.IsTypeArguments() && b.IsTypeArguments());
+    const TypeArguments& arg1 = TypeArguments::Cast(a);
+    const TypeArguments& arg2 = TypeArguments::Cast(b);
+    return arg1.Equals(arg2) && (arg1.Hash() == arg2.Hash());
+  }
+  static bool IsMatch(const CanonicalTypeArgumentsKey& a, const Object& b) {
+    ASSERT(b.IsTypeArguments());
+    return a.Matches(TypeArguments::Cast(b));
+  }
+  static uword Hash(const Object& key) {
+    ASSERT(key.IsTypeArguments());
+    return TypeArguments::Cast(key).Hash();
+  }
+  static uword Hash(const CanonicalTypeArgumentsKey& key) { return key.Hash(); }
+  static ObjectPtr NewKey(const CanonicalTypeArgumentsKey& obj) {
+    return obj.key_.raw();
+  }
+};
+typedef UnorderedHashSet<CanonicalTypeArgumentsTraits>
+    CanonicalTypeArgumentsSet;
+
+}  // namespace dart
+
+#endif  // RUNTIME_VM_CANONICAL_TABLES_H_
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index 9732d93..e2c1435 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -7,6 +7,7 @@
 
 #include "vm/class_finalizer.h"
 
+#include "vm/canonical_tables.h"
 #include "vm/compiler/jit/compiler.h"
 #include "vm/flags.h"
 #include "vm/hash_table.h"
@@ -21,7 +22,6 @@
 #include "vm/runtime_entry.h"
 #include "vm/symbols.h"
 #include "vm/timeline.h"
-#include "vm/type_table.h"
 #include "vm/type_testing_stubs.h"
 
 namespace dart {
diff --git a/runtime/vm/class_id.h b/runtime/vm/class_id.h
index 0664cbb..97f9325 100644
--- a/runtime/vm/class_id.h
+++ b/runtime/vm/class_id.h
@@ -91,7 +91,8 @@
   V(FutureOr)                                                                  \
   V(UserTag)                                                                   \
   V(TransferableTypedData)                                                     \
-  V(WeakSerializationReference)
+  V(WeakSerializationReference)                                                \
+  V(ImageHeader)
 
 #define CLASS_LIST_ARRAYS(V)                                                   \
   V(Array)                                                                     \
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index 1918244..d6436b7 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -9,6 +9,7 @@
 #include "platform/assert.h"
 #include "vm/bootstrap.h"
 #include "vm/bss_relocs.h"
+#include "vm/canonical_tables.h"
 #include "vm/class_id.h"
 #include "vm/code_observers.h"
 #include "vm/compiler/api/print_filter.h"
@@ -494,6 +495,25 @@
       }
     }
   }
+
+  void PostLoadEarly(Deserializer* d, const Array& refs) {
+    if (d->isolate() == Dart::vm_isolate()) {
+      return;
+    }
+    CanonicalTypeArgumentsSet table(
+        d->zone(), d->isolate()->object_store()->canonical_type_arguments());
+    TypeArguments& type_arg = TypeArguments::Handle(d->zone());
+    for (intptr_t i = start_index_; i < stop_index_; i++) {
+      type_arg ^= refs.At(i);
+      if (type_arg.IsCanonical()) {
+        bool present = table.Insert(type_arg);
+        // Two recursive types with different topology (and hashes) may be
+        // equal.
+        ASSERT(!present || type_arg.IsRecursive());
+      }
+    }
+    d->isolate()->object_store()->set_canonical_type_arguments(table.Release());
+  }
 };
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
@@ -1892,23 +1912,23 @@
     code->ptr()->code_source_map_ = static_cast<CodeSourceMapPtr>(d->ReadRef());
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
-      if (d->kind() == Snapshot::kFullJIT) {
-        code->ptr()->deopt_info_array_ = static_cast<ArrayPtr>(d->ReadRef());
-        code->ptr()->static_calls_target_table_ =
-            static_cast<ArrayPtr>(d->ReadRef());
-      }
+    if (d->kind() == Snapshot::kFullJIT) {
+      code->ptr()->deopt_info_array_ = static_cast<ArrayPtr>(d->ReadRef());
+      code->ptr()->static_calls_target_table_ =
+          static_cast<ArrayPtr>(d->ReadRef());
+    }
 #endif  // !DART_PRECOMPILED_RUNTIME
 
 #if !defined(PRODUCT)
-      code->ptr()->return_address_metadata_ = d->ReadRef();
-      code->ptr()->var_descriptors_ = LocalVarDescriptors::null();
-      code->ptr()->comments_ = FLAG_code_comments
-                                   ? static_cast<ArrayPtr>(d->ReadRef())
-                                   : Array::null();
-      code->ptr()->compile_timestamp_ = 0;
+    code->ptr()->return_address_metadata_ = d->ReadRef();
+    code->ptr()->var_descriptors_ = LocalVarDescriptors::null();
+    code->ptr()->comments_ = FLAG_code_comments
+                                 ? static_cast<ArrayPtr>(d->ReadRef())
+                                 : Array::null();
+    code->ptr()->compile_timestamp_ = 0;
 #endif
 
-      code->ptr()->state_bits_ = d->Read<int32_t>();
+    code->ptr()->state_bits_ = d->Read<int32_t>();
   }
 
   void PostLoad(Deserializer* d, const Array& refs) {
@@ -3608,6 +3628,25 @@
     }
   }
 
+  void PostLoadEarly(Deserializer* d, const Array& refs) {
+    if (d->isolate() == Dart::vm_isolate()) {
+      return;
+    }
+    CanonicalTypeSet table(d->zone(),
+                           d->isolate()->object_store()->canonical_types());
+    Type& type = Type::Handle(d->zone());
+    for (intptr_t i = canonical_start_index_; i < canonical_stop_index_; i++) {
+      type ^= refs.At(i);
+      if (type.IsCanonical()) {
+        bool present = table.Insert(type);
+        // Two recursive types with different topology (and hashes) may be
+        // equal.
+        ASSERT(!present || type.IsRecursive());
+      }
+    }
+    d->isolate()->object_store()->set_canonical_types(table.Release());
+  }
+
   void PostLoad(Deserializer* d, const Array& refs) {
     Type& type = Type::Handle(d->zone());
     Code& stub = Code::Handle(d->zone());
@@ -3840,6 +3879,24 @@
     }
   }
 
+  void PostLoadEarly(Deserializer* d, const Array& refs) {
+    if (d->isolate() == Dart::vm_isolate()) {
+      return;
+    }
+    CanonicalTypeParameterSet table(
+        d->zone(), d->isolate()->object_store()->canonical_type_parameters());
+    TypeParameter& type_param = TypeParameter::Handle(d->zone());
+    for (intptr_t i = canonical_start_index_; i < canonical_stop_index_; i++) {
+      type_param ^= refs.At(i);
+      if (type_param.IsCanonical() && !type_param.IsDeclaration()) {
+        bool present = table.Insert(type_param);
+        ASSERT(!present);
+      }
+    }
+    d->isolate()->object_store()->set_canonical_type_parameters(
+        table.Release());
+  }
+
   void PostLoad(Deserializer* d, const Array& refs) {
     TypeParameter& type_param = TypeParameter::Handle(d->zone());
     Code& stub = Code::Handle(d->zone());
@@ -4894,6 +4951,23 @@
       String::SetCachedHash(str, hasher.Finalize());
     }
   }
+
+  void PostLoadEarly(Deserializer* d, const Array& refs) {
+    if (d->isolate() == Dart::vm_isolate()) {
+      return;
+    }
+    CanonicalStringSet table(d->zone(),
+                             d->isolate()->object_store()->symbol_table());
+    String& str = String::Handle(d->zone());
+    for (intptr_t i = start_index_; i < stop_index_; i++) {
+      str ^= refs.At(i);
+      if (str.IsCanonical()) {
+        bool present = table.Insert(str);
+        ASSERT(!present);
+      }
+    }
+    d->isolate()->object_store()->set_symbol_table(table.Release());
+  }
 };
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
@@ -4974,6 +5048,23 @@
       String::SetCachedHash(str, hasher.Finalize());
     }
   }
+
+  void PostLoadEarly(Deserializer* d, const Array& refs) {
+    if (d->isolate() == Dart::vm_isolate()) {
+      return;
+    }
+    CanonicalStringSet table(d->zone(),
+                             d->isolate()->object_store()->symbol_table());
+    String& str = String::Handle(d->zone());
+    for (intptr_t i = start_index_; i < stop_index_; i++) {
+      str ^= refs.At(i);
+      if (str.IsCanonical()) {
+        bool present = table.Insert(str);
+        ASSERT(!present);
+      }
+    }
+    d->isolate()->object_store()->set_symbol_table(table.Release());
+  }
 };
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
@@ -5204,7 +5295,36 @@
                             ObjectStore* object_store)
       : num_base_objects_(num_base_objects),
         object_store_(object_store),
-        dispatch_table_entries_(Array::Handle()) {}
+        saved_symbol_table_(Array::Handle()),
+        saved_canonical_types_(Array::Handle()),
+        saved_canonical_type_parameters_(Array::Handle()),
+        saved_canonical_type_arguments_(Array::Handle()),
+        dispatch_table_entries_(Array::Handle()) {
+    saved_symbol_table_ = object_store->symbol_table();
+    object_store->set_symbol_table(
+        Array::Handle(HashTables::New<CanonicalStringSet>(4)));
+
+    saved_canonical_types_ = object_store->canonical_types();
+    object_store->set_canonical_types(
+        Array::Handle(HashTables::New<CanonicalTypeSet>(4)));
+
+    saved_canonical_type_parameters_ =
+        object_store->canonical_type_parameters();
+    object_store->set_canonical_type_parameters(
+        Array::Handle(HashTables::New<CanonicalTypeParameterSet>(4)));
+
+    saved_canonical_type_arguments_ = object_store->canonical_type_arguments();
+    object_store->set_canonical_type_arguments(
+        Array::Handle(HashTables::New<CanonicalTypeArgumentsSet>(4)));
+  }
+  ~ProgramSerializationRoots() {
+    object_store_->set_symbol_table(saved_symbol_table_);
+    object_store_->set_canonical_types(saved_canonical_types_);
+    object_store_->set_canonical_type_parameters(
+        saved_canonical_type_parameters_);
+    object_store_->set_canonical_type_arguments(
+        saved_canonical_type_arguments_);
+  }
 
   void AddBaseObjects(Serializer* s) {
     if (num_base_objects_ == 0) {
@@ -5257,6 +5377,10 @@
  private:
   intptr_t num_base_objects_;
   ObjectStore* object_store_;
+  Array& saved_symbol_table_;
+  Array& saved_canonical_types_;
+  Array& saved_canonical_type_parameters_;
+  Array& saved_canonical_type_arguments_;
   Array& dispatch_table_entries_;
 };
 #endif  // !DART_PRECOMPILED_RUNTIME
@@ -5426,9 +5550,7 @@
 
 Serializer::Serializer(Thread* thread,
                        Snapshot::Kind kind,
-                       uint8_t** buffer,
-                       ReAlloc alloc,
-                       intptr_t initial_size,
+                       NonStreamingWriteStream* stream,
                        ImageWriter* image_writer,
                        bool vm,
                        V8SnapshotProfileWriter* profile_writer)
@@ -5436,7 +5558,7 @@
       heap_(thread->isolate()->heap()),
       zone_(thread->zone()),
       kind_(kind),
-      stream_(buffer, alloc, initial_size),
+      stream_(stream),
       image_writer_(image_writer),
       clusters_by_cid_(NULL),
       stack_(),
@@ -5481,8 +5603,8 @@
     // All bytes between objects are attributed into root node.
     profile_writer_->AttributeBytesTo(
         V8SnapshotProfileWriter::ArtificialRootId(),
-        stream_.Position() - object_currently_writing_.stream_start_);
-    object_currently_writing_.stream_start_ = stream_.Position();
+        stream_->Position() - object_currently_writing_.stream_start_);
+    object_currently_writing_.stream_start_ = stream_->Position();
   }
 #endif
 }
@@ -5525,7 +5647,7 @@
   FlushBytesWrittenToRoot();
   object_currently_writing_.object_ = obj;
   object_currently_writing_.id_ = id;
-  object_currently_writing_.stream_start_ = stream_.Position();
+  object_currently_writing_.stream_start_ = stream_->Position();
   object_currently_writing_.cid_ = cid;
   profile_writer_->SetObjectTypeAndName(
       {V8SnapshotProfileWriter::kSnapshot, id}, type, name);
@@ -5536,9 +5658,9 @@
     ASSERT(IsAllocatedReference(object_currently_writing_.id_));
     profile_writer_->AttributeBytesTo(
         {V8SnapshotProfileWriter::kSnapshot, object_currently_writing_.id_},
-        stream_.Position() - object_currently_writing_.stream_start_);
+        stream_->Position() - object_currently_writing_.stream_start_);
     object_currently_writing_ = ProfilingObject();
-    object_currently_writing_.stream_start_ = stream_.Position();
+    object_currently_writing_.stream_start_ = stream_->Position();
   }
 }
 
@@ -6087,7 +6209,7 @@
 #endif
 
   FlushBytesWrittenToRoot();
-  object_currently_writing_.stream_start_ = stream_.Position();
+  object_currently_writing_.stream_start_ = stream_->Position();
 
   PrintSnapshotSizes();
 
@@ -6218,7 +6340,7 @@
   }
   dispatch_table_size_ = bytes_written() - bytes_before;
 
-  object_currently_writing_.stream_start_ = stream_.Position();
+  object_currently_writing_.stream_start_ = stream_->Position();
   // If any bytes were written for the dispatch table, add it to the profile.
   if (dispatch_table_size_ > 0 && profile_writer_ != nullptr) {
     // Grab an unused ref index for a unique object id for the dispatch table.
@@ -6803,8 +6925,8 @@
     for (intptr_t i = 0; i < num_clusters_; i++) {
       clusters_[i]->ReadFill(this);
 #if defined(DEBUG)
-    int32_t section_marker = Read<int32_t>();
-    ASSERT(section_marker == kSectionMarker);
+      int32_t section_marker = Read<int32_t>();
+      ASSERT(section_marker == kSectionMarker);
 #endif
     }
 
@@ -6829,23 +6951,30 @@
   }
 #endif
 
+  // TODO(rmacnak): When splitting literals, load clusters requiring
+  // canonicalization first, canonicalize and update the ref array, the load
+  // the remaining clusters to avoid a full heap walk to update references to
+  // the losers of any canonicalization races.
+  for (intptr_t i = 0; i < num_clusters_; i++) {
+    clusters_[i]->PostLoadEarly(this, refs);
+  }
+
   for (intptr_t i = 0; i < num_clusters_; i++) {
     clusters_[i]->PostLoad(this, refs);
   }
 }
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
-FullSnapshotWriter::FullSnapshotWriter(Snapshot::Kind kind,
-                                       uint8_t** vm_snapshot_data_buffer,
-                                       uint8_t** isolate_snapshot_data_buffer,
-                                       ReAlloc alloc,
-                                       ImageWriter* vm_image_writer,
-                                       ImageWriter* isolate_image_writer)
+FullSnapshotWriter::FullSnapshotWriter(
+    Snapshot::Kind kind,
+    NonStreamingWriteStream* vm_snapshot_data,
+    NonStreamingWriteStream* isolate_snapshot_data,
+    ImageWriter* vm_image_writer,
+    ImageWriter* isolate_image_writer)
     : thread_(Thread::Current()),
       kind_(kind),
-      vm_snapshot_data_buffer_(vm_snapshot_data_buffer),
-      isolate_snapshot_data_buffer_(isolate_snapshot_data_buffer),
-      alloc_(alloc),
+      vm_snapshot_data_(vm_snapshot_data),
+      isolate_snapshot_data_(isolate_snapshot_data),
       vm_isolate_snapshot_size_(0),
       isolate_snapshot_size_(0),
       vm_image_writer_(vm_image_writer),
@@ -6854,7 +6983,6 @@
       clustered_isolate_size_(0),
       mapped_data_size_(0),
       mapped_text_size_(0) {
-  ASSERT(alloc_ != NULL);
   ASSERT(isolate() != NULL);
   ASSERT(heap() != NULL);
   ObjectStore* object_store = isolate()->object_store();
@@ -6877,10 +7005,9 @@
 intptr_t FullSnapshotWriter::WriteVMSnapshot() {
   TIMELINE_DURATION(thread(), Isolate, "WriteVMSnapshot");
 
-  ASSERT(vm_snapshot_data_buffer_ != NULL);
-  Serializer serializer(thread(), kind_, vm_snapshot_data_buffer_, alloc_,
-                        kInitialSize, vm_image_writer_, /*vm=*/true,
-                        profile_writer_);
+  ASSERT(vm_snapshot_data_ != nullptr);
+  Serializer serializer(thread(), kind_, vm_snapshot_data_, vm_image_writer_,
+                        /*vm=*/true, profile_writer_);
 
   serializer.ReserveHeader();
   serializer.WriteVersionAndFeatures(true);
@@ -6909,9 +7036,9 @@
     GrowableArray<LoadingUnitSerializationData*>* units) {
   TIMELINE_DURATION(thread(), Isolate, "WriteProgramSnapshot");
 
-  Serializer serializer(thread(), kind_, isolate_snapshot_data_buffer_, alloc_,
-                        kInitialSize, isolate_image_writer_, /*vm=*/false,
-                        profile_writer_);
+  ASSERT(isolate_snapshot_data_ != nullptr);
+  Serializer serializer(thread(), kind_, isolate_snapshot_data_,
+                        isolate_image_writer_, /*vm=*/false, profile_writer_);
   serializer.set_loading_units(units);
   serializer.set_current_loading_unit_id(LoadingUnit::kRootId);
   ObjectStore* object_store = isolate()->object_store();
@@ -6954,9 +7081,8 @@
     uint32_t program_hash) {
   TIMELINE_DURATION(thread(), Isolate, "WriteUnitSnapshot");
 
-  Serializer serializer(thread(), kind_, isolate_snapshot_data_buffer_, alloc_,
-                        kInitialSize, isolate_image_writer_, /*vm=*/false,
-                        profile_writer_);
+  Serializer serializer(thread(), kind_, isolate_snapshot_data_,
+                        isolate_image_writer_, /*vm=*/false, profile_writer_);
   serializer.set_loading_units(units);
   serializer.set_current_loading_unit_id(unit->id());
 
@@ -6989,14 +7115,14 @@
 void FullSnapshotWriter::WriteFullSnapshot(
     GrowableArray<LoadingUnitSerializationData*>* data) {
   intptr_t num_base_objects;
-  if (vm_snapshot_data_buffer() != NULL) {
+  if (vm_snapshot_data_ != nullptr) {
     num_base_objects = WriteVMSnapshot();
     ASSERT(num_base_objects != 0);
   } else {
     num_base_objects = 0;
   }
 
-  if (isolate_snapshot_data_buffer() != NULL) {
+  if (isolate_snapshot_data_ != nullptr) {
     WriteProgramSnapshot(num_base_objects, data);
   }
 
@@ -7026,8 +7152,7 @@
       buffer_(snapshot->Addr()),
       size_(snapshot->length()),
       data_image_(snapshot->DataImage()),
-      instructions_image_(instructions_buffer) {
-}
+      instructions_image_(instructions_buffer) {}
 
 char* SnapshotHeaderReader::InitializeGlobalVMFlagsFromSnapshot(
     const Snapshot* snapshot) {
@@ -7217,12 +7342,8 @@
   // Initialize entries in the VM portion of the BSS segment.
   ASSERT(Snapshot::IncludesCode(kind_));
   Image image(instructions_image_);
-  if (image.bss_offset() != 0) {
-    // The const cast is safe because we're translating from the start of the
-    // instructions (read-only) to the start of the BSS (read-write).
-    uword* const bss_start = const_cast<uword*>(reinterpret_cast<const uword*>(
-        instructions_image_ + image.bss_offset()));
-    BSS::Initialize(thread_, bss_start, /*vm=*/true);
+  if (auto const bss = image.bss()) {
+    BSS::Initialize(thread_, bss, /*vm=*/true);
   }
 #endif  // defined(DART_PRECOMPILED_RUNTIME)
 
@@ -7353,12 +7474,8 @@
   // Initialize entries in the isolate portion of the BSS segment.
   ASSERT(Snapshot::IncludesCode(kind_));
   Image image(instructions_image_);
-  if (image.bss_offset() != 0) {
-    // The const cast is safe because we're translating from the start of the
-    // instructions (read-only) to the start of the BSS (read-write).
-    uword* const bss_start = const_cast<uword*>(reinterpret_cast<const uword*>(
-        instructions_image_ + image.bss_offset()));
-    BSS::Initialize(thread_, bss_start, /*vm=*/false);
+  if (auto const bss = image.bss()) {
+    BSS::Initialize(thread_, bss, /*vm=*/false);
   }
 #endif  // defined(DART_PRECOMPILED_RUNTIME)
 }
diff --git a/runtime/vm/clustered_snapshot.h b/runtime/vm/clustered_snapshot.h
index 2dd7253..4188c75 100644
--- a/runtime/vm/clustered_snapshot.h
+++ b/runtime/vm/clustered_snapshot.h
@@ -116,6 +116,7 @@
 
   // Complete any action that requires the full graph to be deserialized, such
   // as rehashing.
+  virtual void PostLoadEarly(Deserializer* deserializer, const Array& refs) {}
   virtual void PostLoad(Deserializer* deserializer, const Array& refs) {}
 
  protected:
@@ -192,9 +193,7 @@
  public:
   Serializer(Thread* thread,
              Snapshot::Kind kind,
-             uint8_t** buffer,
-             ReAlloc alloc,
-             intptr_t initial_size,
+             NonStreamingWriteStream* stream,
              ImageWriter* image_writer_,
              bool vm_,
              V8SnapshotProfileWriter* profile_writer = nullptr);
@@ -271,13 +270,13 @@
 
   void ReserveHeader() {
     // Make room for recording snapshot buffer size.
-    stream_.SetPosition(Snapshot::kHeaderSize);
+    stream_->SetPosition(Snapshot::kHeaderSize);
   }
 
   void FillHeader(Snapshot::Kind kind) {
-    Snapshot* header = reinterpret_cast<Snapshot*>(stream_.buffer());
+    Snapshot* header = reinterpret_cast<Snapshot*>(stream_->buffer());
     header->set_magic();
-    header->set_length(stream_.bytes_written());
+    header->set_length(stream_->bytes_written());
     header->set_kind(kind);
   }
 
@@ -288,8 +287,8 @@
 
   FieldTable* field_table() { return field_table_; }
 
-  WriteStream* stream() { return &stream_; }
-  intptr_t bytes_written() { return stream_.bytes_written(); }
+  NonStreamingWriteStream* stream() { return stream_; }
+  intptr_t bytes_written() { return stream_->bytes_written(); }
 
   void FlushBytesWrittenToRoot();
   void TraceStartWritingObject(const char* type, ObjectPtr obj, StringPtr name);
@@ -302,19 +301,19 @@
   // sizeof(T) must be in {1,2,4,8}.
   template <typename T>
   void Write(T value) {
-    WriteStream::Raw<sizeof(T), T>::Write(&stream_, value);
+    BaseWriteStream::Raw<sizeof(T), T>::Write(stream_, value);
   }
-  void WriteUnsigned(intptr_t value) { stream_.WriteUnsigned(value); }
-  void WriteUnsigned64(uint64_t value) { stream_.WriteUnsigned(value); }
+  void WriteUnsigned(intptr_t value) { stream_->WriteUnsigned(value); }
+  void WriteUnsigned64(uint64_t value) { stream_->WriteUnsigned(value); }
 
   void WriteWordWith32BitWrites(uword value) {
-    stream_.WriteWordWith32BitWrites(value);
+    stream_->WriteWordWith32BitWrites(value);
   }
 
   void WriteBytes(const uint8_t* addr, intptr_t len) {
-    stream_.WriteBytes(addr, len);
+    stream_->WriteBytes(addr, len);
   }
-  void Align(intptr_t alignment) { stream_.Align(alignment); }
+  void Align(intptr_t alignment) { stream_->Align(alignment); }
 
   void WriteRootRef(ObjectPtr object, const char* name = nullptr) {
     intptr_t id = RefId(object);
@@ -498,7 +497,7 @@
   Heap* heap_;
   Zone* zone_;
   Snapshot::Kind kind_;
-  WriteStream stream_;
+  NonStreamingWriteStream* stream_;
   ImageWriter* image_writer_;
   SerializationCluster** clusters_by_cid_;
   GrowableArray<ObjectPtr> stack_;
@@ -739,19 +738,12 @@
  public:
   static const intptr_t kInitialSize = 64 * KB;
   FullSnapshotWriter(Snapshot::Kind kind,
-                     uint8_t** vm_snapshot_data_buffer,
-                     uint8_t** isolate_snapshot_data_buffer,
-                     ReAlloc alloc,
+                     NonStreamingWriteStream* vm_snapshot_data,
+                     NonStreamingWriteStream* isolate_snapshot_data,
                      ImageWriter* vm_image_writer,
                      ImageWriter* iso_image_writer);
   ~FullSnapshotWriter();
 
-  uint8_t** vm_snapshot_data_buffer() const { return vm_snapshot_data_buffer_; }
-
-  uint8_t** isolate_snapshot_data_buffer() const {
-    return isolate_snapshot_data_buffer_;
-  }
-
   Thread* thread() const { return thread_; }
   Zone* zone() const { return thread_->zone(); }
   Isolate* isolate() const { return thread_->isolate(); }
@@ -777,9 +769,8 @@
 
   Thread* thread_;
   Snapshot::Kind kind_;
-  uint8_t** vm_snapshot_data_buffer_;
-  uint8_t** isolate_snapshot_data_buffer_;
-  ReAlloc alloc_;
+  NonStreamingWriteStream* const vm_snapshot_data_;
+  NonStreamingWriteStream* const isolate_snapshot_data_;
   intptr_t vm_isolate_snapshot_size_;
   intptr_t isolate_snapshot_size_;
   ImageWriter* vm_image_writer_;
diff --git a/runtime/vm/code_descriptors.cc b/runtime/vm/code_descriptors.cc
index a462905..2dc5584 100644
--- a/runtime/vm/code_descriptors.cc
+++ b/runtime/vm/code_descriptors.cc
@@ -281,13 +281,6 @@
   return handlers.raw();
 }
 
-static uint8_t* ZoneAllocator(uint8_t* ptr,
-                              intptr_t old_size,
-                              intptr_t new_size) {
-  Zone* zone = Thread::Current()->zone();
-  return zone->Realloc<uint8_t>(ptr, old_size, new_size);
-}
-
 #if !defined(DART_PRECOMPILED_RUNTIME)
 class CatchEntryMovesMapBuilder::TrieNode : public ZoneAllocated {
  public:
@@ -319,8 +312,7 @@
     : zone_(Thread::Current()->zone()),
       root_(new TrieNode()),
       current_pc_offset_(0),
-      buffer_(NULL),
-      stream_(&buffer_, ZoneAllocator, 64) {}
+      stream_(zone_, 64) {}
 
 void CatchEntryMovesMapBuilder::Append(const CatchEntryMove& move) {
   moves_.Add(move);
@@ -344,7 +336,7 @@
   intptr_t length = moves_.length() - suffix_length;
   intptr_t current_offset = stream_.bytes_written();
 
-  typedef WriteStream::Raw<sizeof(intptr_t), intptr_t> Writer;
+  typedef ZoneWriteStream::Raw<sizeof(intptr_t), intptr_t> Writer;
   Writer::Write(&stream_, current_pc_offset_);
   Writer::Write(&stream_, length);
   Writer::Write(&stream_, suffix_length);
@@ -378,6 +370,7 @@
     TokenPosition(TokenPosition::kDartCodeProloguePos);
 
 CodeSourceMapBuilder::CodeSourceMapBuilder(
+    Zone* zone,
     bool stack_traces_only,
     const GrowableArray<intptr_t>& caller_inline_id,
     const GrowableArray<TokenPosition>& inline_id_to_token_pos,
@@ -393,8 +386,7 @@
       inline_id_to_function_(inline_id_to_function),
       inlined_functions_(
           GrowableObjectArray::Handle(GrowableObjectArray::New(Heap::kOld))),
-      buffer_(NULL),
-      stream_(&buffer_, ZoneAllocator, 64),
+      stream_(zone, 64),
       stack_traces_only_(stack_traces_only) {
   buffered_inline_id_stack_.Add(0);
   buffered_token_pos_stack_.Add(kInitialPosition);
@@ -567,7 +559,7 @@
   intptr_t length = stream_.bytes_written();
   const CodeSourceMap& map = CodeSourceMap::Handle(CodeSourceMap::New(length));
   NoSafepointScope no_safepoint;
-  memmove(map.Data(), buffer_, length);
+  memmove(map.Data(), stream_.buffer(), length);
   return map.raw();
 }
 
diff --git a/runtime/vm/code_descriptors.h b/runtime/vm/code_descriptors.h
index 6f89c91..bef3ef8 100644
--- a/runtime/vm/code_descriptors.h
+++ b/runtime/vm/code_descriptors.h
@@ -226,8 +226,7 @@
   TrieNode* root_;
   intptr_t current_pc_offset_;
   GrowableArray<CatchEntryMove> moves_;
-  uint8_t* buffer_;
-  WriteStream stream_;
+  ZoneWriteStream stream_;
 
   DISALLOW_COPY_AND_ASSIGN(CatchEntryMovesMapBuilder);
 };
@@ -246,6 +245,7 @@
 class CodeSourceMapBuilder : public ZoneAllocated {
  public:
   CodeSourceMapBuilder(
+      Zone* zone,
       bool stack_traces_only,
       const GrowableArray<intptr_t>& caller_inline_id,
       const GrowableArray<TokenPosition>& inline_id_to_token_pos,
@@ -336,8 +336,7 @@
 
   const GrowableObjectArray& inlined_functions_;
 
-  uint8_t* buffer_;
-  WriteStream stream_;
+  ZoneWriteStream stream_;
 
   const bool stack_traces_only_;
 
diff --git a/runtime/vm/compilation_trace.cc b/runtime/vm/compilation_trace.cc
index 173652f..0db337d 100644
--- a/runtime/vm/compilation_trace.cc
+++ b/runtime/vm/compilation_trace.cc
@@ -429,7 +429,7 @@
   }
 }
 
-TypeFeedbackSaver::TypeFeedbackSaver(WriteStream* stream)
+TypeFeedbackSaver::TypeFeedbackSaver(BaseWriteStream* stream)
     : stream_(stream),
       cls_(Class::Handle()),
       lib_(Library::Handle()),
diff --git a/runtime/vm/compilation_trace.h b/runtime/vm/compilation_trace.h
index cf26611..80d671e 100644
--- a/runtime/vm/compilation_trace.h
+++ b/runtime/vm/compilation_trace.h
@@ -67,7 +67,7 @@
 
 class TypeFeedbackSaver : public FunctionVisitor {
  public:
-  explicit TypeFeedbackSaver(WriteStream* stream);
+  explicit TypeFeedbackSaver(BaseWriteStream* stream);
 
   void WriteHeader();
   void SaveClasses();
@@ -79,7 +79,7 @@
   void WriteString(const String& value);
   void WriteInt(intptr_t value) { stream_->Write(static_cast<int32_t>(value)); }
 
-  WriteStream* const stream_;
+  BaseWriteStream* const stream_;
   Class& cls_;
   Library& lib_;
   String& str_;
diff --git a/runtime/vm/compiler/aot/precompiler.cc b/runtime/vm/compiler/aot/precompiler.cc
index 878ce4a..1f31fd0 100644
--- a/runtime/vm/compiler/aot/precompiler.cc
+++ b/runtime/vm/compiler/aot/precompiler.cc
@@ -5,6 +5,7 @@
 #include "vm/compiler/aot/precompiler.h"
 
 #include "platform/unicode.h"
+#include "vm/canonical_tables.h"
 #include "vm/class_finalizer.h"
 #include "vm/code_patcher.h"
 #include "vm/compiler/aot/aot_call_specializer.h"
@@ -48,7 +49,6 @@
 #include "vm/tags.h"
 #include "vm/timeline.h"
 #include "vm/timer.h"
-#include "vm/type_table.h"
 #include "vm/type_testing_stubs.h"
 #include "vm/version.h"
 #include "vm/zone_text_buffer.h"
@@ -449,8 +449,6 @@
     Symbols::GetStats(I, &symbols_before, &capacity);
   }
 
-  Symbols::Compact();
-
   if (FLAG_trace_precompiler) {
     Symbols::GetStats(I, &symbols_after, &capacity);
     THR_Print("Precompiled %" Pd " functions,", function_count_);
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.cc b/runtime/vm/compiler/backend/flow_graph_compiler.cc
index 9c7eabc..361ccbe 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.cc
@@ -164,7 +164,7 @@
   const bool stack_traces_only = false;
 #endif
   code_source_map_builder_ = new (zone_)
-      CodeSourceMapBuilder(stack_traces_only, caller_inline_id,
+      CodeSourceMapBuilder(zone_, stack_traces_only, caller_inline_id,
                            inline_id_to_token_pos, inline_id_to_function);
 
   ArchSpecificInitialization();
diff --git a/runtime/vm/compiler/frontend/scope_builder.cc b/runtime/vm/compiler/frontend/scope_builder.cc
index bb55bba..e736c7a 100644
--- a/runtime/vm/compiler/frontend/scope_builder.cc
+++ b/runtime/vm/compiler/frontend/scope_builder.cc
@@ -1580,6 +1580,7 @@
   VariableDeclarationHelper helper(&helper_);
   helper.ReadUntilExcluding(VariableDeclarationHelper::kType);
   String& name = H.DartSymbolObfuscate(helper.name_index_);
+  ASSERT(name.Length() > 0);
   AbstractType& type = BuildAndVisitVariableType();  // read type.
   helper.SetJustRead(VariableDeclarationHelper::kType);
   helper.ReadUntilExcluding(VariableDeclarationHelper::kInitializer);
diff --git a/runtime/vm/compiler/runtime_api.cc b/runtime/vm/compiler/runtime_api.cc
index 0aecfbd..c313f53 100644
--- a/runtime/vm/compiler/runtime_api.cc
+++ b/runtime/vm/compiler/runtime_api.cc
@@ -800,6 +800,10 @@
   return 0;
 }
 
+word ImageHeader::InstanceSize() {
+  return RoundedAllocationSize(UnroundedSize());
+}
+
 word Instance::NextFieldOffset() {
   return TranslateOffsetInWords(dart::Instance::NextFieldOffset());
 }
@@ -808,6 +812,10 @@
   return TranslateOffsetInWords(dart::Pointer::NextFieldOffset());
 }
 
+word ImageHeader::NextFieldOffset() {
+  return -kWordSize;
+}
+
 word WeakSerializationReference::NextFieldOffset() {
   return -kWordSize;
 }
diff --git a/runtime/vm/compiler/runtime_api.h b/runtime/vm/compiler/runtime_api.h
index 1a75739..5ec71e8 100644
--- a/runtime/vm/compiler/runtime_api.h
+++ b/runtime/vm/compiler/runtime_api.h
@@ -1179,6 +1179,13 @@
   static word NextFieldOffset();
 };
 
+class ImageHeader : public AllStatic {
+ public:
+  static word UnroundedSize();
+  static word InstanceSize();
+  static word NextFieldOffset();
+};
+
 class WeakSerializationReference : public AllStatic {
  public:
   static word InstanceSize();
diff --git a/runtime/vm/compiler/runtime_offsets_extracted.h b/runtime/vm/compiler/runtime_offsets_extracted.h
index 4994749..6ad8752 100644
--- a/runtime/vm/compiler/runtime_offsets_extracted.h
+++ b/runtime/vm/compiler/runtime_offsets_extracted.h
@@ -454,6 +454,7 @@
 static constexpr dart::compiler::target::word GrowableObjectArray_InstanceSize =
     16;
 static constexpr dart::compiler::target::word ICData_InstanceSize = 32;
+static constexpr dart::compiler::target::word ImageHeader_UnroundedSize = 20;
 static constexpr dart::compiler::target::word Instance_InstanceSize = 4;
 static constexpr dart::compiler::target::word Instructions_InstanceSize = 8;
 static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
@@ -966,6 +967,7 @@
 static constexpr dart::compiler::target::word GrowableObjectArray_InstanceSize =
     32;
 static constexpr dart::compiler::target::word ICData_InstanceSize = 56;
+static constexpr dart::compiler::target::word ImageHeader_UnroundedSize = 40;
 static constexpr dart::compiler::target::word Instance_InstanceSize = 8;
 static constexpr dart::compiler::target::word Instructions_InstanceSize = 12;
 static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
@@ -1469,6 +1471,7 @@
 static constexpr dart::compiler::target::word GrowableObjectArray_InstanceSize =
     16;
 static constexpr dart::compiler::target::word ICData_InstanceSize = 32;
+static constexpr dart::compiler::target::word ImageHeader_UnroundedSize = 20;
 static constexpr dart::compiler::target::word Instance_InstanceSize = 4;
 static constexpr dart::compiler::target::word Instructions_InstanceSize = 8;
 static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
@@ -1982,6 +1985,7 @@
 static constexpr dart::compiler::target::word GrowableObjectArray_InstanceSize =
     32;
 static constexpr dart::compiler::target::word ICData_InstanceSize = 56;
+static constexpr dart::compiler::target::word ImageHeader_UnroundedSize = 40;
 static constexpr dart::compiler::target::word Instance_InstanceSize = 8;
 static constexpr dart::compiler::target::word Instructions_InstanceSize = 12;
 static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
@@ -2484,6 +2488,7 @@
 static constexpr dart::compiler::target::word GrowableObjectArray_InstanceSize =
     16;
 static constexpr dart::compiler::target::word ICData_InstanceSize = 32;
+static constexpr dart::compiler::target::word ImageHeader_UnroundedSize = 20;
 static constexpr dart::compiler::target::word Instance_InstanceSize = 4;
 static constexpr dart::compiler::target::word Instructions_InstanceSize = 8;
 static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
@@ -2990,6 +2995,7 @@
 static constexpr dart::compiler::target::word GrowableObjectArray_InstanceSize =
     32;
 static constexpr dart::compiler::target::word ICData_InstanceSize = 56;
+static constexpr dart::compiler::target::word ImageHeader_UnroundedSize = 40;
 static constexpr dart::compiler::target::word Instance_InstanceSize = 8;
 static constexpr dart::compiler::target::word Instructions_InstanceSize = 12;
 static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
@@ -3487,6 +3493,7 @@
 static constexpr dart::compiler::target::word GrowableObjectArray_InstanceSize =
     16;
 static constexpr dart::compiler::target::word ICData_InstanceSize = 32;
+static constexpr dart::compiler::target::word ImageHeader_UnroundedSize = 20;
 static constexpr dart::compiler::target::word Instance_InstanceSize = 4;
 static constexpr dart::compiler::target::word Instructions_InstanceSize = 8;
 static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
@@ -3994,6 +4001,7 @@
 static constexpr dart::compiler::target::word GrowableObjectArray_InstanceSize =
     32;
 static constexpr dart::compiler::target::word ICData_InstanceSize = 56;
+static constexpr dart::compiler::target::word ImageHeader_UnroundedSize = 40;
 static constexpr dart::compiler::target::word Instance_InstanceSize = 8;
 static constexpr dart::compiler::target::word Instructions_InstanceSize = 12;
 static constexpr dart::compiler::target::word Instructions_UnalignedHeaderSize =
@@ -4542,6 +4550,8 @@
 static constexpr dart::compiler::target::word
     AOT_GrowableObjectArray_InstanceSize = 16;
 static constexpr dart::compiler::target::word AOT_ICData_InstanceSize = 24;
+static constexpr dart::compiler::target::word AOT_ImageHeader_UnroundedSize =
+    20;
 static constexpr dart::compiler::target::word AOT_Instance_InstanceSize = 4;
 static constexpr dart::compiler::target::word AOT_Instructions_InstanceSize = 8;
 static constexpr dart::compiler::target::word
@@ -5105,6 +5115,8 @@
 static constexpr dart::compiler::target::word
     AOT_GrowableObjectArray_InstanceSize = 32;
 static constexpr dart::compiler::target::word AOT_ICData_InstanceSize = 48;
+static constexpr dart::compiler::target::word AOT_ImageHeader_UnroundedSize =
+    40;
 static constexpr dart::compiler::target::word AOT_Instance_InstanceSize = 8;
 static constexpr dart::compiler::target::word AOT_Instructions_InstanceSize =
     12;
@@ -5673,6 +5685,8 @@
 static constexpr dart::compiler::target::word
     AOT_GrowableObjectArray_InstanceSize = 32;
 static constexpr dart::compiler::target::word AOT_ICData_InstanceSize = 48;
+static constexpr dart::compiler::target::word AOT_ImageHeader_UnroundedSize =
+    40;
 static constexpr dart::compiler::target::word AOT_Instance_InstanceSize = 8;
 static constexpr dart::compiler::target::word AOT_Instructions_InstanceSize =
     12;
@@ -6229,6 +6243,8 @@
 static constexpr dart::compiler::target::word
     AOT_GrowableObjectArray_InstanceSize = 16;
 static constexpr dart::compiler::target::word AOT_ICData_InstanceSize = 24;
+static constexpr dart::compiler::target::word AOT_ImageHeader_UnroundedSize =
+    20;
 static constexpr dart::compiler::target::word AOT_Instance_InstanceSize = 4;
 static constexpr dart::compiler::target::word AOT_Instructions_InstanceSize = 8;
 static constexpr dart::compiler::target::word
@@ -6785,6 +6801,8 @@
 static constexpr dart::compiler::target::word
     AOT_GrowableObjectArray_InstanceSize = 32;
 static constexpr dart::compiler::target::word AOT_ICData_InstanceSize = 48;
+static constexpr dart::compiler::target::word AOT_ImageHeader_UnroundedSize =
+    40;
 static constexpr dart::compiler::target::word AOT_Instance_InstanceSize = 8;
 static constexpr dart::compiler::target::word AOT_Instructions_InstanceSize =
     12;
@@ -7346,6 +7364,8 @@
 static constexpr dart::compiler::target::word
     AOT_GrowableObjectArray_InstanceSize = 32;
 static constexpr dart::compiler::target::word AOT_ICData_InstanceSize = 48;
+static constexpr dart::compiler::target::word AOT_ImageHeader_UnroundedSize =
+    40;
 static constexpr dart::compiler::target::word AOT_Instance_InstanceSize = 8;
 static constexpr dart::compiler::target::word AOT_Instructions_InstanceSize =
     12;
diff --git a/runtime/vm/compiler/runtime_offsets_list.h b/runtime/vm/compiler/runtime_offsets_list.h
index 6f1dcb6..01874c4 100644
--- a/runtime/vm/compiler/runtime_offsets_list.h
+++ b/runtime/vm/compiler/runtime_offsets_list.h
@@ -306,6 +306,7 @@
   SIZEOF(FutureOr, InstanceSize, FutureOrLayout)                               \
   SIZEOF(GrowableObjectArray, InstanceSize, GrowableObjectArrayLayout)         \
   SIZEOF(ICData, InstanceSize, ICDataLayout)                                   \
+  SIZEOF(ImageHeader, UnroundedSize, ImageHeaderLayout)                        \
   SIZEOF(Instance, InstanceSize, InstanceLayout)                               \
   SIZEOF(Instructions, InstanceSize, InstructionsLayout)                       \
   SIZEOF(Instructions, UnalignedHeaderSize, InstructionsLayout)                \
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 63ba037..e8bcf03 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -1928,16 +1928,6 @@
   Thread::ExitIsolate();
 }
 
-#if !defined(DART_PRECOMPILED_RUNTIME)
-static uint8_t* ApiReallocate(uint8_t* ptr,
-                              intptr_t old_size,
-                              intptr_t new_size) {
-  return Api::TopScope(Thread::Current())
-      ->zone()
-      ->Realloc<uint8_t>(ptr, old_size, new_size);
-}
-#endif
-
 DART_EXPORT Dart_Handle
 Dart_CreateSnapshot(uint8_t** vm_snapshot_data_buffer,
                     intptr_t* vm_snapshot_data_size,
@@ -1949,8 +1939,8 @@
   DARTSCOPE(Thread::Current());
   API_TIMELINE_DURATION(T);
   Isolate* I = T->isolate();
-  if (vm_snapshot_data_buffer != NULL && vm_snapshot_data_size == NULL) {
-    RETURN_NULL_ERROR(vm_snapshot_data_size);
+  if (vm_snapshot_data_buffer != nullptr) {
+    CHECK_NULL(vm_snapshot_data_size);
   }
   CHECK_NULL(isolate_snapshot_data_buffer);
   CHECK_NULL(isolate_snapshot_data_size);
@@ -1970,16 +1960,19 @@
   }
 #endif  // #if defined(DEBUG)
 
-  Symbols::Compact();
-
-  FullSnapshotWriter writer(Snapshot::kFull, vm_snapshot_data_buffer,
-                            isolate_snapshot_data_buffer, ApiReallocate,
-                            NULL /* vm_image_writer */,
-                            NULL /* isolate_image_writer */);
+  ZoneWriteStream vm_snapshot_data(Api::TopScope(T)->zone(),
+                                   FullSnapshotWriter::kInitialSize);
+  ZoneWriteStream isolate_snapshot_data(Api::TopScope(T)->zone(),
+                                        FullSnapshotWriter::kInitialSize);
+  FullSnapshotWriter writer(
+      Snapshot::kFull, &vm_snapshot_data, &isolate_snapshot_data,
+      nullptr /* vm_image_writer */, nullptr /* isolate_image_writer */);
   writer.WriteFullSnapshot();
-  if (vm_snapshot_data_buffer != NULL) {
+  if (vm_snapshot_data_buffer != nullptr) {
+    *vm_snapshot_data_buffer = vm_snapshot_data.buffer();
     *vm_snapshot_data_size = writer.VmIsolateSnapshotSize();
   }
+  *isolate_snapshot_data_buffer = isolate_snapshot_data.buffer();
   *isolate_snapshot_data_size = writer.IsolateSnapshotSize();
   return Api::Success();
 #endif
@@ -6546,12 +6539,13 @@
   CHECK_NULL(buffer);
   CHECK_NULL(buffer_length);
 
-  WriteStream stream(buffer, ApiReallocate, MB);
+  ZoneWriteStream stream(Api::TopScope(thread)->zone(), MB);
   TypeFeedbackSaver saver(&stream);
   saver.WriteHeader();
   saver.SaveClasses();
   saver.SaveFields();
   ProgramVisitor::WalkProgram(thread->zone(), thread->isolate(), &saver);
+  *buffer = stream.buffer();
   *buffer_length = stream.bytes_written();
 
   return Api::Success();
@@ -6648,6 +6642,7 @@
 
 // Used for StreamingWriteStream/BlobImageWriter sizes for ELF and blobs.
 #if !defined(TARGET_ARCH_IA32) && defined(DART_PRECOMPILER)
+static const intptr_t kAssemblyInitialSize = 512 * KB;
 static const intptr_t kInitialSize = 2 * MB;
 static const intptr_t kInitialDebugSize = 1 * MB;
 
@@ -6665,10 +6660,11 @@
   NOT_IN_PRODUCT(TimelineBeginEndScope tbes2(T, Timeline::GetIsolateStream(),
                                              "WriteAppAOTSnapshot"));
 
-  uint8_t* vm_snapshot_data_buffer = nullptr;
-  uint8_t* vm_snapshot_instructions_buffer = nullptr;
-  uint8_t* isolate_snapshot_data_buffer = nullptr;
-  uint8_t* isolate_snapshot_instructions_buffer = nullptr;
+  ZoneWriteStream vm_snapshot_data(T->zone(), FullSnapshotWriter::kInitialSize);
+  ZoneWriteStream vm_snapshot_instructions(T->zone(), kInitialSize);
+  ZoneWriteStream isolate_snapshot_data(T->zone(),
+                                        FullSnapshotWriter::kInitialSize);
+  ZoneWriteStream isolate_snapshot_instructions(T->zone(), kInitialSize);
 
   const bool generate_debug = debug_callback_data != nullptr;
 
@@ -6685,15 +6681,13 @@
                                      strip ? new (Z) Dwarf(Z) : dwarf)
                        : nullptr;
 
-    BlobImageWriter vm_image_writer(T, &vm_snapshot_instructions_buffer,
-                                    ApiReallocate, kInitialSize, debug_elf,
+    BlobImageWriter vm_image_writer(T, &vm_snapshot_instructions, debug_elf,
                                     elf);
-    BlobImageWriter isolate_image_writer(
-        T, &isolate_snapshot_instructions_buffer, ApiReallocate, kInitialSize,
-        debug_elf, elf);
-    FullSnapshotWriter writer(Snapshot::kFullAOT, &vm_snapshot_data_buffer,
-                              &isolate_snapshot_data_buffer, ApiReallocate,
-                              &vm_image_writer, &isolate_image_writer);
+    BlobImageWriter isolate_image_writer(T, &isolate_snapshot_instructions,
+                                         debug_elf, elf);
+    FullSnapshotWriter writer(Snapshot::kFullAOT, &vm_snapshot_data,
+                              &isolate_snapshot_data, &vm_image_writer,
+                              &isolate_image_writer);
 
     if (unit == nullptr || unit->id() == LoadingUnit::kRootId) {
       writer.WriteFullSnapshot(units);
@@ -6706,6 +6700,8 @@
       debug_elf->Finalize();
     }
   } else {
+    StreamingWriteStream assembly_stream(kAssemblyInitialSize, callback,
+                                         callback_data);
     StreamingWriteStream debug_stream(generate_debug ? kInitialDebugSize : 0,
                                       callback, debug_callback_data);
 
@@ -6714,12 +6710,10 @@
                                        new (Z) Dwarf(Z))
                          : nullptr;
 
-    AssemblyImageWriter image_writer(T, callback, callback_data, strip, elf);
-    uint8_t* vm_snapshot_data_buffer = NULL;
-    uint8_t* isolate_snapshot_data_buffer = NULL;
-    FullSnapshotWriter writer(Snapshot::kFullAOT, &vm_snapshot_data_buffer,
-                              &isolate_snapshot_data_buffer, ApiReallocate,
-                              &image_writer, &image_writer);
+    AssemblyImageWriter image_writer(T, &assembly_stream, strip, elf);
+    FullSnapshotWriter writer(Snapshot::kFullAOT, &vm_snapshot_data,
+                              &isolate_snapshot_data, &image_writer,
+                              &image_writer);
 
     if (unit == nullptr || unit->id() == LoadingUnit::kRootId) {
       writer.WriteFullSnapshot(units);
@@ -6849,10 +6843,12 @@
   CHECK_NULL(callback);
 
   TIMELINE_DURATION(T, Isolate, "WriteVMAOTSnapshot");
-  AssemblyImageWriter image_writer(T, callback, callback_data);
-  uint8_t* vm_snapshot_data_buffer = nullptr;
-  FullSnapshotWriter writer(Snapshot::kFullAOT, &vm_snapshot_data_buffer,
-                            nullptr, ApiReallocate, &image_writer, nullptr);
+  StreamingWriteStream assembly_stream(kAssemblyInitialSize, callback,
+                                       callback_data);
+  AssemblyImageWriter image_writer(T, &assembly_stream);
+  ZoneWriteStream vm_snapshot_data(T->zone(), FullSnapshotWriter::kInitialSize);
+  FullSnapshotWriter writer(Snapshot::kFullAOT, &vm_snapshot_data, nullptr,
+                            &image_writer, nullptr);
 
   writer.WriteFullSnapshot();
 
@@ -7021,24 +7017,34 @@
   DropRegExpMatchCode(Z);
 
   ProgramVisitor::Dedup(T);
-  Symbols::Compact();
 
   TIMELINE_DURATION(T, Isolate, "WriteCoreJITSnapshot");
-  BlobImageWriter vm_image_writer(T, vm_snapshot_instructions_buffer,
-                                  ApiReallocate, 2 * MB /* initial_size */);
-  BlobImageWriter isolate_image_writer(T, isolate_snapshot_instructions_buffer,
-                                       ApiReallocate,
-                                       2 * MB /* initial_size */);
-  FullSnapshotWriter writer(Snapshot::kFullJIT, vm_snapshot_data_buffer,
-                            isolate_snapshot_data_buffer, ApiReallocate,
-                            &vm_image_writer, &isolate_image_writer);
+  ZoneWriteStream vm_snapshot_data(Api::TopScope(T)->zone(),
+                                   FullSnapshotWriter::kInitialSize);
+  ZoneWriteStream vm_snapshot_instructions(Api::TopScope(T)->zone(),
+                                           FullSnapshotWriter::kInitialSize);
+  ZoneWriteStream isolate_snapshot_data(Api::TopScope(T)->zone(),
+                                        FullSnapshotWriter::kInitialSize);
+  ZoneWriteStream isolate_snapshot_instructions(
+      Api::TopScope(T)->zone(), FullSnapshotWriter::kInitialSize);
+
+  BlobImageWriter vm_image_writer(T, &vm_snapshot_instructions);
+  BlobImageWriter isolate_image_writer(T, &isolate_snapshot_instructions);
+  FullSnapshotWriter writer(Snapshot::kFullJIT, &vm_snapshot_data,
+                            &isolate_snapshot_data, &vm_image_writer,
+                            &isolate_image_writer);
   writer.WriteFullSnapshot();
 
-  *vm_snapshot_data_size = writer.VmIsolateSnapshotSize();
-  *vm_snapshot_instructions_size = vm_image_writer.InstructionsBlobSize();
-  *isolate_snapshot_data_size = writer.IsolateSnapshotSize();
+  *vm_snapshot_data_buffer = vm_snapshot_data.buffer();
+  *vm_snapshot_data_size = vm_snapshot_data.bytes_written();
+  *vm_snapshot_instructions_buffer = vm_snapshot_instructions.buffer();
+  *vm_snapshot_instructions_size = vm_snapshot_instructions.bytes_written();
+  *isolate_snapshot_data_buffer = isolate_snapshot_data.buffer();
+  *isolate_snapshot_data_size = isolate_snapshot_data.bytes_written();
+  *isolate_snapshot_instructions_buffer =
+      isolate_snapshot_instructions.buffer();
   *isolate_snapshot_instructions_size =
-      isolate_image_writer.InstructionsBlobSize();
+      isolate_snapshot_instructions.bytes_written();
 
   return Api::Success();
 #endif
@@ -7097,7 +7103,6 @@
   DropRegExpMatchCode(Z);
 
   ProgramVisitor::Dedup(T);
-  Symbols::Compact();
 
   if (FLAG_dump_tables) {
     Symbols::DumpTable(I);
@@ -7107,17 +7112,21 @@
   }
 
   TIMELINE_DURATION(T, Isolate, "WriteAppJITSnapshot");
-  BlobImageWriter isolate_image_writer(T, isolate_snapshot_instructions_buffer,
-                                       ApiReallocate,
-                                       2 * MB /* initial_size */);
-  FullSnapshotWriter writer(Snapshot::kFullJIT, NULL,
-                            isolate_snapshot_data_buffer, ApiReallocate, NULL,
-                            &isolate_image_writer);
+  ZoneWriteStream isolate_snapshot_data(Api::TopScope(T)->zone(),
+                                        FullSnapshotWriter::kInitialSize);
+  ZoneWriteStream isolate_snapshot_instructions(
+      Api::TopScope(T)->zone(), FullSnapshotWriter::kInitialSize);
+  BlobImageWriter isolate_image_writer(T, &isolate_snapshot_instructions);
+  FullSnapshotWriter writer(Snapshot::kFullJIT, nullptr, &isolate_snapshot_data,
+                            nullptr, &isolate_image_writer);
   writer.WriteFullSnapshot();
 
-  *isolate_snapshot_data_size = writer.IsolateSnapshotSize();
+  *isolate_snapshot_data_buffer = isolate_snapshot_data.buffer();
+  *isolate_snapshot_data_size = isolate_snapshot_data.bytes_written();
+  *isolate_snapshot_instructions_buffer =
+      isolate_snapshot_instructions.buffer();
   *isolate_snapshot_instructions_size =
-      isolate_image_writer.InstructionsBlobSize();
+      isolate_snapshot_instructions.bytes_written();
 
   return Api::Success();
 #endif
diff --git a/runtime/vm/dart_api_message.cc b/runtime/vm/dart_api_message.cc
index 613614e..bc83266 100644
--- a/runtime/vm/dart_api_message.cc
+++ b/runtime/vm/dart_api_message.cc
@@ -774,15 +774,8 @@
   return NULL;
 }
 
-static uint8_t* malloc_allocator(uint8_t* ptr,
-                                 intptr_t old_size,
-                                 intptr_t new_size) {
-  void* new_ptr = realloc(reinterpret_cast<void*>(ptr), new_size);
-  return reinterpret_cast<uint8_t*>(new_ptr);
-}
-
 ApiMessageWriter::ApiMessageWriter()
-    : BaseWriter(malloc_allocator, NULL, kInitialSize),
+    : BaseWriter(kInitialSize),
       object_id_(0),
       forward_list_(NULL),
       forward_list_length_(0),
@@ -1170,7 +1163,8 @@
   bool success = WriteCObject(object);
   if (!success) {
     UnmarkAllCObjects(object);
-    free(buffer());
+    intptr_t unused;
+    free(Steal(&unused));
     return nullptr;
   }
 
@@ -1181,16 +1175,18 @@
     success = WriteForwardedCObject(forward_list_[i]);
     if (!success) {
       UnmarkAllCObjects(object);
-      free(buffer());
+      intptr_t unused;
+      free(Steal(&unused));
       return nullptr;
     }
   }
 
   UnmarkAllCObjects(object);
   MessageFinalizableData* finalizable_data = finalizable_data_;
-  finalizable_data_ = NULL;
-  return Message::New(dest_port, buffer(), BytesWritten(), finalizable_data,
-                      priority);
+  finalizable_data_ = nullptr;
+  intptr_t size;
+  uint8_t* buffer = Steal(&size);
+  return Message::New(dest_port, buffer, size, finalizable_data, priority);
 }
 
 }  // namespace dart
diff --git a/runtime/vm/datastream.cc b/runtime/vm/datastream.cc
index de77937..a87cf46 100644
--- a/runtime/vm/datastream.cc
+++ b/runtime/vm/datastream.cc
@@ -3,19 +3,26 @@
 // BSD-style license that can be found in the LICENSE file.
 
 #include "vm/datastream.h"
+#include "vm/zone.h"
 
 namespace dart {
 
-StreamingWriteStream::StreamingWriteStream(intptr_t initial_capacity,
-                                           Dart_StreamingWriteCallback callback,
-                                           void* callback_data)
-    : flushed_size_(0), callback_(callback), callback_data_(callback_data) {
-  buffer_ = reinterpret_cast<uint8_t*>(malloc(initial_capacity));
-  if (buffer_ == NULL) {
-    OUT_OF_MEMORY();
-  }
-  cursor_ = buffer_;
-  limit_ = buffer_ + initial_capacity;
+MallocWriteStream::~MallocWriteStream() {
+  free(buffer_);
+}
+
+void MallocWriteStream::Realloc(intptr_t new_size) {
+  const intptr_t old_offset = current_ - buffer_;
+  buffer_ = reinterpret_cast<uint8_t*>(realloc(buffer_, new_size));
+  capacity_ = buffer_ != nullptr ? new_size : 0;
+  current_ = buffer_ != nullptr ? buffer_ + old_offset : nullptr;
+}
+
+void ZoneWriteStream::Realloc(intptr_t new_size) {
+  const intptr_t old_offset = current_ - buffer_;
+  buffer_ = zone_->Realloc(buffer_, capacity_, new_size);
+  capacity_ = buffer_ != nullptr ? new_size : 0;
+  current_ = buffer_ != nullptr ? buffer_ + old_offset : nullptr;
 }
 
 StreamingWriteStream::~StreamingWriteStream() {
@@ -23,46 +30,23 @@
   free(buffer_);
 }
 
-void StreamingWriteStream::VPrint(const char* format, va_list args) {
-  // Measure.
-  va_list measure_args;
-  va_copy(measure_args, args);
-  intptr_t len = Utils::VSNPrint(NULL, 0, format, measure_args);
-  va_end(measure_args);
-
-  // Alloc.
-  EnsureAvailable(len + 1);
-
-  // Print.
-  va_list print_args;
-  va_copy(print_args, args);
-  Utils::VSNPrint(reinterpret_cast<char*>(cursor_), len + 1, format,
-                  print_args);
-  va_end(print_args);
-  cursor_ += len;  // Not len + 1 to swallow the terminating NUL.
-}
-
-void StreamingWriteStream::EnsureAvailableSlowPath(intptr_t needed) {
+void StreamingWriteStream::Realloc(intptr_t new_size) {
   Flush();
-
-  intptr_t available = limit_ - cursor_;
-  if (available >= needed) return;
-
-  intptr_t new_capacity = Utils::RoundUp(needed, 64 * KB);
-  free(buffer_);
-  buffer_ = reinterpret_cast<uint8_t*>(malloc(new_capacity));
-  if (buffer_ == NULL) {
-    OUT_OF_MEMORY();
+  // Check whether resetting the internal buffer by flushing gave enough space.
+  if (new_size <= capacity_) {
+    return;
   }
-  cursor_ = buffer_;
-  limit_ = buffer_ + new_capacity;
+  const intptr_t new_capacity = Utils::RoundUp(new_size, 64 * KB);
+  buffer_ = reinterpret_cast<uint8_t*>(realloc(buffer_, new_capacity));
+  capacity_ = buffer_ != nullptr ? new_capacity : 0;
+  current_ = buffer_;  // Flushing reset the internal buffer offset to 0.
 }
 
 void StreamingWriteStream::Flush() {
-  intptr_t size = cursor_ - buffer_;
+  intptr_t size = current_ - buffer_;
   callback_(callback_data_, buffer_, size);
   flushed_size_ += size;
-  cursor_ = buffer_;
+  current_ = buffer_;
 }
 
 }  // namespace dart
diff --git a/runtime/vm/datastream.h b/runtime/vm/datastream.h
index a844493..39acb48 100644
--- a/runtime/vm/datastream.h
+++ b/runtime/vm/datastream.h
@@ -5,13 +5,13 @@
 #ifndef RUNTIME_VM_DATASTREAM_H_
 #define RUNTIME_VM_DATASTREAM_H_
 
-#include "include/dart_api.h"
 #include "platform/assert.h"
 #include "platform/utils.h"
 #include "vm/allocation.h"
 #include "vm/exceptions.h"
 #include "vm/globals.h"
 #include "vm/os.h"
+#include "vm/zone.h"
 
 namespace dart {
 
@@ -23,9 +23,6 @@
 static const uint8_t kEndByteMarker = (255 - kMaxDataPerByte);
 static const uint8_t kEndUnsignedByteMarker = (255 - kMaxUnsignedDataPerByte);
 
-typedef uint8_t* (*ReAlloc)(uint8_t* ptr, intptr_t old_size, intptr_t new_size);
-typedef void (*DeAlloc)(uint8_t* ptr);
-
 // Stream for reading various types from a buffer.
 class ReadStream : public ValueObject {
  public:
@@ -308,38 +305,23 @@
   DISALLOW_COPY_AND_ASSIGN(ReadStream);
 };
 
-// Stream for writing various types into a buffer.
-class WriteStream : public ValueObject {
+// Base class for streams that writing various types into a buffer, possibly
+// flushing data out periodically to a more permanent store.
+class BaseWriteStream : public ValueObject {
  public:
-  WriteStream(uint8_t** buffer, ReAlloc alloc, intptr_t initial_size)
-      : buffer_(buffer),
-        end_(NULL),
-        current_(NULL),
-        current_size_(0),
-        alloc_(alloc),
-        initial_size_(initial_size) {
-    ASSERT(buffer != NULL);
-    ASSERT(alloc != NULL);
-    *buffer_ = reinterpret_cast<uint8_t*>(alloc_(NULL, 0, initial_size_));
-    if (*buffer_ == NULL) {
-      Exceptions::ThrowOOM();
-    }
-    current_ = *buffer_;
-    current_size_ = initial_size_;
-    end_ = *buffer_ + initial_size_;
-  }
+  explicit BaseWriteStream(intptr_t initial_size)
+      : initial_size_(Utils::RoundUpToPowerOfTwo(initial_size)) {}
+  virtual ~BaseWriteStream() {}
 
-  uint8_t* buffer() const { return *buffer_; }
-  void set_buffer(uint8_t* value) { *buffer_ = value; }
-  intptr_t bytes_written() const { return current_ - *buffer_; }
-
-  intptr_t Position() const { return current_ - *buffer_; }
-  void SetPosition(intptr_t value) { current_ = *buffer_ + value; }
+  DART_FORCE_INLINE intptr_t bytes_written() const { return Position(); }
+  virtual intptr_t Position() const { return current_ - buffer_; }
 
   void Align(intptr_t alignment) {
-    intptr_t position_before = Position();
-    intptr_t position_after = Utils::RoundUp(position_before, alignment);
-    memset(current_, 0, position_after - position_before);
+    const intptr_t position_before = Position();
+    const intptr_t position_after = Utils::RoundUp(position_before, alignment);
+    const intptr_t length = position_after - position_before;
+    EnsureSpace(length);
+    memset(current_, 0, length);
     SetPosition(position_after);
   }
 
@@ -349,7 +331,7 @@
   template <typename T>
   class Raw<1, T> {
    public:
-    static void Write(WriteStream* st, T value) {
+    static void Write(BaseWriteStream* st, T value) {
       st->WriteByte(bit_cast<int8_t>(value));
     }
   };
@@ -357,7 +339,7 @@
   template <typename T>
   class Raw<2, T> {
    public:
-    static void Write(WriteStream* st, T value) {
+    static void Write(BaseWriteStream* st, T value) {
       st->Write<int16_t>(bit_cast<int16_t>(value));
     }
   };
@@ -365,7 +347,7 @@
   template <typename T>
   class Raw<4, T> {
    public:
-    static void Write(WriteStream* st, T value) {
+    static void Write(BaseWriteStream* st, T value) {
       st->Write<int32_t>(bit_cast<int32_t>(value));
     }
   };
@@ -373,7 +355,7 @@
   template <typename T>
   class Raw<8, T> {
    public:
-    static void Write(WriteStream* st, T value) {
+    static void Write(BaseWriteStream* st, T value) {
       st->Write<int64_t>(bit_cast<int64_t>(value));
     }
   };
@@ -401,10 +383,7 @@
   }
 
   void WriteBytes(const void* addr, intptr_t len) {
-    if ((end_ - current_) < len) {
-      Resize(len);
-    }
-    ASSERT((end_ - current_) >= len);
+    EnsureSpace(len);
     if (len != 0) {
       memmove(current_, addr, len);
     }
@@ -413,10 +392,7 @@
 
   void WriteWord(uword value) {
     const intptr_t len = sizeof(uword);
-    if ((end_ - current_) < len) {
-      Resize(len);
-    }
-    ASSERT((end_ - current_) >= len);
+    EnsureSpace(len);
     *reinterpret_cast<uword*>(current_) = value;
     current_ += len;
   }
@@ -425,10 +401,7 @@
 #if defined(IS_SIMARM_X64)
     RELEASE_ASSERT(Utils::IsInt(32, static_cast<word>(value)));
     const intptr_t len = sizeof(uint32_t);
-    if ((end_ - current_) < len) {
-      Resize(len);
-    }
-    ASSERT((end_ - current_) >= len);
+    EnsureSpace(len);
     *reinterpret_cast<uint32_t*>(current_) = static_cast<uint32_t>(value);
     current_ += len;
 #else   // defined(IS_SIMARM_X64)
@@ -451,10 +424,7 @@
     va_end(measure_args);
 
     // Alloc.
-    if ((end_ - current_) < (len + 1)) {
-      Resize(len + 1);
-    }
-    ASSERT((end_ - current_) >= (len + 1));
+    EnsureSpace(len + 1);
 
     // Print.
     va_list print_args;
@@ -478,101 +448,161 @@
   template <typename T>
   void WriteFixed(T value) {
     const intptr_t len = sizeof(T);
-    if ((end_ - current_) < len) {
-      Resize(len);
-    }
-    ASSERT((end_ - current_) >= len);
+    EnsureSpace(len);
     *reinterpret_cast<T*>(current_) = static_cast<T>(value);
     current_ += len;
   }
 
- private:
+ protected:
   DART_FORCE_INLINE void WriteByte(uint8_t value) {
-    if (current_ >= end_) {
-      Resize(1);
-    }
-    ASSERT(current_ < end_);
+    EnsureSpace(1);
     *current_++ = value;
   }
 
-  void Resize(intptr_t size_needed) {
-    intptr_t position = current_ - *buffer_;
-    intptr_t increment_size = current_size_;
+  void EnsureSpace(intptr_t size_needed) {
+    if (Remaining() >= size_needed) return;
+    intptr_t increment_size = capacity_;
     if (size_needed > increment_size) {
       increment_size = Utils::RoundUp(size_needed, initial_size_);
     }
-    intptr_t new_size = current_size_ + increment_size;
-    ASSERT(new_size > current_size_);
-    *buffer_ =
-        reinterpret_cast<uint8_t*>(alloc_(*buffer_, current_size_, new_size));
-    if (*buffer_ == NULL) {
+    intptr_t new_size = capacity_ + increment_size;
+    ASSERT(new_size > capacity_);
+    Realloc(new_size);
+    if (buffer_ == nullptr) {
       Exceptions::ThrowOOM();
     }
-    current_ = *buffer_ + position;
-    current_size_ = new_size;
-    end_ = *buffer_ + new_size;
-    ASSERT(end_ > *buffer_);
+    ASSERT(Remaining() >= size_needed);
+  }
+
+  virtual void SetPosition(intptr_t value) {
+    EnsureSpace(value - BaseWriteStream::Position());
+    current_ = buffer_ + value;
+  }
+
+  DART_FORCE_INLINE intptr_t Remaining() const {
+    return capacity_ - BaseWriteStream::Position();
+  }
+
+  // Resizes the internal buffer to the requested new capacity. Should set
+  // buffer_, capacity_, and current_ appropriately.
+  //
+  // Instead of templating over an Allocator (which would then cause users
+  // of the templated class to need to be templated, etc.), we just add an
+  // Realloc method to override appropriately in subclasses. Less flexible,
+  // but requires less changes throughout the codebase.
+  virtual void Realloc(intptr_t new_capacity) = 0;
+
+  const intptr_t initial_size_;
+  uint8_t* buffer_ = nullptr;
+  uint8_t* current_ = nullptr;
+  intptr_t capacity_ = 0;
+
+  DISALLOW_COPY_AND_ASSIGN(BaseWriteStream);
+};
+
+// A base class for non-streaming write streams. Since these streams are
+// not flushed periodically, the internal buffer contains all written data
+// and can be retrieved via buffer(). NonStreamingWriteStream also provides
+// SetPosition as part of its public API for non-sequential writing.
+class NonStreamingWriteStream : public BaseWriteStream {
+ public:
+  explicit NonStreamingWriteStream(intptr_t initial_size)
+      : BaseWriteStream(initial_size) {}
+
+ public:
+  uint8_t* buffer() const { return buffer_; }
+
+  // Sets the position of the buffer
+  DART_FORCE_INLINE void SetPosition(intptr_t value) {
+    BaseWriteStream::SetPosition(value);
+  }
+};
+
+// A non-streaming write stream that uses realloc for reallocation, and frees
+// the buffer when destructed unless ownership is transfered using Steal().
+class MallocWriteStream : public NonStreamingWriteStream {
+ public:
+  explicit MallocWriteStream(intptr_t initial_size)
+      : NonStreamingWriteStream(initial_size) {
+    // Go ahead and allocate initial space at construction.
+    EnsureSpace(initial_size_);
+  }
+  ~MallocWriteStream();
+
+  // Resets the stream and returns the original buffer, which is now considered
+  // owned by the caller. Sets [*length] to the length of the returned buffer.
+  uint8_t* Steal(intptr_t* length) {
+    ASSERT(length != nullptr);
+    *length = bytes_written();
+    uint8_t* const old_buffer = buffer_;
+    // We don't immediately reallocate a new space just in case this steal
+    // is the last use of this stream.
+    current_ = buffer_ = nullptr;
+    capacity_ = 0;
+    return old_buffer;
   }
 
  private:
-  uint8_t** const buffer_;
-  uint8_t* end_;
-  uint8_t* current_;
-  intptr_t current_size_;
-  ReAlloc alloc_;
-  intptr_t initial_size_;
+  virtual void Realloc(intptr_t new_size);
 
-  DISALLOW_COPY_AND_ASSIGN(WriteStream);
+  DISALLOW_COPY_AND_ASSIGN(MallocWriteStream);
 };
 
-class StreamingWriteStream : public ValueObject {
+// A non-streaming write stream that uses a zone for reallocation.
+class ZoneWriteStream : public NonStreamingWriteStream {
+ public:
+  ZoneWriteStream(Zone* zone, intptr_t initial_size)
+      : NonStreamingWriteStream(initial_size), zone_(zone) {
+    // Go ahead and allocate initial space at construction.
+    EnsureSpace(initial_size_);
+  }
+
+ private:
+  virtual void Realloc(intptr_t new_size);
+
+  Zone* const zone_;
+
+  DISALLOW_COPY_AND_ASSIGN(ZoneWriteStream);
+};
+
+// A streaming write stream that uses the internal buffer only for non-flushed
+// data. Like MallocWriteStream, uses realloc for reallocation, and flushes and
+// frees the internal buffer when destructed. Since part or all of the written
+// data may be flushed and no longer in the internal buffer, it does not provide
+// a way to retrieve the written contents.
+class StreamingWriteStream : public BaseWriteStream {
  public:
   explicit StreamingWriteStream(intptr_t initial_capacity,
                                 Dart_StreamingWriteCallback callback,
-                                void* callback_data);
+                                void* callback_data)
+      : BaseWriteStream(initial_capacity),
+        callback_(callback),
+        callback_data_(callback_data) {
+    // Go ahead and allocate initial space at construction.
+    EnsureSpace(initial_capacity);
+  }
   ~StreamingWriteStream();
 
-  intptr_t position() const { return flushed_size_ + (cursor_ - buffer_); }
-
-  void Align(intptr_t alignment) {
-    intptr_t padding = Utils::RoundUp(position(), alignment) - position();
-    EnsureAvailable(padding);
-    memset(cursor_, 0, padding);
-    cursor_ += padding;
-  }
-
-  void Print(const char* format, ...) {
-    va_list args;
-    va_start(args, format);
-    VPrint(format, args);
-    va_end(args);
-  }
-  void VPrint(const char* format, va_list args);
-
-  void WriteBytes(const uint8_t* buffer, intptr_t size) {
-    EnsureAvailable(size);
-    if (size != 0) {
-      memmove(cursor_, buffer, size);
-    }
-    cursor_ += size;
-  }
-
  private:
-  void EnsureAvailable(intptr_t needed) {
-    intptr_t available = limit_ - cursor_;
-    if (available >= needed) return;
-    EnsureAvailableSlowPath(needed);
+  // Flushes any unflushed data to callback_data and resets the internal
+  // buffer. Changes current_ and flushed_size_ accordingly.
+  virtual void Flush();
+
+  virtual void Realloc(intptr_t new_size);
+
+  virtual intptr_t Position() const {
+    return flushed_size_ + BaseWriteStream::Position();
   }
 
-  void EnsureAvailableSlowPath(intptr_t needed);
-  void Flush();
+  virtual void SetPosition(intptr_t value) {
+    // Make sure we're not trying to set the position to already-flushed data.
+    ASSERT(value >= flushed_size_);
+    BaseWriteStream::SetPosition(value - flushed_size_);
+  }
 
-  uint8_t* buffer_;
-  uint8_t* cursor_;
-  uint8_t* limit_;
-  intptr_t flushed_size_;
-  Dart_StreamingWriteCallback callback_;
-  void* callback_data_;
+  const Dart_StreamingWriteCallback callback_;
+  void* const callback_data_;
+  intptr_t flushed_size_ = 0;
 
   DISALLOW_COPY_AND_ASSIGN(StreamingWriteStream);
 };
diff --git a/runtime/vm/deopt_instructions.cc b/runtime/vm/deopt_instructions.cc
index 360929b..f194067 100644
--- a/runtime/vm/deopt_instructions.cc
+++ b/runtime/vm/deopt_instructions.cc
@@ -1231,12 +1231,6 @@
   return -1;
 }
 
-static uint8_t* ZoneReAlloc(uint8_t* ptr,
-                            intptr_t old_size,
-                            intptr_t new_size) {
-  return Thread::Current()->zone()->Realloc<uint8_t>(ptr, old_size, new_size);
-}
-
 TypedDataPtr DeoptInfoBuilder::CreateDeoptInfo(const Array& deopt_table) {
   intptr_t length = instructions_.length();
 
@@ -1260,9 +1254,8 @@
     length -= (suffix_length - 1);
   }
 
-  uint8_t* buffer;
-  typedef WriteStream::Raw<sizeof(intptr_t), intptr_t> Writer;
-  WriteStream stream(&buffer, ZoneReAlloc, 2 * length * kWordSize);
+  typedef ZoneWriteStream::Raw<sizeof(intptr_t), intptr_t> Writer;
+  ZoneWriteStream stream(zone(), 2 * length * kWordSize);
 
   Writer::Write(&stream, FrameSize());
 
diff --git a/runtime/vm/elf.cc b/runtime/vm/elf.cc
index 606ef61..9d08ce5 100644
--- a/runtime/vm/elf.cc
+++ b/runtime/vm/elf.cc
@@ -14,14 +14,14 @@
 
 namespace dart {
 
-// A wrapper around StreamingWriteStream that provides methods useful for
+// A wrapper around BaseWriteStream that provides methods useful for
 // writing ELF files (e.g., using ELF definitions of data sizes).
 class ElfWriteStream : public ValueObject {
  public:
-  explicit ElfWriteStream(StreamingWriteStream* stream)
+  explicit ElfWriteStream(BaseWriteStream* stream)
       : stream_(ASSERT_NOTNULL(stream)) {}
 
-  intptr_t position() const { return stream_->position(); }
+  intptr_t position() const { return stream_->Position(); }
   void Align(const intptr_t alignment) {
     ASSERT(Utils::IsPowerOfTwo(alignment));
     stream_->Align(alignment);
@@ -51,7 +51,7 @@
 #endif
 
  private:
-  StreamingWriteStream* const stream_;
+  BaseWriteStream* const stream_;
 };
 
 static constexpr intptr_t kLinearInitValue = -1;
@@ -127,7 +127,7 @@
   FOR_EACH_SEGMENT_LINEAR_FIELD(DEFINE_LINEAR_FIELD_METHODS);
 
   // Each section belongs to at most one PT_LOAD segment.
-  const Segment* load_segment = nullptr;
+  Segment* load_segment = nullptr;
 
   virtual intptr_t MemorySize() const = 0;
 
@@ -234,6 +234,9 @@
     // a memory offset since we use it to determine the segment memory offset.
     ASSERT(initial_section->IsAllocated());
     ASSERT(initial_section->memory_offset_is_set());
+    // Make sure the memory offset chosen for the initial section is consistent
+    // with the alignment for the segment.
+    ASSERT(Utils::IsAligned(initial_section->memory_offset(), Alignment(type)));
     sections_.Add(initial_section);
     if (type == elf::ProgramHeaderType::PT_LOAD) {
       ASSERT(initial_section->load_segment == nullptr);
@@ -245,6 +248,7 @@
 
   static intptr_t Alignment(elf::ProgramHeaderType segment_type) {
     switch (segment_type) {
+      case elf::ProgramHeaderType::PT_PHDR:
       case elf::ProgramHeaderType::PT_DYNAMIC:
         return compiler::target::kWordSize;
       case elf::ProgramHeaderType::PT_NOTE:
@@ -319,6 +323,30 @@
     return true;
   }
 
+  void Replace(Section* old_section, Section* new_section) {
+    ASSERT(old_section->load_segment == this);
+    // All these must be true for replacement to be safe.
+    ASSERT_EQUAL(static_cast<uint32_t>(old_section->type),
+                 static_cast<uint32_t>(new_section->type));
+    ASSERT_EQUAL(old_section->MemorySize(), new_section->MemorySize());
+    ASSERT_EQUAL(old_section->IsExecutable(), new_section->IsExecutable());
+    ASSERT_EQUAL(old_section->IsWritable(), new_section->IsWritable());
+    ASSERT(old_section->memory_offset_is_set());
+    ASSERT(!new_section->memory_offset_is_set());
+    for (intptr_t i = 0; i < sections_.length(); i++) {
+      auto const section = sections_[i];
+      if (section != old_section) {
+        continue;
+      }
+      new_section->set_memory_offset(old_section->memory_offset());
+      sections_[i] = new_section;
+      new_section->load_segment = this;
+      old_section->load_segment = nullptr;
+      return;
+    }
+    UNREACHABLE();
+  }
+
   intptr_t FileOffset() const { return sections_[0]->file_offset(); }
 
   intptr_t FileSize() const {
@@ -792,6 +820,7 @@
   }
 };
 
+// We assume that the final program table fits in a single page of memory.
 static const intptr_t kProgramTableSegmentSize = Elf::kPageSize;
 
 // Here, both VM and isolate will be compiled into a single snapshot.
@@ -806,7 +835,7 @@
 static const intptr_t kBssSize =
     kBssIsolateOffset + BSS::kIsolateEntryCount * compiler::target::kWordSize;
 
-Elf::Elf(Zone* zone, StreamingWriteStream* stream, Type type, Dwarf* dwarf)
+Elf::Elf(Zone* zone, BaseWriteStream* stream, Type type, Dwarf* dwarf)
     : zone_(zone),
       unwrapped_stream_(stream),
       type_(type),
@@ -818,7 +847,7 @@
   // Separate debugging information should always have a Dwarf object.
   ASSERT(type_ == Type::Snapshot || dwarf_ != nullptr);
   // Assumed by various offset logic in this file.
-  ASSERT_EQUAL(unwrapped_stream_->position(), 0);
+  ASSERT_EQUAL(unwrapped_stream_->Position(), 0);
   // The first section in the section header table is always a reserved
   // entry containing only 0 values.
   sections_.Add(new (zone_) ReservedSection());
@@ -834,9 +863,20 @@
   auto const start_segment =
       new (zone_) ProgramTableLoadSegment(zone_, kProgramTableSegmentSize);
   segments_.Add(start_segment);
-  // Note that the BSS segment must be the first user-defined segment because
+  // We allocate an initial build ID of all zeroes, since we need the build ID
+  // memory offset during ImageHeader creation (see BlobImageWriter::WriteText).
+  // We replace it with the real build ID during finalization. (We add this
+  // prior to BSS because we make the BuildID section writable also, so they are
+  // placed in the same segment before any non-writable ones, and if we add it
+  // after, then in separate debugging information, it'll go into a separate
+  // segment because the BSS section for debugging info is NOBITS.)
+  build_id_ = GenerateBuildId();
+  AddSection(build_id_, kBuildIdNoteName, kSnapshotBuildIdAsmSymbol);
+  // Note that the BSS segment must be in the first user-defined segment because
   // it cannot be placed in between any two non-writable segments, due to a bug
-  // in Jelly Bean's ELF loader. See also Elf::WriteProgramTable().
+  // in Jelly Bean's ELF loader. (For this reason, the program table segments
+  // generated during finalization are marked as writable.) See also
+  // Elf::WriteProgramTable().
   //
   // We add it in all cases, even to the separate debugging information ELF,
   // to ensure that relocated addresses are consistent between ELF snapshots
@@ -844,8 +884,14 @@
   AddSection(bss_, ".bss", kSnapshotBssAsmSymbol);
 }
 
-intptr_t Elf::NextMemoryOffset() const {
-  return Utils::RoundUp(LastLoadSegment()->MemoryEnd(), Elf::kPageSize);
+intptr_t Elf::NextMemoryOffset(intptr_t alignment) const {
+  // Without more information, we won't know whether we might create a new
+  // segment or put the section into the current one. Thus, for now, only allow
+  // the offset to be queried ahead of time if it matches the load segment
+  // alignment.
+  auto const type = elf::ProgramHeaderType::PT_LOAD;
+  ASSERT_EQUAL(alignment, Segment::Alignment(type));
+  return Utils::RoundUp(LastLoadSegment()->MemoryEnd(), alignment);
 }
 
 uword Elf::BssStart(bool vm) const {
@@ -870,8 +916,10 @@
     // We can't add this section to the last load segment, so create a new one.
     // The new segment starts at the next aligned address.
     auto const type = elf::ProgramHeaderType::PT_LOAD;
+    intptr_t alignment =
+        Utils::Maximum(section->alignment, Segment::Alignment(type));
     auto const start_address =
-        Utils::RoundUp(last_load->MemoryEnd(), Segment::Alignment(type));
+        Utils::RoundUp(last_load->MemoryEnd(), alignment);
     section->set_memory_offset(start_address);
     auto const segment = new (zone_) Segment(zone_, section, type);
     segments_.Add(segment);
@@ -882,13 +930,31 @@
   return section->memory_offset();
 }
 
+void Elf::ReplaceSection(Section* old_section, Section* new_section) {
+  ASSERT(section_table_file_size_ < 0);
+  ASSERT(old_section->index_is_set());
+  ASSERT(!new_section->index_is_set());
+  ASSERT_EQUAL(new_section->IsAllocated(), old_section->IsAllocated());
+  new_section->set_name(old_section->name());
+  new_section->set_index(old_section->index());
+  sections_[old_section->index()] = new_section;
+
+  if (!old_section->IsAllocated()) {
+    return;
+  }
+
+  ASSERT(program_table_file_size_ < 0);
+  ASSERT(old_section->load_segment != nullptr);
+  old_section->load_segment->Replace(old_section, new_section);
+}
+
 intptr_t Elf::AddText(const char* name, const uint8_t* bytes, intptr_t size) {
   // When making a separate debugging info file for assembly, we don't have
   // the binary text segment contents.
   ASSERT(type_ == Type::DebugInfo || bytes != nullptr);
-  auto const image = new (zone_)
-      BitsContainer(type_, /*executable=*/true,
-                    /*writable=*/false, size, bytes, Elf::kPageSize);
+  auto const image = new (zone_) BitsContainer(type_, /*executable=*/true,
+                                               /*writable=*/false, size, bytes,
+                                               ImageWriter::kTextAlignment);
   return AddSection(image, ".text", name);
 }
 
@@ -904,14 +970,14 @@
     memset(bytes, 0, size);
   }
   return new (zone) BitsContainer(type, /*executable=*/false, /*writable=*/true,
-                                  kBssSize, bytes, Image::kBssAlignment);
+                                  kBssSize, bytes, ImageWriter::kBssAlignment);
 }
 
 intptr_t Elf::AddROData(const char* name, const uint8_t* bytes, intptr_t size) {
   ASSERT(bytes != nullptr);
-  auto const image = new (zone_)
-      BitsContainer(type_, /*executable=*/false,
-                    /*writable=*/false, size, bytes, kMaxObjectAlignment);
+  auto const image = new (zone_) BitsContainer(type_, /*executable=*/false,
+                                               /*writable=*/false, size, bytes,
+                                               ImageWriter::kRODataAlignment);
   return AddSection(image, ".rodata", name);
 }
 
@@ -956,9 +1022,9 @@
 class DwarfElfStream : public DwarfWriteStream {
  public:
   explicit DwarfElfStream(Zone* zone,
-                          WriteStream* stream,
+                          NonStreamingWriteStream* stream,
                           const CStringMap<intptr_t>& address_map)
-      : zone_(zone),
+      : zone_(ASSERT_NOTNULL(zone)),
         stream_(ASSERT_NOTNULL(stream)),
         address_map_(address_map) {}
 
@@ -1012,8 +1078,11 @@
     return fixup;
   }
   void SetSize(intptr_t fixup, const char* prefix, intptr_t start) {
-    const uint32_t value = position() - start;
-    memmove(stream_->buffer() + fixup, &value, sizeof(value));
+    const intptr_t old_position = position();
+    stream_->SetPosition(fixup);
+    const uint32_t value = old_position - start;
+    stream_->WriteBytes(&value, sizeof(value));
+    stream_->SetPosition(old_position);
   }
   void OffsetFromSymbol(const char* symbol, intptr_t offset) {
     auto const address = address_map_.LookupValue(symbol);
@@ -1053,7 +1122,7 @@
   }
 
   Zone* const zone_;
-  WriteStream* const stream_;
+  NonStreamingWriteStream* const stream_;
   const CStringMap<intptr_t>& address_map_;
   uint32_t* abstract_origins_ = nullptr;
   intptr_t abstract_origins_size_ = -1;
@@ -1064,10 +1133,6 @@
 static constexpr intptr_t kInitialDwarfBufferSize = 64 * KB;
 #endif
 
-static uint8_t* ZoneReallocate(uint8_t* ptr, intptr_t len, intptr_t new_len) {
-  return Thread::Current()->zone()->Realloc<uint8_t>(ptr, len, new_len);
-}
-
 Segment* Elf::LastLoadSegment() const {
   for (intptr_t i = segments_.length() - 1; i >= 0; i--) {
     auto const segment = segments_.At(i);
@@ -1155,27 +1220,24 @@
   // provide unwinding information.
 
   {
-    uint8_t* buffer = nullptr;
-    WriteStream stream(&buffer, ZoneReallocate, kInitialDwarfBufferSize);
+    ZoneWriteStream stream(zone(), kInitialDwarfBufferSize);
     DwarfElfStream dwarf_stream(zone_, &stream, symbol_to_address_map);
     dwarf_->WriteAbbreviations(&dwarf_stream);
-    AddDebug(".debug_abbrev", buffer, stream.bytes_written());
+    AddDebug(".debug_abbrev", stream.buffer(), stream.bytes_written());
   }
 
   {
-    uint8_t* buffer = nullptr;
-    WriteStream stream(&buffer, ZoneReallocate, kInitialDwarfBufferSize);
+    ZoneWriteStream stream(zone(), kInitialDwarfBufferSize);
     DwarfElfStream dwarf_stream(zone_, &stream, symbol_to_address_map);
     dwarf_->WriteDebugInfo(&dwarf_stream);
-    AddDebug(".debug_info", buffer, stream.bytes_written());
+    AddDebug(".debug_info", stream.buffer(), stream.bytes_written());
   }
 
   {
-    uint8_t* buffer = nullptr;
-    WriteStream stream(&buffer, ZoneReallocate, kInitialDwarfBufferSize);
+    ZoneWriteStream stream(zone(), kInitialDwarfBufferSize);
     DwarfElfStream dwarf_stream(zone_, &stream, symbol_to_address_map);
     dwarf_->WriteLineNumberProgram(&dwarf_stream);
-    AddDebug(".debug_line", buffer, stream.bytes_written());
+    AddDebug(".debug_line", stream.buffer(), stream.bytes_written());
   }
 #endif
 }
@@ -1189,11 +1251,11 @@
   // without changing how we add the .text and .rodata sections (since we
   // determine memory offsets for those sections when we add them, and the
   // text sections must have the memory offsets to do BSS relocations).
-  if (auto const build_id = GenerateBuildId()) {
-    AddSection(build_id, ".note.gnu.build-id", kSnapshotBuildIdAsmSymbol);
+  if (auto const new_build_id = GenerateBuildId()) {
+    ReplaceSection(build_id_, new_build_id);
 
     // Add a PT_NOTE segment for the build ID.
-    segments_.Add(new (zone_) NoteSegment(zone_, build_id));
+    segments_.Add(new (zone_) NoteSegment(zone_, new_build_id));
   }
 
   // Adding the dynamic symbol table and associated sections.
@@ -1291,9 +1353,15 @@
   return FinalizeHash(hash, 32);
 }
 
+uword Elf::BuildIdStart(intptr_t* size) {
+  ASSERT(size != nullptr);
+  ASSERT(build_id_ != nullptr);
+  *size = kBuildIdDescriptionLength;
+  return build_id_->memory_offset() + kBuildIdDescriptionOffset;
+}
+
 Section* Elf::GenerateBuildId() {
-  uint8_t* notes_buffer = nullptr;
-  WriteStream stream(&notes_buffer, ZoneReallocate, kBuildIdSize);
+  ZoneWriteStream stream(zone(), kBuildIdSize);
   stream.WriteFixed(kBuildIdNameLength);
   stream.WriteFixed(kBuildIdDescriptionLength);
   stream.WriteFixed(static_cast<uint32_t>(elf::NoteType::NT_GNU_BUILD_ID));
@@ -1319,9 +1387,15 @@
   }
   ASSERT_EQUAL(stream.bytes_written() - description_start,
                kBuildIdDescriptionLength);
-  return new (zone_) BitsContainer(
-      elf::SectionHeaderType::SHT_NOTE, /*allocate=*/true, /*executable=*/false,
-      /*writable=*/false, stream.bytes_written(), notes_buffer, kNoteAlignment);
+  ASSERT_EQUAL(stream.bytes_written(), kBuildIdSize);
+  // While the build ID section does not need to be writable, it and the
+  // BSS section are allocated segments at the same time. Having the same flags
+  // ensures they will be combined in the same segment and not unnecessarily
+  // aligned into a new page.
+  return new (zone_) BitsContainer(elf::SectionHeaderType::SHT_NOTE,
+                                   /*allocate=*/true, /*executable=*/false,
+                                   /*writable=*/true, stream.bytes_written(),
+                                   stream.buffer(), kNoteAlignment);
 }
 
 void Elf::FinalizeProgramTable() {
diff --git a/runtime/vm/elf.h b/runtime/vm/elf.h
index da0af3c..37b2fc8 100644
--- a/runtime/vm/elf.h
+++ b/runtime/vm/elf.h
@@ -30,12 +30,9 @@
     DebugInfo,
   };
 
-  Elf(Zone* zone,
-      StreamingWriteStream* stream,
-      Type type,
-      Dwarf* dwarf = nullptr);
+  Elf(Zone* zone, BaseWriteStream* stream, Type type, Dwarf* dwarf = nullptr);
 
-  static const intptr_t kPageSize = 4096;
+  static constexpr intptr_t kPageSize = 4096;
 
   bool IsStripped() const { return dwarf_ == nullptr; }
 
@@ -44,13 +41,13 @@
   Dwarf* dwarf() { return dwarf_; }
 
   uword BssStart(bool vm) const;
+  uword BuildIdStart(intptr_t* size);
 
-  // What the next memory offset for a kPageSize-aligned section would be.
+  // What the next memory offset for an appropriately aligned section would be.
   //
   // Only used by BlobImageWriter::WriteText() to determine the memory offset
   // for the text section before it is added.
-  intptr_t NextMemoryOffset() const;
-  intptr_t AddNoBits(const char* name, const uint8_t* bytes, intptr_t size);
+  intptr_t NextMemoryOffset(intptr_t alignment) const;
   intptr_t AddText(const char* name, const uint8_t* bytes, intptr_t size);
   intptr_t AddROData(const char* name, const uint8_t* bytes, intptr_t size);
   void AddDebug(const char* name, const uint8_t* bytes, intptr_t size);
@@ -58,6 +55,8 @@
   void Finalize();
 
  private:
+  static constexpr const char* kBuildIdNoteName = ".note.gnu.build-id";
+
   static Section* CreateBSS(Zone* zone, Type type, intptr_t size);
 
   // Adds the section and also creates a PT_LOAD segment for the section if it
@@ -71,6 +70,11 @@
   intptr_t AddSection(Section* section,
                       const char* name,
                       const char* symbol_name = nullptr);
+  // Replaces [old_section] with [new_section] in all appropriate places. If the
+  // section is allocated, the memory size of the section must be the same as
+  // the original to ensure any already-calculated memory offsets are unchanged.
+  void ReplaceSection(Section* old_section, Section* new_section);
+
   void AddStaticSymbol(const char* name,
                        intptr_t info,
                        intptr_t section_index,
@@ -97,7 +101,7 @@
   void WriteSections(ElfWriteStream* stream);
 
   Zone* const zone_;
-  StreamingWriteStream* const unwrapped_stream_;
+  BaseWriteStream* const unwrapped_stream_;
   const Type type_;
 
   // If nullptr, then the ELF file should be stripped of static information like
@@ -118,6 +122,12 @@
   StringTable* strtab_ = nullptr;
   SymbolTable* symtab_ = nullptr;
 
+  // We always create a GNU build ID for all Elf files. In order to create
+  // the appropriate offset to it in an ImageHeader object, we create an
+  // initial build ID section as a placeholder and then replace that section
+  // during finalization once we have the information to calculate the real one.
+  Section* build_id_;
+
   GrowableArray<Section*> sections_;
   GrowableArray<Segment*> segments_;
   intptr_t memory_offset_;
diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc
index 3bcb484..142c890 100644
--- a/runtime/vm/exceptions.cc
+++ b/runtime/vm/exceptions.cc
@@ -384,8 +384,8 @@
 }
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
-void CatchEntryMove::WriteTo(WriteStream* stream) {
-  using Writer = WriteStream::Raw<sizeof(int32_t), int32_t>;
+void CatchEntryMove::WriteTo(BaseWriteStream* stream) {
+  using Writer = BaseWriteStream::Raw<sizeof(int32_t), int32_t>;
   Writer::Write(stream, src_);
   Writer::Write(stream, dest_and_kind_);
 }
diff --git a/runtime/vm/exceptions.h b/runtime/vm/exceptions.h
index 7a44cd8..e7b52e5 100644
--- a/runtime/vm/exceptions.h
+++ b/runtime/vm/exceptions.h
@@ -21,7 +21,7 @@
 class Instance;
 class Integer;
 class ReadStream;
-class WriteStream;
+class BaseWriteStream;
 class String;
 class Thread;
 class TypedData;
@@ -203,7 +203,7 @@
   static CatchEntryMove ReadFrom(ReadStream* stream);
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
-  void WriteTo(WriteStream* stream);
+  void WriteTo(BaseWriteStream* stream);
 #endif
 
 #if !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER)
diff --git a/runtime/vm/image_snapshot.cc b/runtime/vm/image_snapshot.cc
index 3d52db5..8ed1d98 100644
--- a/runtime/vm/image_snapshot.cc
+++ b/runtime/vm/image_snapshot.cc
@@ -6,6 +6,7 @@
 
 #include "include/dart_api.h"
 #include "platform/assert.h"
+#include "vm/bss_relocs.h"
 #include "vm/class_id.h"
 #include "vm/compiler/runtime_api.h"
 #include "vm/dwarf.h"
@@ -36,10 +37,84 @@
 
 DEFINE_FLAG(charp,
             print_instructions_sizes_to,
-            NULL,
+            nullptr,
             "Print sizes of all instruction objects to the given file");
 #endif
 
+const ImageHeaderLayout* Image::ExtraInfo(const uword raw_memory,
+                                          const uword size) {
+#if defined(DART_PRECOMPILED_RUNTIME)
+  auto const raw_value = FieldValue(raw_memory, HeaderField::ImageHeaderOffset);
+  if (raw_value != kNoImageHeader) {
+    ASSERT(raw_value >= kHeaderSize);
+    ASSERT(raw_value <= size - ImageHeader::InstanceSize());
+    return reinterpret_cast<const ImageHeaderLayout*>(raw_memory + raw_value);
+  }
+#endif
+  return nullptr;
+}
+
+uword* Image::bss() const {
+#if defined(DART_PRECOMPILED_RUNTIME)
+  ASSERT(extra_info_ != nullptr);
+  // There should always be a non-zero BSS offset.
+  ASSERT(extra_info_->bss_offset_ != 0);
+  // Returning a non-const uword* is safe because we're translating from
+  // the start of the instructions (read-only) to the start of the BSS
+  // (read-write).
+  return reinterpret_cast<uword*>(raw_memory_ + extra_info_->bss_offset_);
+#else
+  return nullptr;
+#endif
+}
+
+uword Image::instructions_relocated_address() const {
+#if defined(DART_PRECOMPILED_RUNTIME)
+  ASSERT(extra_info_ != nullptr);
+  // For assembly snapshots, we need to retrieve this from the initialized BSS.
+  const uword address =
+      compiled_to_elf() ? extra_info_->instructions_relocated_address_
+                        : bss()[BSS::RelocationIndex(
+                              BSS::Relocation::InstructionsRelocatedAddress)];
+  ASSERT(address != kNoRelocatedAddress);
+  return address;
+#else
+  return kNoRelocatedAddress;
+#endif
+}
+
+const uint8_t* Image::build_id() const {
+#if defined(DART_PRECOMPILED_RUNTIME)
+  ASSERT(extra_info_ != nullptr);
+  if (extra_info_->build_id_offset_ != kNoBuildId) {
+    return reinterpret_cast<const uint8_t*>(raw_memory_ +
+                                            extra_info_->build_id_offset_);
+  }
+#endif
+  return nullptr;
+}
+
+intptr_t Image::build_id_length() const {
+#if defined(DART_PRECOMPILED_RUNTIME)
+  ASSERT(extra_info_ != nullptr);
+  return extra_info_->build_id_length_;
+#else
+  return 0;
+#endif
+}
+
+bool Image::compiled_to_elf() const {
+#if defined(DART_PRECOMPILED_RUNTIME)
+  ASSERT(extra_info_ != nullptr);
+  // Since assembly snapshots can't set up this field correctly (instead,
+  // it's initialized in BSS at snapshot load time), we use it to detect
+  // direct-to-ELF snapshots.
+  return extra_info_->instructions_relocated_address_ != kNoRelocatedAddress;
+#else
+  return false;
+#endif
+}
+
 intptr_t ObjectOffsetTrait::Hashcode(Key key) {
   ObjectPtr obj = key;
   ASSERT(!obj->IsSmi());
@@ -88,6 +163,8 @@
       next_text_offset_(0),
       objects_(),
       instructions_(),
+      image_type_(TagObjectTypeAsReadOnly(t->zone(), "Image")),
+      image_header_type_(TagObjectTypeAsReadOnly(t->zone(), "ImageHeader")),
       instructions_section_type_(
           TagObjectTypeAsReadOnly(t->zone(), "InstructionsSection")),
       instructions_type_(TagObjectTypeAsReadOnly(t->zone(), "Instructions")),
@@ -386,7 +463,7 @@
 }
 #endif
 
-void ImageWriter::Write(WriteStream* clustered_stream, bool vm) {
+void ImageWriter::Write(NonStreamingWriteStream* clustered_stream, bool vm) {
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
   Heap* heap = thread->isolate()->heap();
@@ -412,33 +489,36 @@
     data.obj_ = &Object::Handle(zone, data.raw_obj_);
   }
 
-  // Append the direct-mapped RO data objects after the clustered snapshot.
-  // We need to do this before WriteText because WriteText currently adds the
-  // finalized contents of the clustered_stream as data sections.
-  offset_space_ = vm ? V8SnapshotProfileWriter::kVmData
-                     : V8SnapshotProfileWriter::kIsolateData;
-  WriteROData(clustered_stream);
+  // Needs to happen before WriteText, as we add information about the
+  // BSSsection in the text section as an initial ImageHeader object.
+  WriteBss(vm);
 
   offset_space_ = vm ? V8SnapshotProfileWriter::kVmText
                      : V8SnapshotProfileWriter::kIsolateText;
-  // Needs to happen after WriteROData, because all image writers currently
-  // add the clustered data information to their output in WriteText().
-  WriteText(clustered_stream, vm);
+  WriteText(vm);
+
+  // Append the direct-mapped RO data objects after the clustered snapshot
+  // and then for ELF and assembly outputs, add appropriate sections with
+  // that combined data.
+  offset_space_ = vm ? V8SnapshotProfileWriter::kVmData
+                     : V8SnapshotProfileWriter::kIsolateData;
+  WriteROData(clustered_stream, vm);
 }
 
-void ImageWriter::WriteROData(WriteStream* stream) {
+void ImageWriter::WriteROData(NonStreamingWriteStream* stream, bool vm) {
 #if defined(DART_PRECOMPILER)
   const intptr_t start_position = stream->Position();
 #endif
-  stream->Align(kMaxObjectAlignment);
+  stream->Align(ImageWriter::kRODataAlignment);
 
   // Heap page starts here.
 
   intptr_t section_start = stream->Position();
 
   stream->WriteWord(next_data_offset_);  // Data length.
-  // Zero values for other image header fields.
-  stream->Align(kMaxObjectAlignment);
+  stream->WriteWord(0);  // No ImageHeader object in data sections.
+  // Zero values for the rest of the Image object header bytes.
+  stream->Align(Image::kHeaderSize);
   ASSERT(stream->Position() - section_start == Image::kHeaderSize);
 #if defined(DART_PRECOMPILER)
   if (profile_writer_ != nullptr) {
@@ -539,7 +619,7 @@
 #if defined(DART_PRECOMPILER)
 class DwarfAssemblyStream : public DwarfWriteStream {
  public:
-  explicit DwarfAssemblyStream(StreamingWriteStream* stream)
+  explicit DwarfAssemblyStream(BaseWriteStream* stream)
       : stream_(ASSERT_NOTNULL(stream)) {}
 
   void sleb128(intptr_t value) { Print(".sleb128 %" Pd "\n", value); }
@@ -648,7 +728,7 @@
 
 #undef FORM_ADDR
 
-  StreamingWriteStream* const stream_;
+  BaseWriteStream* const stream_;
   intptr_t temp_ = 0;
 
   DISALLOW_COPY_AND_ASSIGN(DwarfAssemblyStream);
@@ -670,19 +750,18 @@
 }
 
 AssemblyImageWriter::AssemblyImageWriter(Thread* thread,
-                                         Dart_StreamingWriteCallback callback,
-                                         void* callback_data,
+                                         BaseWriteStream* stream,
                                          bool strip,
                                          Elf* debug_elf)
     : ImageWriter(thread),
-      assembly_stream_(512 * KB, callback, callback_data),
+      assembly_stream_(stream),
       assembly_dwarf_(AddDwarfIfUnstripped(thread->zone(), strip, debug_elf)),
       debug_elf_(debug_elf) {}
 
 void AssemblyImageWriter::Finalize() {
 #if defined(DART_PRECOMPILER)
   if (assembly_dwarf_ != nullptr) {
-    DwarfAssemblyStream dwarf_stream(&assembly_stream_);
+    DwarfAssemblyStream dwarf_stream(assembly_stream_);
     dwarf_stream.AbbreviationsPrologue();
     assembly_dwarf_->WriteAbbreviations(&dwarf_stream);
     dwarf_stream.DebugInfoPrologue();
@@ -751,7 +830,61 @@
   return SnapshotNameFor(index, *data.code_);
 }
 
-void AssemblyImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
+#if defined(DART_PRECOMPILER)
+static const char* const kVmSnapshotBssAsmSymbol = "_kDartVmSnapshotBss";
+static const char* const kIsolateSnapshotBssAsmSymbol =
+    "_kDartIsolateSnapshotBss";
+#endif
+
+void AssemblyImageWriter::WriteBss(bool vm) {
+#if defined(DART_PRECOMPILER)
+  auto const bss_symbol =
+      vm ? kVmSnapshotBssAsmSymbol : kIsolateSnapshotBssAsmSymbol;
+  assembly_stream_->Print(".bss\n");
+  // Align the BSS contents as expected by the Image class.
+  Align(ImageWriter::kBssAlignment);
+  assembly_stream_->Print("%s:\n", bss_symbol);
+
+  auto const entry_count = vm ? BSS::kVmEntryCount : BSS::kIsolateEntryCount;
+  for (intptr_t i = 0; i < entry_count; i++) {
+    WriteWordLiteralText(0);
+  }
+#endif
+}
+
+void AssemblyImageWriter::WriteROData(NonStreamingWriteStream* clustered_stream,
+                                      bool vm) {
+  ImageWriter::WriteROData(clustered_stream, vm);
+#if defined(DART_PRECOMPILED_RUNTIME)
+  UNREACHABLE();
+#else
+#if defined(TARGET_OS_LINUX) || defined(TARGET_OS_ANDROID) ||                  \
+    defined(TARGET_OS_FUCHSIA)
+  assembly_stream_->Print(".section .rodata\n");
+#elif defined(TARGET_OS_MACOS) || defined(TARGET_OS_MACOS_IOS)
+  assembly_stream_->Print(".const\n");
+#else
+  UNIMPLEMENTED();
+#endif
+
+  const char* data_symbol =
+      vm ? kVmSnapshotDataAsmSymbol : kIsolateSnapshotDataAsmSymbol;
+  assembly_stream_->Print(".globl %s\n", data_symbol);
+  Align(ImageWriter::kRODataAlignment);
+  assembly_stream_->Print("%s:\n", data_symbol);
+  const uword buffer = reinterpret_cast<uword>(clustered_stream->buffer());
+  const intptr_t length = clustered_stream->bytes_written();
+  WriteByteSequence(buffer, buffer + length);
+#if defined(DART_PRECOMPILER)
+  if (debug_elf_ != nullptr) {
+    // Add a NoBits section for the ROData as well.
+    debug_elf_->AddROData(data_symbol, clustered_stream->buffer(), length);
+  }
+#endif  // defined(DART_PRECOMPILER)
+#endif  // !defined(DART_PRECOMPILED_RUNTIME)
+}
+
+void AssemblyImageWriter::WriteText(bool vm) {
 #if defined(DART_PRECOMPILED_RUNTIME)
   UNREACHABLE();
 #else
@@ -760,25 +893,25 @@
   const bool bare_instruction_payloads =
       FLAG_precompiled_mode && FLAG_use_bare_instructions;
 
-#if defined(DART_PRECOMPILER)
-  const char* bss_symbol =
-      vm ? "_kDartVmSnapshotBss" : "_kDartIsolateSnapshotBss";
-  intptr_t debug_segment_base = 0;
-  if (debug_elf_ != nullptr) {
-    debug_segment_base = debug_elf_->NextMemoryOffset();
-  }
-#endif
-
   const char* instructions_symbol = vm ? kVmSnapshotInstructionsAsmSymbol
                                        : kIsolateSnapshotInstructionsAsmSymbol;
-  assembly_stream_.Print(".text\n");
-  assembly_stream_.Print(".globl %s\n", instructions_symbol);
+  assembly_stream_->Print(".text\n");
+  assembly_stream_->Print(".globl %s\n", instructions_symbol);
 
   // Start snapshot at page boundary.
-  ASSERT(VirtualMemory::PageSize() >= kMaxObjectAlignment);
-  ASSERT(VirtualMemory::PageSize() >= Image::kBssAlignment);
-  Align(VirtualMemory::PageSize());
-  assembly_stream_.Print("%s:\n", instructions_symbol);
+  ASSERT(ImageWriter::kTextAlignment >= VirtualMemory::PageSize());
+  Align(ImageWriter::kTextAlignment);
+  assembly_stream_->Print("%s:\n", instructions_symbol);
+
+#if defined(DART_PRECOMPILER)
+  auto const bss_symbol =
+      vm ? kVmSnapshotBssAsmSymbol : kIsolateSnapshotBssAsmSymbol;
+  intptr_t debug_segment_base = 0;
+  if (debug_elf_ != nullptr) {
+    debug_segment_base =
+        debug_elf_->NextMemoryOffset(ImageWriter::kTextAlignment);
+  }
+#endif
 
   intptr_t text_offset = 0;
 #if defined(DART_PRECOMPILER)
@@ -793,64 +926,113 @@
   const intptr_t image_size = Utils::RoundUp(
       next_text_offset_, compiler::target::ObjectAlignment::kObjectAlignment);
   text_offset += WriteWordLiteralText(image_size);
-
-#if defined(DART_PRECOMPILER)
-  assembly_stream_.Print("%s %s - %s\n", kLiteralPrefix, bss_symbol,
-                         instructions_symbol);
-  text_offset += compiler::target::kWordSize;
-#else
-  text_offset += WriteWordLiteralText(0);  // No relocations.
-#endif
-
-  text_offset += Align(kMaxObjectAlignment, text_offset);
-  ASSERT_EQUAL(text_offset, Image::kHeaderSize);
-#if defined(DART_PRECOMPILER)
-  if (profile_writer_ != nullptr) {
-    profile_writer_->SetObjectTypeAndName(parent_id, "Image",
-                                          instructions_symbol);
-    // Assign post-instruction padding to the Image, unless we're writing bare
-    // instruction payloads, in which case we'll assign it to the
-    // InstructionsSection object.
-    const intptr_t padding =
-        bare_instruction_payloads ? 0 : image_size - next_text_offset_;
-    profile_writer_->AttributeBytesTo(parent_id, Image::kHeaderSize + padding);
-    profile_writer_->AddRoot(parent_id);
+  if (FLAG_precompiled_mode) {
+    // Output the offset to the ImageHeader object from the start of the image.
+    text_offset += WriteWordLiteralText(Image::kHeaderSize);
+  } else {
+    text_offset += WriteWordLiteralText(Image::kNoImageHeader);
   }
-#endif
+  // Zero values for the rest of the Image object header bytes.
+  text_offset += Align(Image::kHeaderSize, text_offset);
+  ASSERT_EQUAL(text_offset, Image::kHeaderSize);
 
-  if (bare_instruction_payloads) {
 #if defined(DART_PRECOMPILER)
+  if (FLAG_precompiled_mode) {
+    if (profile_writer_ != nullptr) {
+      profile_writer_->SetObjectTypeAndName(parent_id, image_type_,
+                                            instructions_symbol);
+      // Assign post-instruction padding to the Image, unless we're writing bare
+      // instruction payloads, in which case we'll assign it to the
+      // InstructionsSection object.
+      const intptr_t padding =
+          bare_instruction_payloads ? 0 : image_size - next_text_offset_;
+      profile_writer_->AttributeBytesTo(parent_id,
+                                        Image::kHeaderSize + padding);
+      profile_writer_->AddRoot(parent_id);
+    }
+
+    // Write the ImageHeader object, starting with the header.
+    const intptr_t image_header_size =
+        compiler::target::ImageHeader::InstanceSize();
     if (profile_writer_ != nullptr) {
       const V8SnapshotProfileWriter::ObjectId id(offset_space_, text_offset);
-      profile_writer_->SetObjectTypeAndName(id, instructions_section_type_,
+      profile_writer_->SetObjectTypeAndName(id, image_header_type_,
                                             instructions_symbol);
-      const intptr_t padding = image_size - next_text_offset_;
-      profile_writer_->AttributeBytesTo(
-          id, compiler::target::InstructionsSection::HeaderSize() + padding);
+      profile_writer_->AttributeBytesTo(id, image_header_size);
       const intptr_t element_offset = id.second - parent_id.second;
       profile_writer_->AttributeReferenceTo(
           parent_id,
           {id, V8SnapshotProfileWriter::Reference::kElement, element_offset});
-      // Later objects will have the InstructionsSection as a parent.
-      parent_id = id;
     }
-#endif
-    const intptr_t section_size = image_size - text_offset;
-    // Add the RawInstructionsSection header.
     const compiler::target::uword marked_tags =
         ObjectLayout::OldBit::encode(true) |
         ObjectLayout::OldAndNotMarkedBit::encode(false) |
         ObjectLayout::OldAndNotRememberedBit::encode(true) |
         ObjectLayout::NewBit::encode(false) |
-        ObjectLayout::SizeTag::encode(AdjustObjectSizeForTarget(section_size)) |
-        ObjectLayout::ClassIdTag::encode(kInstructionsSectionCid);
+        ObjectLayout::SizeTag::encode(
+            AdjustObjectSizeForTarget(image_header_size)) |
+        ObjectLayout::ClassIdTag::encode(kImageHeaderCid);
     text_offset += WriteWordLiteralText(marked_tags);
-    // Calculated using next_text_offset_, which doesn't include post-payload
-    // padding to object alignment.
-    const intptr_t instructions_length =
-        next_text_offset_ - (text_offset + compiler::target::kWordSize);
-    text_offset += WriteWordLiteralText(instructions_length);
+
+    // An ImageHeader has four fields:
+    // 1) The BSS offset from this section.
+    assembly_stream_->Print("%s %s - %s\n", kLiteralPrefix, bss_symbol,
+                            instructions_symbol);
+    text_offset += compiler::target::kWordSize;
+    // 2) The relocated address of the instructions.
+    //
+    // For assembly snapshots, we can't generate assembly to get the absolute
+    // address of the text section, as using the section symbol gives us a
+    // relative offset from the section start, which is 0. Instead, depend on
+    // the BSS initialization to retrieve this for us at runtime. As a side
+    // effect, this field also doubles as a way to detect whether we compiled to
+    // assembly or directly to ELF.
+    text_offset += WriteWordLiteralText(Image::kNoRelocatedAddress);
+    // TODO(dartbug.com/43274): Change once we generate consistent build IDs
+    // between assembly snapshots and their debugging information.
+    // 3) The GNU build ID offset from this section.
+    text_offset += WriteWordLiteralText(Image::kNoBuildId);
+    // 4) The GNU build ID length.
+    text_offset += WriteWordLiteralText(0);
+    text_offset +=
+        Align(compiler::target::ObjectAlignment::kObjectAlignment, text_offset);
+
+    ASSERT_EQUAL(text_offset, Image::kHeaderSize + image_header_size);
+
+    if (bare_instruction_payloads) {
+      if (profile_writer_ != nullptr) {
+        const V8SnapshotProfileWriter::ObjectId id(offset_space_, text_offset);
+        profile_writer_->SetObjectTypeAndName(id, instructions_section_type_,
+                                              instructions_symbol);
+        const intptr_t padding = image_size - next_text_offset_;
+        profile_writer_->AttributeBytesTo(
+            id, compiler::target::InstructionsSection::HeaderSize() + padding);
+        const intptr_t element_offset = id.second - parent_id.second;
+        profile_writer_->AttributeReferenceTo(
+            parent_id,
+            {id, V8SnapshotProfileWriter::Reference::kElement, element_offset});
+        // Later objects will have the InstructionsSection as a parent.
+        parent_id = id;
+      }
+      const intptr_t section_size = image_size - text_offset;
+      // Add the RawInstructionsSection header.
+      const compiler::target::uword marked_tags =
+          ObjectLayout::OldBit::encode(true) |
+          ObjectLayout::OldAndNotMarkedBit::encode(false) |
+          ObjectLayout::OldAndNotRememberedBit::encode(true) |
+          ObjectLayout::NewBit::encode(false) |
+          ObjectLayout::SizeTag::encode(
+              AdjustObjectSizeForTarget(section_size)) |
+          ObjectLayout::ClassIdTag::encode(kInstructionsSectionCid);
+      text_offset += WriteWordLiteralText(marked_tags);
+      // Calculated using next_text_offset_, which doesn't include post-payload
+      // padding to object alignment.
+      const intptr_t instructions_length =
+          next_text_offset_ - (text_offset + compiler::target::kWordSize);
+      text_offset += WriteWordLiteralText(instructions_length);
+    }
   }
+#endif
 
   FrameUnwindPrologue();
 
@@ -932,7 +1114,7 @@
       text_offset += sizeof(compiler::target::uword);
       WriteWordLiteralText(insns.raw_ptr()->size_and_flags_);
       text_offset += sizeof(compiler::target::uword);
-#else   // defined(IS_SIMARM_X64)
+#else  // defined(IS_SIMARM_X64)
       uword object_start = reinterpret_cast<uword>(insns.raw_ptr());
       WriteWordLiteralText(marked_tags);
       object_start += sizeof(uword);
@@ -951,7 +1133,7 @@
 #endif
     // 2. Write a label at the entry point.
     // Linux's perf uses these labels.
-    assembly_stream_.Print("%s:\n", object_name);
+    assembly_stream_->Print("%s:\n", object_name);
 
     {
       // 3. Write from the payload start to payload end. For AOT snapshots
@@ -981,8 +1163,8 @@
         compiler::target::uword data =
             *reinterpret_cast<compiler::target::uword*>(cursor);
         if ((cursor - payload_start) == next_reloc_offset) {
-          assembly_stream_.Print("%s %s - (.) + %" Pd "\n", kLiteralPrefix,
-                                 bss_symbol, /*addend=*/data);
+          assembly_stream_->Print("%s %s - (.) + %" Pd "\n", kLiteralPrefix,
+                                  bss_symbol, /*addend=*/data);
           text_offset += compiler::target::kWordSize;
           next_reloc_offset = iterator.MoveNext() ? iterator.PcOffset() : -1;
         } else {
@@ -1053,41 +1235,7 @@
     // writing the text section.
     ASSERT(debug_segment_base2 == debug_segment_base);
   }
-
-  assembly_stream_.Print(".bss\n");
-  // Align the BSS contents as expected by the Image class.
-  Align(Image::kBssAlignment);
-  assembly_stream_.Print("%s:\n", bss_symbol);
-
-  auto const entry_count = vm ? BSS::kVmEntryCount : BSS::kIsolateEntryCount;
-  for (intptr_t i = 0; i < entry_count; i++) {
-    WriteWordLiteralText(0);
-  }
 #endif
-
-#if defined(TARGET_OS_LINUX) || defined(TARGET_OS_ANDROID) ||                  \
-    defined(TARGET_OS_FUCHSIA)
-  assembly_stream_.Print(".section .rodata\n");
-#elif defined(TARGET_OS_MACOS) || defined(TARGET_OS_MACOS_IOS)
-  assembly_stream_.Print(".const\n");
-#else
-  UNIMPLEMENTED();
-#endif
-
-  const char* data_symbol =
-      vm ? kVmSnapshotDataAsmSymbol : kIsolateSnapshotDataAsmSymbol;
-  assembly_stream_.Print(".globl %s\n", data_symbol);
-  Align(kMaxObjectAlignment);
-  assembly_stream_.Print("%s:\n", data_symbol);
-  const uword buffer = reinterpret_cast<uword>(clustered_stream->buffer());
-  const intptr_t length = clustered_stream->bytes_written();
-  WriteByteSequence(buffer, buffer + length);
-#if defined(DART_PRECOMPILER)
-  if (debug_elf_ != nullptr) {
-    // Add a NoBits section for the ROData as well.
-    debug_elf_->AddROData(data_symbol, clustered_stream->buffer(), length);
-  }
-#endif  // defined(DART_PRECOMPILER)
 #endif  // !defined(DART_PRECOMPILED_RUNTIME)
 }
 
@@ -1095,12 +1243,12 @@
   // Creates DWARF's .debug_frame
   // CFI = Call frame information
   // CFA = Canonical frame address
-  assembly_stream_.Print(".cfi_startproc\n");
+  assembly_stream_->Print(".cfi_startproc\n");
 
 #if defined(TARGET_ARCH_X64)
-  assembly_stream_.Print(".cfi_def_cfa rbp, 0\n");  // CFA is fp+0
-  assembly_stream_.Print(".cfi_offset rbp, 0\n");   // saved fp is *(CFA+0)
-  assembly_stream_.Print(".cfi_offset rip, 8\n");   // saved pc is *(CFA+8)
+  assembly_stream_->Print(".cfi_def_cfa rbp, 0\n");  // CFA is fp+0
+  assembly_stream_->Print(".cfi_offset rbp, 0\n");   // saved fp is *(CFA+0)
+  assembly_stream_->Print(".cfi_offset rip, 8\n");   // saved pc is *(CFA+8)
   // saved sp is CFA+16
   // Should be ".cfi_value_offset rsp, 16", but requires gcc newer than late
   // 2016 and not supported by Android's libunwind.
@@ -1109,14 +1257,14 @@
   // uleb128 size of operation     2
   // DW_OP_plus_uconst          0x23
   // uleb128 addend               16
-  assembly_stream_.Print(".cfi_escape 0x10, 31, 2, 0x23, 16\n");
+  assembly_stream_->Print(".cfi_escape 0x10, 31, 2, 0x23, 16\n");
 
 #elif defined(TARGET_ARCH_ARM64)
   COMPILE_ASSERT(FP == R29);
   COMPILE_ASSERT(LR == R30);
-  assembly_stream_.Print(".cfi_def_cfa x29, 0\n");  // CFA is fp+0
-  assembly_stream_.Print(".cfi_offset x29, 0\n");   // saved fp is *(CFA+0)
-  assembly_stream_.Print(".cfi_offset x30, 8\n");   // saved pc is *(CFA+8)
+  assembly_stream_->Print(".cfi_def_cfa x29, 0\n");  // CFA is fp+0
+  assembly_stream_->Print(".cfi_offset x29, 0\n");   // saved fp is *(CFA+0)
+  assembly_stream_->Print(".cfi_offset x30, 8\n");   // saved pc is *(CFA+8)
   // saved sp is CFA+16
   // Should be ".cfi_value_offset sp, 16", but requires gcc newer than late
   // 2016 and not supported by Android's libunwind.
@@ -1125,19 +1273,19 @@
   // uleb128 size of operation     2
   // DW_OP_plus_uconst          0x23
   // uleb128 addend               16
-  assembly_stream_.Print(".cfi_escape 0x10, 31, 2, 0x23, 16\n");
+  assembly_stream_->Print(".cfi_escape 0x10, 31, 2, 0x23, 16\n");
 
 #elif defined(TARGET_ARCH_ARM)
 #if defined(TARGET_OS_MACOS) || defined(TARGET_OS_MACOS_IOS)
   COMPILE_ASSERT(FP == R7);
-  assembly_stream_.Print(".cfi_def_cfa r7, 0\n");  // CFA is fp+j0
-  assembly_stream_.Print(".cfi_offset r7, 0\n");   // saved fp is *(CFA+0)
+  assembly_stream_->Print(".cfi_def_cfa r7, 0\n");  // CFA is fp+j0
+  assembly_stream_->Print(".cfi_offset r7, 0\n");   // saved fp is *(CFA+0)
 #else
   COMPILE_ASSERT(FP == R11);
-  assembly_stream_.Print(".cfi_def_cfa r11, 0\n");  // CFA is fp+0
-  assembly_stream_.Print(".cfi_offset r11, 0\n");   // saved fp is *(CFA+0)
+  assembly_stream_->Print(".cfi_def_cfa r11, 0\n");  // CFA is fp+0
+  assembly_stream_->Print(".cfi_offset r11, 0\n");   // saved fp is *(CFA+0)
 #endif
-  assembly_stream_.Print(".cfi_offset lr, 4\n");   // saved pc is *(CFA+4)
+  assembly_stream_->Print(".cfi_offset lr, 4\n");   // saved pc is *(CFA+4)
   // saved sp is CFA+8
   // Should be ".cfi_value_offset sp, 8", but requires gcc newer than late
   // 2016 and not supported by Android's libunwind.
@@ -1146,14 +1294,14 @@
   // uleb128 size of operation     2
   // DW_OP_plus_uconst          0x23
   // uleb128 addend                8
-  assembly_stream_.Print(".cfi_escape 0x10, 13, 2, 0x23, 8\n");
+  assembly_stream_->Print(".cfi_escape 0x10, 13, 2, 0x23, 8\n");
 
 // libunwind on ARM may use .ARM.exidx instead of .debug_frame
 #if !defined(TARGET_OS_MACOS) && !defined(TARGET_OS_MACOS_IOS)
   COMPILE_ASSERT(FP == R11);
-  assembly_stream_.Print(".fnstart\n");
-  assembly_stream_.Print(".save {r11, lr}\n");
-  assembly_stream_.Print(".setfp r11, sp, #0\n");
+  assembly_stream_->Print(".fnstart\n");
+  assembly_stream_->Print(".save {r11, lr}\n");
+  assembly_stream_->Print(".setfp r11, sp, #0\n");
 #endif
 
 #endif
@@ -1162,10 +1310,10 @@
 void AssemblyImageWriter::FrameUnwindEpilogue() {
 #if defined(TARGET_ARCH_ARM)
 #if !defined(TARGET_OS_MACOS) && !defined(TARGET_OS_MACOS_IOS)
-  assembly_stream_.Print(".fnend\n");
+  assembly_stream_->Print(".fnend\n");
 #endif
 #endif
-  assembly_stream_.Print(".cfi_endproc\n");
+  assembly_stream_->Print(".cfi_endproc\n");
 }
 
 intptr_t AssemblyImageWriter::WriteByteSequence(uword start, uword end) {
@@ -1179,31 +1327,29 @@
   }
   if (end != end_of_words) {
     auto start_of_rest = reinterpret_cast<const uint8_t*>(end_of_words);
-    assembly_stream_.Print(".byte ");
+    assembly_stream_->Print(".byte ");
     for (auto cursor = start_of_rest;
          cursor < reinterpret_cast<const uint8_t*>(end); cursor++) {
-      if (cursor != start_of_rest) assembly_stream_.Print(", ");
-      assembly_stream_.Print("0x%0.2" Px "", *cursor);
+      if (cursor != start_of_rest) assembly_stream_->Print(", ");
+      assembly_stream_->Print("0x%0.2" Px "", *cursor);
     }
-    assembly_stream_.Print("\n");
+    assembly_stream_->Print("\n");
   }
   return end - start;
 }
 
 intptr_t AssemblyImageWriter::Align(intptr_t alignment, uword position) {
   const uword next_position = Utils::RoundUp(position, alignment);
-  assembly_stream_.Print(".balign %" Pd ", 0\n", alignment);
+  assembly_stream_->Print(".balign %" Pd ", 0\n", alignment);
   return next_position - position;
 }
 
 BlobImageWriter::BlobImageWriter(Thread* thread,
-                                 uint8_t** instructions_blob_buffer,
-                                 ReAlloc alloc,
-                                 intptr_t initial_size,
+                                 NonStreamingWriteStream* stream,
                                  Elf* debug_elf,
                                  Elf* elf)
     : ImageWriter(thread),
-      instructions_blob_stream_(instructions_blob_buffer, alloc, initial_size),
+      instructions_blob_stream_(ASSERT_NOTNULL(stream)),
       elf_(elf),
       debug_elf_(debug_elf) {
 #if defined(DART_PRECOMPILER)
@@ -1215,12 +1361,41 @@
 
 intptr_t BlobImageWriter::WriteByteSequence(uword start, uword end) {
   const uword size = end - start;
-  instructions_blob_stream_.WriteBytes(reinterpret_cast<const void*>(start),
-                                       size);
+  instructions_blob_stream_->WriteBytes(reinterpret_cast<const void*>(start),
+                                        size);
   return size;
 }
 
-void BlobImageWriter::WriteText(WriteStream* clustered_stream, bool vm) {
+void BlobImageWriter::WriteBss(bool vm) {
+#if defined(DART_PRECOMPILER)
+  // We don't actually write a BSS segment, it's created as part of the
+  // Elf constructor, but make sure it has an non-zero start.
+  ASSERT(elf_->BssStart(vm) != 0);
+#endif
+}
+
+void BlobImageWriter::WriteROData(NonStreamingWriteStream* clustered_stream,
+                                  bool vm) {
+  ImageWriter::WriteROData(clustered_stream, vm);
+#if defined(DART_PRECOMPILER)
+  auto const data_symbol =
+      vm ? kVmSnapshotDataAsmSymbol : kIsolateSnapshotDataAsmSymbol;
+  if (elf_ != nullptr) {
+    elf_->AddROData(data_symbol, clustered_stream->buffer(),
+                    clustered_stream->bytes_written());
+  }
+  if (debug_elf_ != nullptr) {
+    // To keep memory addresses consistent, we create elf::SHT_NOBITS sections
+    // in the debugging information. We still pass along the buffers because
+    // we'll need the buffer bytes at generation time to calculate the build ID
+    // so it'll match the one in the snapshot.
+    debug_elf_->AddROData(data_symbol, clustered_stream->buffer(),
+                          clustered_stream->bytes_written());
+  }
+#endif
+}
+
+void BlobImageWriter::WriteText(bool vm) {
   const bool bare_instruction_payloads =
       FLAG_precompiled_mode && FLAG_use_bare_instructions;
   auto const zone = Thread::Current()->zone();
@@ -1230,11 +1405,12 @@
                                       : kIsolateSnapshotInstructionsAsmSymbol;
   intptr_t segment_base = 0;
   if (elf_ != nullptr) {
-    segment_base = elf_->NextMemoryOffset();
+    segment_base = elf_->NextMemoryOffset(ImageWriter::kTextAlignment);
   }
   intptr_t debug_segment_base = 0;
   if (debug_elf_ != nullptr) {
-    debug_segment_base = debug_elf_->NextMemoryOffset();
+    debug_segment_base =
+        debug_elf_->NextMemoryOffset(ImageWriter::kTextAlignment);
     // If we're also generating an ELF snapshot, we want the virtual addresses
     // in it and the separately saved DWARF information to match.
     ASSERT(elf_ == nullptr || segment_base == debug_segment_base);
@@ -1253,74 +1429,123 @@
   // OldPage.
   const intptr_t image_size = Utils::RoundUp(
       next_text_offset_, compiler::target::ObjectAlignment::kObjectAlignment);
-  instructions_blob_stream_.WriteTargetWord(image_size);
-#if defined(DART_PRECOMPILER)
-  // Store the offset of the BSS section from the instructions section here.
-  // If not compiling to ELF (and thus no BSS segment), write 0.
-  const word bss_offset =
-      elf_ != nullptr ? elf_->BssStart(vm) - segment_base : 0;
-  ASSERT_EQUAL(Utils::RoundDown(bss_offset, Image::kBssAlignment), bss_offset);
-  // Set the lowest bit if we are compiling to ELF.
-  const word compiled_to_elf = elf_ != nullptr ? 0x1 : 0x0;
-  instructions_blob_stream_.WriteTargetWord(bss_offset | compiled_to_elf);
-#else
-  instructions_blob_stream_.WriteTargetWord(0);  // No relocations.
-#endif
-  instructions_blob_stream_.Align(kMaxObjectAlignment);
-  ASSERT_EQUAL(instructions_blob_stream_.Position(), Image::kHeaderSize);
-  text_offset += Image::kHeaderSize;
-#if defined(DART_PRECOMPILER)
-  if (profile_writer_ != nullptr) {
-    profile_writer_->SetObjectTypeAndName(parent_id, "Image",
-                                          instructions_symbol);
-    // Assign post-instruction padding to the Image, unless we're writing bare
-    // instruction payloads, in which case we'll assign it to the
-    // InstructionsSection object.
-    const intptr_t padding =
-        bare_instruction_payloads ? 0 : image_size - next_text_offset_;
-    profile_writer_->AttributeBytesTo(parent_id, Image::kHeaderSize + padding);
-    profile_writer_->AddRoot(parent_id);
+  instructions_blob_stream_->WriteTargetWord(image_size);
+  if (FLAG_precompiled_mode) {
+    // Output the offset to the ImageHeader object from the start of the image.
+    instructions_blob_stream_->WriteTargetWord(Image::kHeaderSize);
+  } else {
+    instructions_blob_stream_->WriteTargetWord(0);  // No ImageHeader object.
   }
-#endif
+  // Zero values for the rest of the Image object header bytes.
+  instructions_blob_stream_->Align(Image::kHeaderSize);
+  ASSERT_EQUAL(instructions_blob_stream_->Position(), Image::kHeaderSize);
+  text_offset += Image::kHeaderSize;
 
-  if (bare_instruction_payloads) {
 #if defined(DART_PRECOMPILER)
+  if (FLAG_precompiled_mode) {
+    if (profile_writer_ != nullptr) {
+      profile_writer_->SetObjectTypeAndName(parent_id, image_type_,
+                                            instructions_symbol);
+      // Assign post-instruction padding to the Image, unless we're writing bare
+      // instruction payloads, in which case we'll assign it to the
+      // InstructionsSection object.
+      const intptr_t padding =
+          bare_instruction_payloads ? 0 : image_size - next_text_offset_;
+      profile_writer_->AttributeBytesTo(parent_id,
+                                        Image::kHeaderSize + padding);
+      profile_writer_->AddRoot(parent_id);
+    }
+
+    // Write the ImageHeader object, starting with the header.
+    const intptr_t image_header_size =
+        compiler::target::ImageHeader::InstanceSize();
     if (profile_writer_ != nullptr) {
       const V8SnapshotProfileWriter::ObjectId id(offset_space_, text_offset);
-      profile_writer_->SetObjectTypeAndName(id, instructions_section_type_,
+      profile_writer_->SetObjectTypeAndName(id, image_header_type_,
                                             instructions_symbol);
-      const intptr_t padding = image_size - next_text_offset_;
-      profile_writer_->AttributeBytesTo(
-          id, compiler::target::InstructionsSection::HeaderSize() + padding);
+      profile_writer_->AttributeBytesTo(id, image_header_size);
       const intptr_t element_offset = id.second - parent_id.second;
       profile_writer_->AttributeReferenceTo(
           parent_id,
           {id, V8SnapshotProfileWriter::Reference::kElement, element_offset});
-      // Later objects will have the InstructionsSection as a parent.
-      parent_id = id;
     }
-#endif
-    const intptr_t section_size = image_size - Image::kHeaderSize;
-    // Add the RawInstructionsSection header.
     const compiler::target::uword marked_tags =
         ObjectLayout::OldBit::encode(true) |
         ObjectLayout::OldAndNotMarkedBit::encode(false) |
         ObjectLayout::OldAndNotRememberedBit::encode(true) |
         ObjectLayout::NewBit::encode(false) |
-        ObjectLayout::SizeTag::encode(AdjustObjectSizeForTarget(section_size)) |
-        ObjectLayout::ClassIdTag::encode(kInstructionsSectionCid);
-    instructions_blob_stream_.WriteTargetWord(marked_tags);
-    // Uses next_text_offset_ to avoid any post-payload padding.
-    const intptr_t instructions_length =
-        next_text_offset_ - Image::kHeaderSize -
-        compiler::target::InstructionsSection::HeaderSize();
-    instructions_blob_stream_.WriteTargetWord(instructions_length);
-    ASSERT_EQUAL(instructions_blob_stream_.Position() - text_offset,
-                 compiler::target::InstructionsSection::HeaderSize());
-    text_offset += compiler::target::InstructionsSection::HeaderSize();
-  }
+        ObjectLayout::SizeTag::encode(
+            AdjustObjectSizeForTarget(image_header_size)) |
+        ObjectLayout::ClassIdTag::encode(kImageHeaderCid);
+    instructions_blob_stream_->WriteTargetWord(marked_tags);
 
-  ASSERT_EQUAL(text_offset, instructions_blob_stream_.Position());
+    ASSERT(elf_ != nullptr);
+    // An ImageHeader has four fields:
+    // 1) The BSS offset from this section.
+    const word bss_offset = elf_->BssStart(vm) - segment_base;
+    ASSERT(bss_offset != Image::kNoBssSection);
+    instructions_blob_stream_->WriteTargetWord(bss_offset);
+    // 2) The relocated address of the instructions.
+    //
+    // Since we set this to a non-zero value for ELF snapshots, we also use this
+    // to detect compiled-to-ELF snapshots.
+    ASSERT(segment_base != Image::kNoRelocatedAddress);
+    instructions_blob_stream_->WriteTargetWord(segment_base);
+    // 3) The GNU build ID offset from this section.
+    intptr_t build_id_length = 0;
+    const word build_id_offset =
+        elf_->BuildIdStart(&build_id_length) - segment_base;
+    ASSERT(build_id_offset != Image::kNoBuildId);
+    instructions_blob_stream_->WriteTargetWord(build_id_offset);
+    // 4) The GNU build ID length.
+    ASSERT(build_id_length != 0);
+    instructions_blob_stream_->WriteTargetWord(build_id_length);
+    instructions_blob_stream_->Align(
+        compiler::target::ObjectAlignment::kObjectAlignment);
+
+    ASSERT_EQUAL(instructions_blob_stream_->Position() - text_offset,
+                 image_header_size);
+    text_offset += image_header_size;
+
+    if (bare_instruction_payloads) {
+      if (profile_writer_ != nullptr) {
+        const V8SnapshotProfileWriter::ObjectId id(offset_space_, text_offset);
+        profile_writer_->SetObjectTypeAndName(id, instructions_section_type_,
+                                              instructions_symbol);
+        const intptr_t padding = image_size - next_text_offset_;
+        profile_writer_->AttributeBytesTo(
+            id, compiler::target::InstructionsSection::HeaderSize() + padding);
+        const intptr_t element_offset = id.second - parent_id.second;
+        profile_writer_->AttributeReferenceTo(
+            parent_id,
+            {id, V8SnapshotProfileWriter::Reference::kElement, element_offset});
+        // Later objects will have the InstructionsSection as a parent.
+        parent_id = id;
+      }
+      const intptr_t section_size = image_size - text_offset;
+      // Add the RawInstructionsSection header.
+      const compiler::target::uword marked_tags =
+          ObjectLayout::OldBit::encode(true) |
+          ObjectLayout::OldAndNotMarkedBit::encode(false) |
+          ObjectLayout::OldAndNotRememberedBit::encode(true) |
+          ObjectLayout::NewBit::encode(false) |
+          ObjectLayout::SizeTag::encode(
+              AdjustObjectSizeForTarget(section_size)) |
+          ObjectLayout::ClassIdTag::encode(kInstructionsSectionCid);
+      instructions_blob_stream_->WriteTargetWord(marked_tags);
+      // Uses next_text_offset_ to avoid any post-payload padding.
+      const intptr_t instructions_length =
+          next_text_offset_ - text_offset -
+          compiler::target::InstructionsSection::HeaderSize();
+      instructions_blob_stream_->WriteTargetWord(instructions_length);
+      ASSERT_EQUAL(instructions_blob_stream_->Position() - text_offset,
+                   compiler::target::InstructionsSection::HeaderSize());
+      text_offset += compiler::target::InstructionsSection::HeaderSize();
+    }
+  }
+#endif
+
+  ASSERT_EQUAL(text_offset, instructions_blob_stream_->Position());
 
 #if defined(DART_PRECOMPILER)
   auto& descriptors = PcDescriptors::Handle(zone);
@@ -1381,29 +1606,29 @@
 #endif
 
 #if defined(IS_SIMARM_X64)
-    const intptr_t start_offset = instructions_blob_stream_.bytes_written();
+    const intptr_t start_offset = instructions_blob_stream_->bytes_written();
 
     if (!bare_instruction_payloads) {
       const intptr_t size_in_bytes = InstructionsSizeInSnapshot(insns.raw());
       marked_tags = UpdateObjectSizeForTarget(size_in_bytes, marked_tags);
-      instructions_blob_stream_.WriteTargetWord(marked_tags);
-      instructions_blob_stream_.WriteFixed<uint32_t>(
+      instructions_blob_stream_->WriteTargetWord(marked_tags);
+      instructions_blob_stream_->WriteFixed<uint32_t>(
           insns.raw_ptr()->size_and_flags_);
     } else {
-      ASSERT(Utils::IsAligned(instructions_blob_stream_.Position(),
+      ASSERT(Utils::IsAligned(instructions_blob_stream_->Position(),
                               kBareInstructionsAlignment));
     }
-    const intptr_t payload_offset = instructions_blob_stream_.Position();
-    instructions_blob_stream_.WriteBytes(
+    const intptr_t payload_offset = instructions_blob_stream_->Position();
+    instructions_blob_stream_->WriteBytes(
         reinterpret_cast<const void*>(insns.PayloadStart()), insns.Size());
     const intptr_t alignment =
         bare_instruction_payloads
             ? kBareInstructionsAlignment
             : compiler::target::ObjectAlignment::kObjectAlignment;
-    instructions_blob_stream_.Align(alignment);
-    const intptr_t end_offset = instructions_blob_stream_.bytes_written();
+    instructions_blob_stream_->Align(alignment);
+    const intptr_t end_offset = instructions_blob_stream_->bytes_written();
     text_offset += (end_offset - start_offset);
-#else   // defined(IS_SIMARM_X64)
+#else  // defined(IS_SIMARM_X64)
     // Only payload is output in AOT snapshots.
     const uword header_size =
         bare_instruction_payloads
@@ -1413,15 +1638,15 @@
     const uword object_end = payload_start + payload_size;
     if (!bare_instruction_payloads) {
       uword object_start = reinterpret_cast<uword>(insns.raw_ptr());
-      instructions_blob_stream_.WriteWord(marked_tags);
+      instructions_blob_stream_->WriteWord(marked_tags);
       text_offset += sizeof(uword);
       object_start += sizeof(uword);
       text_offset += WriteByteSequence(object_start, payload_start);
     } else {
-      ASSERT(Utils::IsAligned(instructions_blob_stream_.Position(),
+      ASSERT(Utils::IsAligned(instructions_blob_stream_->Position(),
                               kBareInstructionsAlignment));
     }
-    const intptr_t payload_offset = instructions_blob_stream_.Position();
+    const intptr_t payload_offset = instructions_blob_stream_->Position();
     text_offset += WriteByteSequence(payload_start, object_end);
 #endif
 
@@ -1440,13 +1665,14 @@
     // or not after loading.
     if (elf_ != nullptr) {
       const intptr_t current_stream_position =
-          instructions_blob_stream_.Position();
+          instructions_blob_stream_->Position();
 
       descriptors = code.pc_descriptors();
 
       PcDescriptors::Iterator iterator(
           descriptors, /*kind_mask=*/PcDescriptorsLayout::kBSSRelocation);
 
+      const intptr_t bss_offset = elf_->BssStart(vm) - segment_base;
       while (iterator.MoveNext()) {
         const intptr_t reloc_offset = iterator.PcOffset();
 
@@ -1460,14 +1686,14 @@
         // offset of the BSS segment from the relocation position plus the
         // addend in the relocation.
         auto const reloc_pos = payload_offset + reloc_offset;
-        instructions_blob_stream_.SetPosition(reloc_pos);
+        instructions_blob_stream_->SetPosition(reloc_pos);
 
         const compiler::target::word offset = bss_offset - reloc_pos + addend;
-        instructions_blob_stream_.WriteTargetWord(offset);
+        instructions_blob_stream_->WriteTargetWord(offset);
       }
 
       // Restore stream position after the relocation was patched.
-      instructions_blob_stream_.SetPosition(current_stream_position);
+      instructions_blob_stream_->SetPosition(current_stream_position);
     }
 #else
     USE(payload_offset);
@@ -1480,25 +1706,20 @@
   // Should be a no-op unless writing bare instruction payloads, in which case
   // we need to add post-payload padding to the object alignment. The alignment
   // should match the alignment used in image_size above.
-  instructions_blob_stream_.Align(
+  instructions_blob_stream_->Align(
       compiler::target::ObjectAlignment::kObjectAlignment);
   text_offset = Utils::RoundUp(
       text_offset, compiler::target::ObjectAlignment::kObjectAlignment);
 
-  ASSERT_EQUAL(text_offset, instructions_blob_stream_.bytes_written());
+  ASSERT_EQUAL(text_offset, instructions_blob_stream_->bytes_written());
   ASSERT_EQUAL(text_offset, image_size);
 
-#ifdef DART_PRECOMPILER
-  auto const data_symbol =
-      vm ? kVmSnapshotDataAsmSymbol : kIsolateSnapshotDataAsmSymbol;
+#if defined(DART_PRECOMPILER)
   if (elf_ != nullptr) {
     auto const segment_base2 =
-        elf_->AddText(instructions_symbol, instructions_blob_stream_.buffer(),
-                      instructions_blob_stream_.bytes_written());
+        elf_->AddText(instructions_symbol, instructions_blob_stream_->buffer(),
+                      instructions_blob_stream_->bytes_written());
     ASSERT_EQUAL(segment_base2, segment_base);
-    // Write the .rodata section here like the AssemblyImageWriter.
-    elf_->AddROData(data_symbol, clustered_stream->buffer(),
-                    clustered_stream->bytes_written());
   }
   if (debug_elf_ != nullptr) {
     // To keep memory addresses consistent, we create elf::SHT_NOBITS sections
@@ -1506,11 +1727,9 @@
     // we'll need the buffer bytes at generation time to calculate the build ID
     // so it'll match the one in the snapshot.
     auto const debug_segment_base2 = debug_elf_->AddText(
-        instructions_symbol, instructions_blob_stream_.buffer(),
-        instructions_blob_stream_.bytes_written());
+        instructions_symbol, instructions_blob_stream_->buffer(),
+        instructions_blob_stream_->bytes_written());
     ASSERT_EQUAL(debug_segment_base2, debug_segment_base);
-    debug_elf_->AddROData(data_symbol, clustered_stream->buffer(),
-                          clustered_stream->bytes_written());
   }
 #endif
 }
@@ -1518,10 +1737,8 @@
 
 ImageReader::ImageReader(const uint8_t* data_image,
                          const uint8_t* instructions_image)
-    : data_image_(data_image), instructions_image_(instructions_image) {
-  ASSERT(data_image != NULL);
-  ASSERT(instructions_image != NULL);
-}
+    : data_image_(ASSERT_NOTNULL(data_image)),
+      instructions_image_(ASSERT_NOTNULL(instructions_image)) {}
 
 ApiErrorPtr ImageReader::VerifyAlignment() const {
   if (!Utils::IsAligned(data_image_, kObjectAlignment) ||
diff --git a/runtime/vm/image_snapshot.h b/runtime/vm/image_snapshot.h
index 6727ca0..a75871b 100644
--- a/runtime/vm/image_snapshot.h
+++ b/runtime/vm/image_snapshot.h
@@ -13,6 +13,7 @@
 #include "vm/allocation.h"
 #include "vm/compiler/runtime_api.h"
 #include "vm/datastream.h"
+#include "vm/elf.h"
 #include "vm/globals.h"
 #include "vm/growable_array.h"
 #include "vm/hash_map.h"
@@ -26,65 +27,117 @@
 // Forward declarations.
 class Code;
 class Dwarf;
-class Elf;
 class Instructions;
 class Object;
 
 class Image : ValueObject {
  public:
-  explicit Image(const void* raw_memory) : raw_memory_(raw_memory) {
+  explicit Image(const void* raw_memory)
+      : Image(reinterpret_cast<uword>(raw_memory)) {}
+  explicit Image(const uword raw_memory)
+      : raw_memory_(raw_memory),
+        snapshot_size_(FieldValue(raw_memory, HeaderField::ImageSize)),
+        extra_info_(ExtraInfo(raw_memory_, snapshot_size_)) {
     ASSERT(Utils::IsAligned(raw_memory, kMaxObjectAlignment));
   }
 
+  // Even though an Image is read-only memory, we must return a void* here.
+  // All objects in an Image are pre-marked, though, so the GC will not attempt
+  // to change the returned memory.
   void* object_start() const {
-    return reinterpret_cast<void*>(reinterpret_cast<uword>(raw_memory_) +
-                                   kHeaderSize);
+    return reinterpret_cast<void*>(raw_memory_ + kHeaderSize);
   }
 
-  uword object_size() const {
-    uword snapshot_size = *reinterpret_cast<const uword*>(raw_memory_);
-    return snapshot_size - kHeaderSize;
-  }
+  uword object_size() const { return snapshot_size_ - kHeaderSize; }
 
   bool contains(uword address) const {
     uword start = reinterpret_cast<uword>(object_start());
     return address >= start && (address - start < object_size());
   }
 
-  // Returns the offset of the BSS section from this image. Only has meaning for
-  // instructions images.
-  word bss_offset() const {
-    auto const raw_value = *(reinterpret_cast<const word*>(raw_memory_) + 1);
-    return Utils::RoundDown(raw_value, kBssAlignment);
-  }
+  // Returns the address of the BSS section, or nullptr if one is not available.
+  // Only has meaning for instructions images from precompiled snapshots.
+  uword* bss() const;
 
-  // Returns true if the image was compiled directly to ELF. Only has meaning
-  // for instructions images.
-  bool compiled_to_elf() const {
-    auto const raw_value = *(reinterpret_cast<const word*>(raw_memory_) + 1);
-    return (raw_value & 0x1) == 0x1;
-  }
+  // Returns the relocated address of the isolate's instructions, or 0 if
+  // one is not available. Only has meaning for instructions images from
+  // precompiled snapshots.
+  uword instructions_relocated_address() const;
+
+  // Returns the GNU build ID, or nullptr if not available. See
+  // build_id_length() for the length of the returned buffer. Only has meaning
+  // for instructions images from precompiled snapshots.
+  const uint8_t* build_id() const;
+
+  // Returns the length of the GNU build ID returned by build_id(). Only has
+  // meaning for instructions images from precompiled snapshots.
+  intptr_t build_id_length() const;
+
+  // Returns whether this instructions section was compiled to ELF. Only has
+  // meaning for instructions images from precompiled snapshots.
+  bool compiled_to_elf() const;
 
  private:
-  static constexpr intptr_t kHeaderFields = 2;
+  // Word-sized fields in an Image object header.
+  enum class HeaderField : intptr_t {
+    // The size of the image (total of header and payload).
+    ImageSize,
+    // The offset of the ImageHeader object in the image. Note this offset
+    // is from the start of the _image_, _not_ from its payload start, so we
+    // can detect images without ImageHeaders by a 0 value here.
+    ImageHeaderOffset,
+    // If adding more fields, updating kHeaderFields below. (However, more
+    // fields _can't_ be added on 64-bit architectures, see the restrictions
+    // on kHeaderSize below.)
+  };
+
+  // Number of fields described by the HeaderField enum.
+  static constexpr intptr_t kHeaderFields =
+      static_cast<intptr_t>(HeaderField::ImageHeaderOffset) + 1;
+
+  static uword FieldValue(uword raw_memory, HeaderField field) {
+    return reinterpret_cast<const uword*>(
+        raw_memory)[static_cast<intptr_t>(field)];
+  }
+
+  // Constants used to denote special values for the offsets in the Image
+  // object header and the fields of the ImageHeader object.
+  static constexpr intptr_t kNoImageHeader = 0;
+  static constexpr intptr_t kNoBssSection = 0;
+  static constexpr intptr_t kNoRelocatedAddress = 0;
+  static constexpr intptr_t kNoBuildId = 0;
+
+  // The size of the Image object header.
+  //
+  // Note: Image::kHeaderSize is _not_ an architecture-dependent constant,
+  // and so there is no compiler::target::Image::kHeaderSize.
   static constexpr intptr_t kHeaderSize = kMaxObjectAlignment;
   // Explicitly double-checking kHeaderSize is never changed. Increasing the
   // Image header size would mean objects would not start at a place expected
   // by parts of the VM (like the GC) that use Image pages as HeapPages.
   static_assert(kHeaderSize == kMaxObjectAlignment,
                 "Image page cannot be used as HeapPage");
+  // Make sure that the number of fields in the Image header fit both on the
+  // host and target architectures.
+  static_assert(kHeaderFields * kWordSize <= kHeaderSize,
+                "Too many fields in Image header for host architecture");
+  static_assert(kHeaderFields * compiler::target::kWordSize <= kHeaderSize,
+                "Too many fields in Image header for target architecture");
 
-  // Determines how many bits we have for encoding any extra information in
-  // the BSS offset.
-  static constexpr intptr_t kBssAlignment = compiler::target::kWordSize;
+  // We don't use a handle or the tagged pointer because this object cannot be
+  // moved in memory by the GC.
+  static const ImageHeaderLayout* ExtraInfo(const uword raw_memory,
+                                            const uword size);
 
-  const void* raw_memory_;  // The symbol kInstructionsSnapshot.
+  // Most internal uses would cast this to uword, so just store it as such.
+  const uword raw_memory_;
+  const intptr_t snapshot_size_;
+  const ImageHeaderLayout* const extra_info_;
 
   // For access to private constants.
   friend class AssemblyImageWriter;
   friend class BlobImageWriter;
   friend class ImageWriter;
-  friend class Elf;
 
   DISALLOW_COPY_AND_ASSIGN(Image);
 };
@@ -178,12 +231,35 @@
   explicit ImageWriter(Thread* thread);
   virtual ~ImageWriter() {}
 
+  // Alignment constants used in writing ELF or assembly snapshots.
+
+  // BSS sections contain word-sized data.
+  static constexpr intptr_t kBssAlignment = compiler::target::kWordSize;
+  // ROData sections contain objects wrapped in an Image object.
+  static constexpr intptr_t kRODataAlignment = kMaxObjectAlignment;
+  // Text sections contain objects (even in bare instructions mode) wrapped
+  // in an Image object, and for now we also align them to the same page
+  // size assumed by Elf objects.
+  static_assert(Elf::kPageSize >= kMaxObjectAlignment,
+                "Page alignment must be consistent with max object alignment");
+  static constexpr intptr_t kTextAlignment = Elf::kPageSize;
+
   void ResetOffsets() {
     next_data_offset_ = Image::kHeaderSize;
     next_text_offset_ = Image::kHeaderSize;
-    if (FLAG_use_bare_instructions && FLAG_precompiled_mode) {
-      next_text_offset_ += compiler::target::InstructionsSection::HeaderSize();
+#if defined(DART_PRECOMPILER)
+    if (FLAG_precompiled_mode) {
+      // We reserve space for the initial ImageHeader object. It is manually
+      // serialized since it involves offsets to other parts of the snapshot.
+      next_text_offset_ += compiler::target::ImageHeader::InstanceSize();
+      if (FLAG_use_bare_instructions) {
+        // For bare instructions mode, we wrap all the instruction payloads
+        // in a single InstructionsSection object.
+        next_text_offset_ +=
+            compiler::target::InstructionsSection::HeaderSize();
+      }
     }
+#endif
     objects_.Clear();
     instructions_.Clear();
   }
@@ -201,7 +277,7 @@
   int32_t GetTextOffsetFor(InstructionsPtr instructions, CodePtr code);
   uint32_t GetDataOffsetFor(ObjectPtr raw_object);
 
-  void Write(WriteStream* clustered_stream, bool vm);
+  void Write(NonStreamingWriteStream* clustered_stream, bool vm);
   intptr_t data_size() const { return next_data_offset_; }
   intptr_t text_size() const { return next_text_offset_; }
   intptr_t GetTextObjectCount() const;
@@ -254,8 +330,9 @@
   static const char* TagObjectTypeAsReadOnly(Zone* zone, const char* type);
 
  protected:
-  void WriteROData(WriteStream* stream);
-  virtual void WriteText(WriteStream* clustered_stream, bool vm) = 0;
+  virtual void WriteBss(bool vm) = 0;
+  virtual void WriteROData(NonStreamingWriteStream* clustered_stream, bool vm);
+  virtual void WriteText(bool vm) = 0;
 
   void DumpInstructionStats();
   void DumpInstructionsSizes();
@@ -309,6 +386,8 @@
   V8SnapshotProfileWriter::IdSpace offset_space_ =
       V8SnapshotProfileWriter::kSnapshot;
   V8SnapshotProfileWriter* profile_writer_ = nullptr;
+  const char* const image_type_;
+  const char* const image_header_type_;
   const char* const instructions_section_type_;
   const char* const instructions_type_;
   const char* const trampoline_type_;
@@ -337,14 +416,13 @@
         stream_(ASSERT_NOTNULL(stream)),
         section_offset_(section_offset),
         start_offset_(stream_->Position() - section_offset),
-        object_(object) {}
+        object_type_(writer->ObjectTypeForProfile(object)) {}
 
   ~TraceImageObjectScope() {
     if (writer_->profile_writer_ == nullptr) return;
     ASSERT(writer_->IsROSpace());
     writer_->profile_writer_->SetObjectTypeAndName(
-        {writer_->offset_space_, start_offset_},
-        writer_->ObjectTypeForProfile(object_), nullptr);
+        {writer_->offset_space_, start_offset_}, object_type_, nullptr);
     writer_->profile_writer_->AttributeBytesTo(
         {writer_->offset_space_, start_offset_},
         stream_->Position() - section_offset_ - start_offset_);
@@ -355,7 +433,7 @@
   const T* const stream_;
   const intptr_t section_offset_;
   const intptr_t start_offset_;
-  const Object& object_;
+  const char* const object_type_;
 };
 
 class SnapshotTextObjectNamer {
@@ -385,15 +463,16 @@
 class AssemblyImageWriter : public ImageWriter {
  public:
   AssemblyImageWriter(Thread* thread,
-                      Dart_StreamingWriteCallback callback,
-                      void* callback_data,
+                      BaseWriteStream* stream,
                       bool strip = false,
                       Elf* debug_elf = nullptr);
   void Finalize();
 
-  virtual void WriteText(WriteStream* clustered_stream, bool vm);
-
  private:
+  virtual void WriteBss(bool vm);
+  virtual void WriteROData(NonStreamingWriteStream* clustered_stream, bool vm);
+  virtual void WriteText(bool vm);
+
   void FrameUnwindPrologue();
   void FrameUnwindEpilogue();
   intptr_t WriteByteSequence(uword start, uword end);
@@ -408,16 +487,16 @@
   intptr_t WriteWordLiteralText(compiler::target::uword value) {
     // Padding is helpful for comparing the .S with --disassemble.
 #if defined(TARGET_ARCH_IS_64_BIT)
-    assembly_stream_.Print(".quad 0x%0.16" Px "\n", value);
+    assembly_stream_->Print(".quad 0x%0.16" Px "\n", value);
 #else
-    assembly_stream_.Print(".long 0x%0.8" Px "\n", value);
+    assembly_stream_->Print(".long 0x%0.8" Px "\n", value);
 #endif
     return compiler::target::kWordSize;
   }
 
-  StreamingWriteStream assembly_stream_;
-  Dwarf* assembly_dwarf_;
-  Elf* debug_elf_;
+  BaseWriteStream* const assembly_stream_;
+  Dwarf* const assembly_dwarf_;
+  Elf* const debug_elf_;
 
   DISALLOW_COPY_AND_ASSIGN(AssemblyImageWriter);
 };
@@ -425,22 +504,22 @@
 class BlobImageWriter : public ImageWriter {
  public:
   BlobImageWriter(Thread* thread,
-                  uint8_t** instructions_blob_buffer,
-                  ReAlloc alloc,
-                  intptr_t initial_size,
+                  NonStreamingWriteStream* stream,
                   Elf* debug_elf = nullptr,
                   Elf* elf = nullptr);
 
-  virtual void WriteText(WriteStream* clustered_stream, bool vm);
-
   intptr_t InstructionsBlobSize() const {
-    return instructions_blob_stream_.bytes_written();
+    return instructions_blob_stream_->bytes_written();
   }
 
  private:
+  virtual void WriteBss(bool vm);
+  virtual void WriteROData(NonStreamingWriteStream* clustered_stream, bool vm);
+  virtual void WriteText(bool vm);
+
   intptr_t WriteByteSequence(uword start, uword end);
 
-  WriteStream instructions_blob_stream_;
+  NonStreamingWriteStream* instructions_blob_stream_;
   Elf* const elf_;
   Elf* const debug_elf_;
 
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 119901a..e835735 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -13,6 +13,7 @@
 #include "platform/unicode.h"
 #include "vm/bit_vector.h"
 #include "vm/bootstrap.h"
+#include "vm/canonical_tables.h"
 #include "vm/class_finalizer.h"
 #include "vm/code_comments.h"
 #include "vm/code_descriptors.h"
@@ -57,7 +58,6 @@
 #include "vm/tags.h"
 #include "vm/thread_registry.h"
 #include "vm/timeline.h"
-#include "vm/type_table.h"
 #include "vm/type_testing_stubs.h"
 #include "vm/zone_text_buffer.h"
 
@@ -16051,6 +16051,10 @@
 }
 #endif
 
+const char* ImageHeader::ToCString() const {
+  return "ImageHeader";
+}
+
 const char* WeakSerializationReference::ToCString() const {
 #if defined(DART_PRECOMPILED_RUNTIME)
   return Symbols::OptimizedOut().ToCString();
@@ -24400,8 +24404,7 @@
 static void PrintNonSymbolicStackFrameBody(BaseTextBuffer* buffer,
                                            uword call_addr,
                                            uword isolate_instructions,
-                                           uword vm_instructions,
-                                           uword isolate_relocated_address) {
+                                           uword vm_instructions) {
   const Image vm_image(reinterpret_cast<const void*>(vm_instructions));
   const Image isolate_image(
       reinterpret_cast<const void*>(isolate_instructions));
@@ -24412,7 +24415,9 @@
     // Only print the relocated address of the call when we know the saved
     // debugging information (if any) will have the same relocated address.
     if (isolate_image.compiled_to_elf()) {
-      buffer->Printf(" virt %" Pp "", isolate_relocated_address + offset);
+      const uword relocated_section_start =
+          isolate_image.instructions_relocated_address();
+      buffer->Printf(" virt %" Pp "", relocated_section_start + offset);
     }
     buffer->Printf(" %s+0x%" Px "", symbol_name, offset);
   } else if (vm_image.contains(call_addr)) {
@@ -24484,16 +24489,6 @@
   PrintSymbolicStackFrameBody(buffer, function_name, url, line, column);
 }
 
-// Find the relocated base of the given instructions section.
-uword InstructionsRelocatedAddress(uword instructions_start) {
-  Image image(reinterpret_cast<const uint8_t*>(instructions_start));
-  auto const bss_start =
-      reinterpret_cast<const uword*>(instructions_start + image.bss_offset());
-  auto const index =
-      BSS::RelocationIndex(BSS::Relocation::InstructionsRelocatedAddress);
-  return bss_start[index];
-}
-
 const char* StackTrace::ToCString() const {
   auto const T = Thread::Current();
   auto const zone = T->zone();
@@ -24512,11 +24507,15 @@
       T->isolate_group()->source()->snapshot_instructions);
   auto const vm_instructions = reinterpret_cast<uword>(
       Dart::vm_isolate()->group()->source()->snapshot_instructions);
-  auto const vm_relocated_address =
-      InstructionsRelocatedAddress(vm_instructions);
-  auto const isolate_relocated_address =
-      InstructionsRelocatedAddress(isolate_instructions);
   if (FLAG_dwarf_stack_traces_mode) {
+    const Image isolate_instructions_image(
+        reinterpret_cast<const void*>(isolate_instructions));
+    const Image vm_instructions_image(
+        reinterpret_cast<const void*>(vm_instructions));
+    auto const isolate_relocated_address =
+        isolate_instructions_image.instructions_relocated_address();
+    auto const vm_relocated_address =
+        vm_instructions_image.instructions_relocated_address();
     // The Dart standard requires the output of StackTrace.toString to include
     // all pending activations with precise source locations (i.e., to expand
     // inlined frames and provide line and column numbers).
@@ -24530,6 +24529,14 @@
     OSThread* thread = OSThread::Current();
     buffer.Printf("pid: %" Pd ", tid: %" Pd ", name %s\n", OS::ProcessId(),
                   OSThread::ThreadIdToIntPtr(thread->id()), thread->name());
+    if (auto const build_id = isolate_instructions_image.build_id()) {
+      const intptr_t length = isolate_instructions_image.build_id_length();
+      buffer.Printf("build_id: '");
+      for (intptr_t i = 0; i < length; i++) {
+        buffer.Printf("%02.2x", build_id[i]);
+      }
+      buffer.Printf("'\n");
+    }
     // Print the dso_base of the VM and isolate_instructions. We print both here
     // as the VM and isolate may be loaded from different snapshot images.
     buffer.Printf("isolate_dso_base: %" Px "",
@@ -24591,8 +24598,7 @@
             // prints call addresses instead of return addresses.
             buffer.Printf("    #%02" Pd " abs %" Pp "", frame_index, call_addr);
             PrintNonSymbolicStackFrameBody(
-                &buffer, call_addr, isolate_instructions, vm_instructions,
-                isolate_relocated_address);
+                &buffer, call_addr, isolate_instructions, vm_instructions);
             frame_index++;
             continue;
           } else if (function.IsNull()) {
@@ -24601,8 +24607,7 @@
             // non-symbolic stack traces.
             PrintSymbolicStackFrameIndex(&buffer, frame_index);
             PrintNonSymbolicStackFrameBody(
-                &buffer, call_addr, isolate_instructions, vm_instructions,
-                isolate_relocated_address);
+                &buffer, call_addr, isolate_instructions, vm_instructions);
             frame_index++;
             continue;
           }
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 22e2810..5084dff 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -5959,6 +5959,26 @@
   friend class Object;
 };
 
+// An ImageHeader contains extra information about serialized AOT snapshots.
+//
+// To avoid changing the embedder to return more information about an AOT
+// snapshot and possibly disturbing existing clients of that interface, we
+// serialize a single ImageHeader object at the start of any text segments.
+class ImageHeader : public Object {
+ public:
+  static intptr_t InstanceSize() {
+    return RoundedAllocationSize(sizeof(ImageHeaderLayout));
+  }
+  // There are no public methods for the ImageHeader contents, because
+  // all access to the contents is handled by methods on the Image class.
+
+ private:
+  // Note there are no New() methods for ImageHeaders. Unstead, the serializer
+  // writes the ImageHeaderLayout object manually at the start of the text
+  // segment in precompiled snapshots.
+  FINAL_HEAP_OBJECT_IMPLEMENTATION(ImageHeader, Object);
+};
+
 // A WeakSerializationReference (WSR) denotes a type of weak reference to a
 // target object. In particular, objects that can only be reached from roots via
 // WSR edges during serialization of AOT snapshots should not be serialized. Of
diff --git a/runtime/vm/object_service.cc b/runtime/vm/object_service.cc
index 319cff6..80eb1e8 100644
--- a/runtime/vm/object_service.cc
+++ b/runtime/vm/object_service.cc
@@ -2,13 +2,13 @@
 // 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.
 
+#include "vm/canonical_tables.h"
 #include "vm/compiler/assembler/disassembler.h"
 #include "vm/debugger.h"
 #include "vm/object.h"
 #include "vm/object_store.h"
 #include "vm/stub_code.h"
 #include "vm/symbols.h"
-#include "vm/type_table.h"
 
 namespace dart {
 
@@ -684,6 +684,10 @@
   Object::PrintJSONImpl(stream, ref);
 }
 
+void ImageHeader::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  Object::PrintJSONImpl(stream, ref);
+}
+
 void WeakSerializationReference::PrintJSONImpl(JSONStream* stream,
                                                bool ref) const {
   JSONObject jsobj(stream);
diff --git a/runtime/vm/raw_object.cc b/runtime/vm/raw_object.cc
index 3dfd910..de63846 100644
--- a/runtime/vm/raw_object.cc
+++ b/runtime/vm/raw_object.cc
@@ -223,6 +223,10 @@
       instance_size = element->HeapSize();
       break;
     }
+    case kImageHeaderCid: {
+      instance_size = ImageHeader::InstanceSize();
+      break;
+    }
     case kWeakSerializationReferenceCid: {
       instance_size = WeakSerializationReference::InstanceSize();
       break;
@@ -564,6 +568,7 @@
 NULL_VISITOR(Capability)
 NULL_VISITOR(SendPort)
 NULL_VISITOR(TransferableTypedData)
+NULL_VISITOR(ImageHeader)
 REGULAR_VISITOR(Pointer)
 NULL_VISITOR(DynamicLibrary)
 VARIABLE_NULL_VISITOR(Instructions, Instructions::Size(raw_obj))
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 39e0254..82b9df0 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -1404,6 +1404,25 @@
   }
 };
 
+class ImageHeaderLayout : public ObjectLayout {
+  RAW_HEAP_OBJECT_IMPLEMENTATION(ImageHeader);
+
+  VISIT_NOTHING();
+  // The offset of the corresponding BSS section from this text section.
+  uword bss_offset_;
+  // The relocated address of this text section in the shared object. Properly
+  // filled for ELF snapshots, always 0 in assembly snapshots. (For the latter,
+  // we instead get the value during BSS initialization and store it there.)
+  uword instructions_relocated_address_;
+  // The offset of the GNU build ID section description field from this text
+  // section.
+  uword build_id_offset_;
+  // The length of the GNU build ID section description field.
+  uword build_id_length_;
+
+  friend class Image;
+};
+
 class WeakSerializationReferenceLayout : public ObjectLayout {
   RAW_HEAP_OBJECT_IMPLEMENTATION(WeakSerializationReference);
 
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index 68a56b3..36deccf 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -582,6 +582,7 @@
 MESSAGE_SNAPSHOT_UNREACHABLE(UnwindError);
 MESSAGE_SNAPSHOT_UNREACHABLE(FutureOr);
 MESSAGE_SNAPSHOT_UNREACHABLE(WeakSerializationReference);
+MESSAGE_SNAPSHOT_UNREACHABLE(ImageHeader);
 
 MESSAGE_SNAPSHOT_ILLEGAL(DynamicLibrary);
 MESSAGE_SNAPSHOT_ILLEGAL(MirrorReference);
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index e20e9a9..2c7a938 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -13,6 +13,7 @@
 
 #include "platform/unicode.h"
 #include "vm/base64.h"
+#include "vm/canonical_tables.h"
 #include "vm/compiler/jit/compiler.h"
 #include "vm/cpu.h"
 #include "vm/dart_api_impl.h"
@@ -45,7 +46,6 @@
 #include "vm/stack_frame.h"
 #include "vm/symbols.h"
 #include "vm/timeline.h"
-#include "vm/type_table.h"
 #include "vm/version.h"
 
 namespace dart {
diff --git a/runtime/vm/service/service_extension.md b/runtime/vm/service/service_extension.md
index 7bdca7f..b564c2a 100644
--- a/runtime/vm/service/service_extension.md
+++ b/runtime/vm/service/service_extension.md
@@ -108,6 +108,7 @@
 ### getHttpEnableTimelineLogging
 
 ```
+@Deprecated
 HttpTimelineLoggingState getHttpEnableTimelineLogging(string isolateId)
 ```
 
@@ -120,6 +121,7 @@
 ### setHttpEnableTimelineLogging
 
 ```
+@Deprecated
 Success setHttpEnableTimelineLogging(string isolateId, bool enable)
 ```
 
@@ -130,6 +132,22 @@
 
 See [Success](#success).
 
+### httpEnableTimelineLogging
+
+```
+HttpTimelineLoggingState httpEnableTimelineLogging(string isolateId, bool enable [optional])
+```
+
+The _httpEnableTimelineLogging_ RPC is used to set and inspect the value of
+`HttpClient.enableTimelineLogging`, which determines if HTTP client requests
+should be logged to the timeline. If `enable` is provided, the state of
+`HttpClient.enableTimelineLogging` will be updated to the value of `enable`.
+
+If the value of `HttpClient.enableTimelineLogging` is changed, a
+`HttpTimelineLoggingStateChange` event will be sent on the `Extension` stream.
+
+See [HttpTimelineLoggingState](#httptimelineloggingstate).
+
 ## Public Types
 
 ### File
@@ -325,3 +343,4 @@
 1.0 | Initial revision.
 1.1 | Added `lastReadTime` and `lastWriteTime` properties to `SocketStatistic`.
 1.2 | Added `getOpenFiles`, `getOpenFileById`, `getSpawnedProcesses`, and `getSpawnedProcessById` RPCs and added `OpenFile` and `SpawnedProcess` objects.
+1.3 | Added `httpEnableTimelineLogging` RPC and `HttpTimelineLoggingStateChange` event, deprecated `getHttpEnableTimelineLogging` and `setHttpEnableTimelineLogging`.
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index 607f35d..c8a05fa 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -907,12 +907,10 @@
 
 SnapshotWriter::SnapshotWriter(Thread* thread,
                                Snapshot::Kind kind,
-                               ReAlloc alloc,
-                               DeAlloc dealloc,
                                intptr_t initial_size,
                                ForwardList* forward_list,
                                bool can_send_any_object)
-    : BaseWriter(alloc, dealloc, initial_size),
+    : BaseWriter(initial_size),
       thread_(thread),
       kind_(kind),
       object_store_(isolate()->object_store()),
@@ -1576,22 +1574,9 @@
   }
 }
 
-static uint8_t* malloc_allocator(uint8_t* ptr,
-                                 intptr_t old_size,
-                                 intptr_t new_size) {
-  void* new_ptr = realloc(reinterpret_cast<void*>(ptr), new_size);
-  return reinterpret_cast<uint8_t*>(new_ptr);
-}
-
-static void malloc_deallocator(uint8_t* ptr) {
-  free(reinterpret_cast<void*>(ptr));
-}
-
 MessageWriter::MessageWriter(bool can_send_any_object)
     : SnapshotWriter(Thread::Current(),
                      Snapshot::kMessage,
-                     malloc_allocator,
-                     malloc_deallocator,
                      kInitialSize,
                      &forward_list_,
                      can_send_any_object),
@@ -1629,9 +1614,10 @@
   }
 
   MessageFinalizableData* finalizable_data = finalizable_data_;
-  finalizable_data_ = NULL;
-  return Message::New(dest_port, buffer(), BytesWritten(), finalizable_data,
-                      priority);
+  finalizable_data_ = nullptr;
+  intptr_t size;
+  uint8_t* buffer = Steal(&size);
+  return Message::New(dest_port, buffer, size, finalizable_data, priority);
 }
 
 }  // namespace dart
diff --git a/runtime/vm/snapshot.h b/runtime/vm/snapshot.h
index 6df1270..d685fb2 100644
--- a/runtime/vm/snapshot.h
+++ b/runtime/vm/snapshot.h
@@ -429,14 +429,14 @@
 
 class BaseWriter : public StackResource {
  public:
-  uint8_t* buffer() { return stream_.buffer(); }
+  uint8_t* Steal(intptr_t* length) { return stream_.Steal(length); }
   intptr_t BytesWritten() const { return stream_.bytes_written(); }
 
   // Writes raw data to the stream (basic type).
   // sizeof(T) must be in {1,2,4,8}.
   template <typename T>
   void Write(T value) {
-    WriteStream::Raw<sizeof(T), T>::Write(&stream_, value);
+    MallocWriteStream::Raw<sizeof(T), T>::Write(&stream_, value);
   }
 
   void WriteClassIDValue(classid_t value) { Write<uint32_t>(value); }
@@ -491,13 +491,8 @@
   }
 
  protected:
-  BaseWriter(ReAlloc alloc, DeAlloc dealloc, intptr_t initial_size)
-      : StackResource(Thread::Current()),
-        buffer_(NULL),
-        stream_(&buffer_, alloc, initial_size),
-        dealloc_(dealloc) {
-    ASSERT(alloc != NULL);
-  }
+  explicit BaseWriter(intptr_t initial_size)
+      : StackResource(Thread::Current()), stream_(initial_size) {}
   ~BaseWriter() {}
 
   void ReserveHeader() {
@@ -506,21 +501,20 @@
   }
 
   void FillHeader(Snapshot::Kind kind) {
-    Snapshot* header = reinterpret_cast<Snapshot*>(stream_.buffer());
+    intptr_t length;
+    Snapshot* header = reinterpret_cast<Snapshot*>(Steal(&length));
     header->set_magic();
-    header->set_length(stream_.bytes_written());
+    header->set_length(length);
     header->set_kind(kind);
   }
 
   void FreeBuffer() {
-    dealloc_(stream_.buffer());
-    stream_.set_buffer(NULL);
+    intptr_t unused;
+    free(Steal(&unused));
   }
 
  private:
-  uint8_t* buffer_;
-  WriteStream stream_;
-  DeAlloc dealloc_;
+  MallocWriteStream stream_;
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(BaseWriter);
 };
@@ -586,8 +580,6 @@
  protected:
   SnapshotWriter(Thread* thread,
                  Snapshot::Kind kind,
-                 ReAlloc alloc,
-                 DeAlloc dealloc,
                  intptr_t initial_size,
                  ForwardList* forward_list,
                  bool can_send_any_object);
diff --git a/runtime/vm/snapshot_test.cc b/runtime/vm/snapshot_test.cc
index ed50a53..4ff7ccf 100644
--- a/runtime/vm/snapshot_test.cc
+++ b/runtime/vm/snapshot_test.cc
@@ -52,12 +52,6 @@
   return false;
 }
 
-static uint8_t* malloc_allocator(uint8_t* ptr,
-                                 intptr_t old_size,
-                                 intptr_t new_size) {
-  return reinterpret_cast<uint8_t*>(realloc(ptr, new_size));
-}
-
 // Compare two Dart_CObject object graphs rooted in first and
 // second. The second graph will be destroyed by this operation no matter
 // whether the graphs are equal or not.
@@ -755,10 +749,14 @@
     OS::PrintErr("Without Snapshot: %" Pd64 "us\n", timer1.TotalElapsedTime());
 
     // Write snapshot with object content.
-    FullSnapshotWriter writer(Snapshot::kFull, NULL,
-                              &isolate_snapshot_data_buffer, &malloc_allocator,
-                              NULL, /*image_writer*/ nullptr);
+    MallocWriteStream isolate_snapshot_data(FullSnapshotWriter::kInitialSize);
+    FullSnapshotWriter writer(
+        Snapshot::kFull, /*vm_snapshot_data=*/nullptr, &isolate_snapshot_data,
+        /*vm_image_writer=*/nullptr, /*iso_image_writer=*/nullptr);
     writer.WriteFullSnapshot();
+    // Take ownership so it doesn't get freed by the stream destructor.
+    intptr_t unused;
+    isolate_snapshot_data_buffer = isolate_snapshot_data.Steal(&unused);
   }
 
   // Now Create another isolate using the snapshot and execute a method
@@ -2019,8 +2017,6 @@
   // For performance, we'd like single-byte headers when ids are omitted.
   // If this starts failing, consider renumbering the snapshot ids.
   EXPECT_EQ(1, writer.BytesWritten());
-
-  free(writer.buffer());
 }
 
 TEST_CASE(IsKernelNegative) {
@@ -2075,12 +2071,11 @@
     // Verify that snapshot writing succeeds if erasure is not required.
     if (!required) {
       // Write snapshot with object content.
-      uint8_t* isolate_snapshot_data_buffer;
+      MallocWriteStream isolate_snapshot_data(FullSnapshotWriter::kInitialSize);
       FullSnapshotWriter writer(
-          Snapshot::kFull, NULL, &isolate_snapshot_data_buffer,
-          &malloc_allocator, NULL, /*image_writer*/ nullptr);
+          Snapshot::kFull, /*vm_snapshot_data=*/nullptr, &isolate_snapshot_data,
+          /*vm_image_writer=*/nullptr, /*iso_image_writer=*/nullptr);
       writer.WriteFullSnapshot();
-      free(isolate_snapshot_data_buffer);
     }
   }
 }
diff --git a/runtime/vm/symbols.cc b/runtime/vm/symbols.cc
index 4fb75a0..fac122b 100644
--- a/runtime/vm/symbols.cc
+++ b/runtime/vm/symbols.cc
@@ -5,6 +5,7 @@
 #include "vm/symbols.h"
 
 #include "platform/unicode.h"
+#include "vm/canonical_tables.h"
 #include "vm/handles.h"
 #include "vm/hash_table.h"
 #include "vm/heap/safepoint.h"
@@ -14,7 +15,6 @@
 #include "vm/raw_object.h"
 #include "vm/reusable_handles.h"
 #include "vm/snapshot_ids.h"
-#include "vm/type_table.h"
 #include "vm/visitor.h"
 
 namespace dart {
@@ -44,59 +44,6 @@
   return String::FromUTF16(data, len, space);
 }
 
-template <typename CharType>
-class CharArray {
- public:
-  CharArray(const CharType* data, intptr_t len) : data_(data), len_(len) {
-    hash_ = String::Hash(data, len);
-  }
-  StringPtr ToSymbol() const {
-    String& result = String::Handle(StringFrom(data_, len_, Heap::kOld));
-    result.SetCanonical();
-    result.SetHash(hash_);
-    return result.raw();
-  }
-  bool Equals(const String& other) const {
-    ASSERT(other.HasHash());
-    if (other.Hash() != hash_) {
-      return false;
-    }
-    return other.Equals(data_, len_);
-  }
-  intptr_t Hash() const { return hash_; }
-
- private:
-  const CharType* data_;
-  intptr_t len_;
-  intptr_t hash_;
-};
-typedef CharArray<uint8_t> Latin1Array;
-typedef CharArray<uint16_t> UTF16Array;
-
-class StringSlice {
- public:
-  StringSlice(const String& str, intptr_t begin_index, intptr_t length)
-      : str_(str), begin_index_(begin_index), len_(length) {
-    hash_ = is_all() ? str.Hash() : String::Hash(str, begin_index, length);
-  }
-  StringPtr ToSymbol() const;
-  bool Equals(const String& other) const {
-    ASSERT(other.HasHash());
-    if (other.Hash() != hash_) {
-      return false;
-    }
-    return other.Equals(str_, begin_index_, len_);
-  }
-  intptr_t Hash() const { return hash_; }
-
- private:
-  bool is_all() const { return begin_index_ == 0 && len_ == str_.Length(); }
-  const String& str_;
-  intptr_t begin_index_;
-  intptr_t len_;
-  intptr_t hash_;
-};
-
 StringPtr StringSlice::ToSymbol() const {
   if (is_all() && str_.IsOld()) {
     str_.SetCanonical();
@@ -110,26 +57,6 @@
   }
 }
 
-class ConcatString {
- public:
-  ConcatString(const String& str1, const String& str2)
-      : str1_(str1), str2_(str2), hash_(String::HashConcat(str1, str2)) {}
-  StringPtr ToSymbol() const;
-  bool Equals(const String& other) const {
-    ASSERT(other.HasHash());
-    if (other.Hash() != hash_) {
-      return false;
-    }
-    return other.EqualsConcat(str1_, str2_);
-  }
-  intptr_t Hash() const { return hash_; }
-
- private:
-  const String& str1_;
-  const String& str2_;
-  intptr_t hash_;
-};
-
 StringPtr ConcatString::ToSymbol() const {
   String& result = String::Handle(String::Concat(str1_, str2_, Heap::kOld));
   result.SetCanonical();
@@ -137,53 +64,6 @@
   return result.raw();
 }
 
-class SymbolTraits {
- public:
-  static const char* Name() { return "SymbolTraits"; }
-  static bool ReportStats() { return false; }
-
-  static bool IsMatch(const Object& a, const Object& b) {
-    const String& a_str = String::Cast(a);
-    const String& b_str = String::Cast(b);
-    ASSERT(a_str.HasHash());
-    ASSERT(b_str.HasHash());
-    if (a_str.Hash() != b_str.Hash()) {
-      return false;
-    }
-    intptr_t a_len = a_str.Length();
-    if (a_len != b_str.Length()) {
-      return false;
-    }
-    // Use a comparison which does not consider the state of the canonical bit.
-    return a_str.Equals(b_str, 0, a_len);
-  }
-  template <typename CharType>
-  static bool IsMatch(const CharArray<CharType>& array, const Object& obj) {
-    return array.Equals(String::Cast(obj));
-  }
-  static bool IsMatch(const StringSlice& slice, const Object& obj) {
-    return slice.Equals(String::Cast(obj));
-  }
-  static bool IsMatch(const ConcatString& concat, const Object& obj) {
-    return concat.Equals(String::Cast(obj));
-  }
-  static uword Hash(const Object& key) { return String::Cast(key).Hash(); }
-  template <typename CharType>
-  static uword Hash(const CharArray<CharType>& array) {
-    return array.Hash();
-  }
-  static uword Hash(const StringSlice& slice) { return slice.Hash(); }
-  static uword Hash(const ConcatString& concat) { return concat.Hash(); }
-  template <typename CharType>
-  static ObjectPtr NewKey(const CharArray<CharType>& array) {
-    return array.ToSymbol();
-  }
-  static ObjectPtr NewKey(const StringSlice& slice) { return slice.ToSymbol(); }
-  static ObjectPtr NewKey(const ConcatString& concat) {
-    return concat.ToSymbol();
-  }
-};
-typedef UnorderedHashSet<SymbolTraits> SymbolTable;
 
 const char* Symbols::Name(SymbolId symbol) {
   ASSERT((symbol > kIllegal) && (symbol < kNullCharId));
@@ -211,7 +91,7 @@
   // Create all predefined symbols.
   ASSERT((sizeof(names) / sizeof(const char*)) == Symbols::kNullCharId);
 
-  SymbolTable table(zone, vm_isolate->object_store()->symbol_table());
+  CanonicalStringSet table(zone, vm_isolate->object_store()->symbol_table());
 
   // First set up all the predefined string symbols.
   // Create symbols for language keywords. Some keywords are equal to
@@ -251,7 +131,7 @@
   ASSERT(vm_isolate == Dart::vm_isolate());
   Zone* zone = Thread::Current()->zone();
 
-  SymbolTable table(zone, vm_isolate->object_store()->symbol_table());
+  CanonicalStringSet table(zone, vm_isolate->object_store()->symbol_table());
 
   // Lookup all the predefined string symbols and language keyword symbols
   // and cache them in the read only handles for fast access.
@@ -292,140 +172,14 @@
   const intptr_t initial_size = (isolate == Dart::vm_isolate())
                                     ? kInitialVMIsolateSymtabSize
                                     : kInitialSymtabSize;
-  Array& array =
-      Array::Handle(HashTables::New<SymbolTable>(initial_size, Heap::kOld));
+  Array& array = Array::Handle(
+      HashTables::New<CanonicalStringSet>(initial_size, Heap::kOld));
   isolate->object_store()->set_symbol_table(array);
 }
 
-void Symbols::Compact() {
-  Thread* thread = Thread::Current();
-  ASSERT(thread->isolate() != Dart::vm_isolate());
-  HANDLESCOPE(thread);
-  Zone* zone = thread->zone();
-  ObjectStore* object_store = thread->isolate()->object_store();
-
-  // 1. Drop the tables and do a full garbage collection.
-  object_store->set_symbol_table(Object::empty_array());
-  object_store->set_canonical_types(Object::empty_array());
-  object_store->set_canonical_type_parameters(Object::empty_array());
-  object_store->set_canonical_type_arguments(Object::empty_array());
-  thread->heap()->CollectAllGarbage();
-
-  // 2. Walk the heap to find surviving canonical objects.
-  GrowableArray<String*> symbols;
-  GrowableArray<class Type*> types;
-  GrowableArray<class TypeParameter*> type_params;
-  GrowableArray<class TypeArguments*> type_args;
-  class SymbolCollector : public ObjectVisitor {
-   public:
-    SymbolCollector(Thread* thread,
-                    GrowableArray<String*>* symbols,
-                    GrowableArray<class Type*>* types,
-                    GrowableArray<class TypeParameter*>* type_params,
-                    GrowableArray<class TypeArguments*>* type_args)
-        : symbols_(symbols),
-          types_(types),
-          type_params_(type_params),
-          type_args_(type_args),
-          zone_(thread->zone()) {}
-
-    void VisitObject(ObjectPtr obj) {
-      if (obj->ptr()->IsCanonical()) {
-        if (obj->IsStringInstance()) {
-          symbols_->Add(&String::Handle(zone_, String::RawCast(obj)));
-        } else if (obj->IsType()) {
-          types_->Add(&Type::Handle(zone_, Type::RawCast(obj)));
-        } else if (obj->IsTypeParameter()) {
-          type_params_->Add(
-              &TypeParameter::Handle(zone_, TypeParameter::RawCast(obj)));
-        } else if (obj->IsTypeArguments()) {
-          type_args_->Add(
-              &TypeArguments::Handle(zone_, TypeArguments::RawCast(obj)));
-        }
-      }
-    }
-
-   private:
-    GrowableArray<String*>* symbols_;
-    GrowableArray<class Type*>* types_;
-    GrowableArray<class TypeParameter*>* type_params_;
-    GrowableArray<class TypeArguments*>* type_args_;
-    Zone* zone_;
-  };
-
-  {
-    HeapIterationScope iteration(thread);
-    SymbolCollector visitor(thread, &symbols, &types, &type_params, &type_args);
-    iteration.IterateObjects(&visitor);
-  }
-
-  // 3. Build new tables from the surviving canonical objects.
-  {
-    Array& array = Array::Handle(
-        zone,
-        HashTables::New<SymbolTable>(symbols.length() * 4 / 3, Heap::kOld));
-    SymbolTable table(zone, array.raw());
-    for (intptr_t i = 0; i < symbols.length(); i++) {
-      String& symbol = *symbols[i];
-      ASSERT(symbol.IsString());
-      ASSERT(symbol.IsCanonical());
-      bool present = table.Insert(symbol);
-      ASSERT(!present);
-    }
-    object_store->set_symbol_table(table.Release());
-  }
-
-  {
-    Array& array = Array::Handle(zone, HashTables::New<CanonicalTypeSet>(
-                                           types.length() * 4 / 3, Heap::kOld));
-    CanonicalTypeSet table(zone, array.raw());
-    for (intptr_t i = 0; i < types.length(); i++) {
-      class Type& type = *types[i];
-      ASSERT(type.IsType());
-      ASSERT(type.IsCanonical());
-      bool present = table.Insert(type);
-      // Two recursive types with different topology (and hashes) may be equal.
-      ASSERT(!present || type.IsRecursive());
-    }
-    object_store->set_canonical_types(table.Release());
-  }
-
-  {
-    Array& array =
-        Array::Handle(zone, HashTables::New<CanonicalTypeParameterSet>(
-                                type_params.length() * 4 / 3, Heap::kOld));
-    CanonicalTypeParameterSet table(zone, array.raw());
-    for (intptr_t i = 0; i < type_params.length(); i++) {
-      class TypeParameter& type_param = *type_params[i];
-      ASSERT(type_param.IsTypeParameter());
-      ASSERT(type_param.IsCanonical());
-      if (type_param.IsDeclaration()) continue;
-      bool present = table.Insert(type_param);
-      ASSERT(!present);
-    }
-    object_store->set_canonical_type_parameters(table.Release());
-  }
-
-  {
-    Array& array =
-        Array::Handle(zone, HashTables::New<CanonicalTypeArgumentsSet>(
-                                type_args.length() * 4 / 3, Heap::kOld));
-    CanonicalTypeArgumentsSet table(zone, array.raw());
-    for (intptr_t i = 0; i < type_args.length(); i++) {
-      class TypeArguments& type_arg = *type_args[i];
-      ASSERT(type_arg.IsTypeArguments());
-      ASSERT(type_arg.IsCanonical());
-      bool present = table.Insert(type_arg);
-      // Two recursive types with different topology (and hashes) may be equal.
-      ASSERT(!present || type_arg.IsRecursive());
-    }
-    object_store->set_canonical_type_arguments(table.Release());
-  }
-}
-
 void Symbols::GetStats(Isolate* isolate, intptr_t* size, intptr_t* capacity) {
   ASSERT(isolate != NULL);
-  SymbolTable table(isolate->object_store()->symbol_table());
+  CanonicalStringSet table(isolate->object_store()->symbol_table());
   *size = table.NumOccupied();
   *capacity = table.NumEntries();
   table.Release();
@@ -588,7 +342,7 @@
   {
     Isolate* vm_isolate = Dart::vm_isolate();
     data = vm_isolate->object_store()->symbol_table();
-    SymbolTable table(&key, &value, &data);
+    CanonicalStringSet table(&key, &value, &data);
     symbol ^= table.GetOrNull(str);
     table.Release();
   }
@@ -617,7 +371,7 @@
       // Uncommon case: We are at a safepoint, all mutators are stopped and we
       // have therefore exclusive access to the symbol table.
       data = object_store->symbol_table();
-      SymbolTable table(&key, &value, &data);
+      CanonicalStringSet table(&key, &value, &data);
       symbol ^= table.InsertNewOrGet(str);
       object_store->set_symbol_table(table.Release());
     } else {
@@ -626,7 +380,7 @@
       {
         SafepointReadRwLocker sl(thread, group->symbols_lock());
         data = object_store->symbol_table();
-        SymbolTable table(&key, &value, &data);
+        CanonicalStringSet table(&key, &value, &data);
         symbol ^= table.GetOrNull(str);
         table.Release();
       }
@@ -635,7 +389,7 @@
       if (symbol.IsNull()) {
         auto insert_or_get = [&]() {
           data = object_store->symbol_table();
-          SymbolTable table(&key, &value, &data);
+          CanonicalStringSet table(&key, &value, &data);
           symbol ^= table.InsertNewOrGet(str);
           object_store->set_symbol_table(table.Release());
         };
@@ -672,7 +426,7 @@
   {
     Isolate* vm_isolate = Dart::vm_isolate();
     data = vm_isolate->object_store()->symbol_table();
-    SymbolTable table(&key, &value, &data);
+    CanonicalStringSet table(&key, &value, &data);
     symbol ^= table.GetOrNull(str);
     table.Release();
   }
@@ -693,13 +447,13 @@
       RELEASE_ASSERT(FLAG_enable_isolate_groups || !USING_PRODUCT);
 #endif
       data = object_store->symbol_table();
-      SymbolTable table(&key, &value, &data);
+      CanonicalStringSet table(&key, &value, &data);
       symbol ^= table.GetOrNull(str);
       table.Release();
     } else {
       SafepointReadRwLocker sl(thread, group->symbols_lock());
       data = object_store->symbol_table();
-      SymbolTable table(&key, &value, &data);
+      CanonicalStringSet table(&key, &value, &data);
       symbol ^= table.GetOrNull(str);
       table.Release();
     }
@@ -795,7 +549,7 @@
 
 void Symbols::DumpTable(Isolate* isolate) {
   OS::PrintErr("symbols:\n");
-  SymbolTable table(isolate->object_store()->symbol_table());
+  CanonicalStringSet table(isolate->object_store()->symbol_table());
   table.Dump();
   table.Release();
 }
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index df2a0f0..84b028b 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -654,9 +654,6 @@
   // Initialize and setup a symbol table for the isolate.
   static void SetupSymbolTable(Isolate* isolate);
 
-  // Treat the symbol table as weak and collect garbage.
-  static void Compact();
-
   // Creates a Symbol given a C string that is assumed to contain
   // UTF-8 encoded characters and '\0' is considered a termination character.
   // TODO(7123) - Rename this to FromCString(....).
diff --git a/runtime/vm/tagged_pointer.h b/runtime/vm/tagged_pointer.h
index b81e29d..e1f6c15 100644
--- a/runtime/vm/tagged_pointer.h
+++ b/runtime/vm/tagged_pointer.h
@@ -127,12 +127,12 @@
   constexpr bool operator!=(const ObjectPtr& other) const {
     return tagged_pointer_ != other.tagged_pointer_;
   }
-  bool operator==(const nullptr_t& other) { return tagged_pointer_ == 0; }
-  bool operator!=(const nullptr_t& other) { return tagged_pointer_ != 0; }
-  constexpr bool operator==(const nullptr_t& other) const {
+  bool operator==(const std::nullptr_t& other) { return tagged_pointer_ == 0; }
+  bool operator!=(const std::nullptr_t& other) { return tagged_pointer_ != 0; }
+  constexpr bool operator==(const std::nullptr_t& other) const {
     return tagged_pointer_ == 0;
   }
-  constexpr bool operator!=(const nullptr_t& other) const {
+  constexpr bool operator!=(const std::nullptr_t& other) const {
     return tagged_pointer_ != 0;
   }
 
@@ -183,7 +183,7 @@
   ObjectPtr() : tagged_pointer_(0) {}
   explicit constexpr ObjectPtr(uword tagged) : tagged_pointer_(tagged) {}
   explicit constexpr ObjectPtr(intptr_t tagged) : tagged_pointer_(tagged) {}
-  constexpr ObjectPtr(nullptr_t) : tagged_pointer_(0) {}  // NOLINT
+  constexpr ObjectPtr(std::nullptr_t) : tagged_pointer_(0) {}  // NOLINT
   explicit ObjectPtr(ObjectLayout* heap_object)
       : tagged_pointer_(reinterpret_cast<uword>(heap_object) + kHeapObjectTag) {
   }
@@ -225,7 +225,7 @@
     klass##Ptr() : base##Ptr() {}                                              \
     explicit constexpr klass##Ptr(uword tagged) : base##Ptr(tagged) {}         \
     explicit constexpr klass##Ptr(intptr_t tagged) : base##Ptr(tagged) {}      \
-    constexpr klass##Ptr(nullptr_t) : base##Ptr(nullptr) {} /* NOLINT */       \
+    constexpr klass##Ptr(std::nullptr_t) : base##Ptr(nullptr) {} /* NOLINT */  \
     explicit klass##Ptr(const ObjectLayout* untagged)                          \
         : base##Ptr(reinterpret_cast<uword>(untagged) + kHeapObjectTag) {}     \
   };
@@ -242,6 +242,7 @@
 DEFINE_TAGGED_POINTER(Library, Object)
 DEFINE_TAGGED_POINTER(Namespace, Object)
 DEFINE_TAGGED_POINTER(KernelProgramInfo, Object)
+DEFINE_TAGGED_POINTER(ImageHeader, Object)
 DEFINE_TAGGED_POINTER(WeakSerializationReference, Object)
 DEFINE_TAGGED_POINTER(Code, Object)
 DEFINE_TAGGED_POINTER(Bytecode, Object)
diff --git a/runtime/vm/type_table.h b/runtime/vm/type_table.h
deleted file mode 100644
index 99fad9f..0000000
--- a/runtime/vm/type_table.h
+++ /dev/null
@@ -1,137 +0,0 @@
-// Copyright (c) 2016, 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.
-
-#ifndef RUNTIME_VM_TYPE_TABLE_H_
-#define RUNTIME_VM_TYPE_TABLE_H_
-
-#include "platform/assert.h"
-#include "vm/hash_table.h"
-#include "vm/object.h"
-
-namespace dart {
-
-class CanonicalTypeKey {
- public:
-  explicit CanonicalTypeKey(const Type& key) : key_(key) {}
-  bool Matches(const Type& arg) const { return key_.Equals(arg); }
-  uword Hash() const { return key_.Hash(); }
-  const Type& key_;
-
- private:
-  DISALLOW_ALLOCATION();
-};
-
-// Traits for looking up Canonical Type based on its hash.
-class CanonicalTypeTraits {
- public:
-  static const char* Name() { return "CanonicalTypeTraits"; }
-  static bool ReportStats() { return false; }
-
-  // Called when growing the table.
-  static bool IsMatch(const Object& a, const Object& b) {
-    ASSERT(a.IsType() && b.IsType());
-    const Type& arg1 = Type::Cast(a);
-    const Type& arg2 = Type::Cast(b);
-    return arg1.Equals(arg2) && (arg1.Hash() == arg2.Hash());
-  }
-  static bool IsMatch(const CanonicalTypeKey& a, const Object& b) {
-    ASSERT(b.IsType());
-    return a.Matches(Type::Cast(b));
-  }
-  static uword Hash(const Object& key) {
-    ASSERT(key.IsType());
-    return Type::Cast(key).Hash();
-  }
-  static uword Hash(const CanonicalTypeKey& key) { return key.Hash(); }
-  static ObjectPtr NewKey(const CanonicalTypeKey& obj) {
-    return obj.key_.raw();
-  }
-};
-typedef UnorderedHashSet<CanonicalTypeTraits> CanonicalTypeSet;
-
-class CanonicalTypeParameterKey {
- public:
-  explicit CanonicalTypeParameterKey(const TypeParameter& key) : key_(key) {}
-  bool Matches(const TypeParameter& arg) const { return key_.Equals(arg); }
-  uword Hash() const { return key_.Hash(); }
-  const TypeParameter& key_;
-
- private:
-  DISALLOW_ALLOCATION();
-};
-
-// Traits for looking up Canonical TypeParameter based on its hash.
-class CanonicalTypeParameterTraits {
- public:
-  static const char* Name() { return "CanonicalTypeParameterTraits"; }
-  static bool ReportStats() { return false; }
-
-  // Called when growing the table.
-  static bool IsMatch(const Object& a, const Object& b) {
-    ASSERT(a.IsTypeParameter() && b.IsTypeParameter());
-    const TypeParameter& arg1 = TypeParameter::Cast(a);
-    const TypeParameter& arg2 = TypeParameter::Cast(b);
-    return arg1.Equals(arg2) && (arg1.Hash() == arg2.Hash());
-  }
-  static bool IsMatch(const CanonicalTypeParameterKey& a, const Object& b) {
-    ASSERT(b.IsTypeParameter());
-    return a.Matches(TypeParameter::Cast(b));
-  }
-  static uword Hash(const Object& key) {
-    ASSERT(key.IsTypeParameter());
-    return TypeParameter::Cast(key).Hash();
-  }
-  static uword Hash(const CanonicalTypeParameterKey& key) { return key.Hash(); }
-  static ObjectPtr NewKey(const CanonicalTypeParameterKey& obj) {
-    return obj.key_.raw();
-  }
-};
-typedef UnorderedHashSet<CanonicalTypeParameterTraits>
-    CanonicalTypeParameterSet;
-
-class CanonicalTypeArgumentsKey {
- public:
-  explicit CanonicalTypeArgumentsKey(const TypeArguments& key) : key_(key) {}
-  bool Matches(const TypeArguments& arg) const {
-    return key_.Equals(arg) && (key_.Hash() == arg.Hash());
-  }
-  uword Hash() const { return key_.Hash(); }
-  const TypeArguments& key_;
-
- private:
-  DISALLOW_ALLOCATION();
-};
-
-// Traits for looking up Canonical TypeArguments based on its hash.
-class CanonicalTypeArgumentsTraits {
- public:
-  static const char* Name() { return "CanonicalTypeArgumentsTraits"; }
-  static bool ReportStats() { return false; }
-
-  // Called when growing the table.
-  static bool IsMatch(const Object& a, const Object& b) {
-    ASSERT(a.IsTypeArguments() && b.IsTypeArguments());
-    const TypeArguments& arg1 = TypeArguments::Cast(a);
-    const TypeArguments& arg2 = TypeArguments::Cast(b);
-    return arg1.Equals(arg2) && (arg1.Hash() == arg2.Hash());
-  }
-  static bool IsMatch(const CanonicalTypeArgumentsKey& a, const Object& b) {
-    ASSERT(b.IsTypeArguments());
-    return a.Matches(TypeArguments::Cast(b));
-  }
-  static uword Hash(const Object& key) {
-    ASSERT(key.IsTypeArguments());
-    return TypeArguments::Cast(key).Hash();
-  }
-  static uword Hash(const CanonicalTypeArgumentsKey& key) { return key.Hash(); }
-  static ObjectPtr NewKey(const CanonicalTypeArgumentsKey& obj) {
-    return obj.key_.raw();
-  }
-};
-typedef UnorderedHashSet<CanonicalTypeArgumentsTraits>
-    CanonicalTypeArgumentsSet;
-
-}  // namespace dart
-
-#endif  // RUNTIME_VM_TYPE_TABLE_H_
diff --git a/runtime/vm/vm_sources.gni b/runtime/vm/vm_sources.gni
index a919b39..2cd70b1 100644
--- a/runtime/vm/vm_sources.gni
+++ b/runtime/vm/vm_sources.gni
@@ -21,6 +21,7 @@
   "bootstrap_natives.h",
   "bss_relocs.cc",
   "bss_relocs.h",
+  "canonical_tables.h",
   "class_finalizer.cc",
   "class_finalizer.h",
   "class_id.h",
@@ -341,7 +342,6 @@
   "token.h",
   "token_position.cc",
   "token_position.h",
-  "type_table.h",
   "type_testing_stubs.cc",
   "type_testing_stubs.h",
   "unibrow-inl.h",
diff --git a/sdk/lib/_http/http.dart b/sdk/lib/_http/http.dart
index 151dae4..b7ca682 100644
--- a/sdk/lib/_http/http.dart
+++ b/sdk/lib/_http/http.dart
@@ -18,6 +18,7 @@
 import 'dart:developer' hide log;
 import 'dart:_internal'
     show Since, valueOfNonNullableParamWithDefault, HttpStatus;
+import 'dart:isolate' show Isolate;
 import 'dart:math';
 import 'dart:io';
 import 'dart:typed_data';
@@ -1473,8 +1474,14 @@
   ///
   /// Default is `false`.
   static set enableTimelineLogging(bool value) {
-    _enableTimelineLogging =
-        valueOfNonNullableParamWithDefault<bool>(value, false);
+    final enabled = valueOfNonNullableParamWithDefault<bool>(value, false);
+    if (enabled != _enableTimelineLogging) {
+      postEvent('HttpTimelineLoggingStateChange', {
+        'isolateId': Service.getIsolateID(Isolate.current),
+        'enabled': enabled,
+      });
+    }
+    _enableTimelineLogging = enabled;
   }
 
   /// Current state of HTTP request logging from all [HttpClient]s to the
diff --git a/sdk/lib/_internal/allowed_experiments.json b/sdk/lib/_internal/allowed_experiments.json
index 235e683..464837e 100644
--- a/sdk/lib/_internal/allowed_experiments.json
+++ b/sdk/lib/_internal/allowed_experiments.json
@@ -76,6 +76,9 @@
     "meta": {
       "experimentSet": "nullSafety"
     },
+    "native_stack_traces": {
+      "experimentSet": "nullSafety"
+    },
     "path": {
       "experimentSet": "nullSafety"
     },
diff --git a/sdk/lib/_internal/js_dev_runtime/patch/internal_patch.dart b/sdk/lib/_internal/js_dev_runtime/patch/internal_patch.dart
index 66c6bb1..f4ab556 100644
--- a/sdk/lib/_internal/js_dev_runtime/patch/internal_patch.dart
+++ b/sdk/lib/_internal/js_dev_runtime/patch/internal_patch.dart
@@ -56,3 +56,9 @@
 @patch
 Object? extractTypeArguments<T>(T instance, Function extract) =>
     dart.extractTypeArguments<T>(instance, extract);
+
+@patch
+T createSentinel<T>() => throw UnsupportedError('createSentinel');
+
+@patch
+bool isSentinel(dynamic value) => throw UnsupportedError('isSentinel');
diff --git a/sdk/lib/_internal/js_runtime/lib/foreign_helper.dart b/sdk/lib/_internal/js_runtime/lib/foreign_helper.dart
index 88ca3d2..3c9aed9 100644
--- a/sdk/lib/_internal/js_runtime/lib/foreign_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/foreign_helper.dart
@@ -277,3 +277,11 @@
   // This body is unused, only here for type analysis.
   return JS('String', '# + #', a, b);
 }
+
+/// Creates a JavaScript value that can be used as a sentinel for uninitialized
+/// late fields and variables.
+external T createJsSentinel<T>();
+
+/// Returns `true` if [value] is the sentinel JavaScript value created through
+/// [createJsSentinel].
+external bool isJsSentinel(dynamic value);
diff --git a/sdk/lib/_internal/js_runtime/lib/internal_patch.dart b/sdk/lib/_internal/js_runtime/lib/internal_patch.dart
index 2dc838d..9bf6da6 100644
--- a/sdk/lib/_internal/js_runtime/lib/internal_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/internal_patch.dart
@@ -7,7 +7,8 @@
 import 'dart:_js_primitives' show printString;
 import 'dart:_js_helper' show patch;
 import 'dart:_interceptors' show JSArray;
-import 'dart:_foreign_helper' show JS, JS_GET_FLAG;
+import 'dart:_foreign_helper'
+    show JS, JS_GET_FLAG, createJsSentinel, isJsSentinel;
 
 @patch
 @pragma('dart2js:tryInline')
@@ -64,3 +65,11 @@
   // the returned value flows to the result of extractTypeArguments.
   return extract();
 }
+
+@patch
+@pragma('dart2js:tryInline')
+T createSentinel<T>() => createJsSentinel<T>();
+
+@patch
+@pragma('dart2js:tryInline')
+bool isSentinel(dynamic value) => isJsSentinel(value);
diff --git a/sdk/lib/_internal/js_runtime/lib/native_typed_data.dart b/sdk/lib/_internal/js_runtime/lib/native_typed_data.dart
index 6e19c50..6a7b7b3 100644
--- a/sdk/lib/_internal/js_runtime/lib/native_typed_data.dart
+++ b/sdk/lib/_internal/js_runtime/lib/native_typed_data.dart
@@ -1297,7 +1297,7 @@
   /// Extract the sign bit from each lane return them in the first 4 bits.
   int get signMask {
     var view = _uint32view;
-    var mx, my, mz, mw;
+    int mx, my, mz, mw;
     _list[0] = x;
     _list[1] = y;
     _list[2] = z;
diff --git a/sdk/lib/_internal/js_runtime/pubspec.yaml b/sdk/lib/_internal/js_runtime/pubspec.yaml
index 96abf65..f42b2cd 100644
--- a/sdk/lib/_internal/js_runtime/pubspec.yaml
+++ b/sdk/lib/_internal/js_runtime/pubspec.yaml
@@ -2,5 +2,3 @@
 # make it easier to develop on dart2js.
 name: js_runtime
 publish_to: none
-environment:
-  sdk: '>=2.10.0-0.0 <3.0.0'
diff --git a/sdk/lib/_internal/sdk_library_metadata/pubspec.yaml b/sdk/lib/_internal/sdk_library_metadata/pubspec.yaml
index 8f46e53..79b69ee 100644
--- a/sdk/lib/_internal/sdk_library_metadata/pubspec.yaml
+++ b/sdk/lib/_internal/sdk_library_metadata/pubspec.yaml
@@ -2,5 +2,3 @@
 # make it easer to depend on libraries.dart from sdk packages like dart2js.
 name: sdk_library_metadata
 publish_to: none
-environment:
-  sdk: '>=2.10.0-0.0 <3.0.0'
diff --git a/sdk/lib/_internal/vm/lib/internal_patch.dart b/sdk/lib/_internal/vm/lib/internal_patch.dart
index fa16bc6..812f18f 100644
--- a/sdk/lib/_internal/vm/lib/internal_patch.dart
+++ b/sdk/lib/_internal/vm/lib/internal_patch.dart
@@ -188,3 +188,9 @@
   // This function can be used by tests to enforce garbage collection.
   static void collectAllGarbage() native "Internal_collectAllGarbage";
 }
+
+@patch
+T createSentinel<T>() => throw UnsupportedError('createSentinel');
+
+@patch
+bool isSentinel(dynamic value) => throw UnsupportedError('isSentinel');
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index 8da9d66..5c42772 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -13739,7 +13739,7 @@
       contextElement = _parseDocument!.createElement(tagName);
       _parseDocument!.body!.append(contextElement);
     }
-    var fragment;
+    DocumentFragment fragment;
     if (Range.supportsCreateContextualFragment &&
         _canBeUsedToCreateContextualFragment) {
       _parseRange!.selectNodeContents(contextElement);
diff --git a/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart b/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
index 21640b2..1b501e9 100644
--- a/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
+++ b/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
@@ -473,7 +473,7 @@
           'version and onUpgradeNeeded must be specified together'));
     }
     try {
-      var request;
+      OpenDBRequest request;
       if (version != null) {
         request = _open(name, version);
       } else {
diff --git a/sdk/lib/internal/internal_sources.gni b/sdk/lib/internal/internal_sources.gni
index c35e678..25b98b9 100644
--- a/sdk/lib/internal/internal_sources.gni
+++ b/sdk/lib/internal/internal_sources.gni
@@ -14,6 +14,7 @@
   "iterable.dart",
   "linked_list.dart",
   "list.dart",
+  "lowering.dart",
   "print.dart",
   "sort.dart",
   "symbol.dart",
diff --git a/sdk/lib/internal/lowering.dart b/sdk/lib/internal/lowering.dart
new file mode 100644
index 0000000..30a0cea
--- /dev/null
+++ b/sdk/lib/internal/lowering.dart
@@ -0,0 +1,9 @@
+// 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.
+
+part of dart._internal;
+
+external T createSentinel<T>();
+
+external bool isSentinel(dynamic value);
diff --git a/sdk/lib/io/network_profiling.dart b/sdk/lib/io/network_profiling.dart
index 7121d3c..cb3d1ba 100644
--- a/sdk/lib/io/network_profiling.dart
+++ b/sdk/lib/io/network_profiling.dart
@@ -6,7 +6,7 @@
 
 // TODO(bkonyi): refactor into io_resource_info.dart
 const int _versionMajor = 1;
-const int _versionMinor = 2;
+const int _versionMinor = 3;
 
 const String _tcpSocket = 'tcp';
 const String _udpSocket = 'udp';
@@ -14,10 +14,14 @@
 @pragma('vm:entry-point', !const bool.fromEnvironment("dart.vm.product"))
 abstract class _NetworkProfiling {
   // Http relative RPCs
+  @Deprecated('Use httpEnableTimelineLogging instead')
   static const _kGetHttpEnableTimelineLogging =
       'ext.dart.io.getHttpEnableTimelineLogging';
+  @Deprecated('Use httpEnableTimelineLogging instead')
   static const _kSetHttpEnableTimelineLogging =
       'ext.dart.io.setHttpEnableTimelineLogging';
+  static const _kHttpEnableTimelineLogging =
+      'ext.dart.io.httpEnableTimelineLogging';
   // Socket relative RPCs
   static const _kClearSocketProfileRPC = 'ext.dart.io.clearSocketProfile';
   static const _kGetSocketProfileRPC = 'ext.dart.io.getSocketProfile';
@@ -33,6 +37,7 @@
   static void _registerServiceExtension() {
     registerExtension(_kGetHttpEnableTimelineLogging, _serviceExtensionHandler);
     registerExtension(_kSetHttpEnableTimelineLogging, _serviceExtensionHandler);
+    registerExtension(_kHttpEnableTimelineLogging, _serviceExtensionHandler);
     registerExtension(_kGetSocketProfileRPC, _serviceExtensionHandler);
     registerExtension(_kStartSocketProfilingRPC, _serviceExtensionHandler);
     registerExtension(_kPauseSocketProfilingRPC, _serviceExtensionHandler);
@@ -51,6 +56,12 @@
         case _kSetHttpEnableTimelineLogging:
           responseJson = _setHttpEnableTimelineLogging(parameters);
           break;
+        case _kHttpEnableTimelineLogging:
+          if (parameters.containsKey('enable')) {
+            _setHttpEnableTimelineLogging(parameters);
+          }
+          responseJson = _getHttpEnableTimelineLogging();
+          break;
         case _kGetSocketProfileRPC:
           responseJson = _SocketProfile.toJson();
           break;
@@ -108,7 +119,7 @@
   if (enable != 'true' && enable != 'false') {
     throw _invalidArgument(kEnable, enable);
   }
-  HttpClient.enableTimelineLogging = (enable == 'true');
+  HttpClient.enableTimelineLogging = enable == 'true';
   return _success();
 }
 
diff --git a/tests/co19/co19-co19.status b/tests/co19/co19-co19.status
index 358ce45..1ca6f0b 100644
--- a/tests/co19/co19-co19.status
+++ b/tests/co19/co19-co19.status
@@ -41,7 +41,6 @@
 LanguageFeatures/Simple-bounds/dynamic/type-aliases/*: Skip # Not migrated to NNBD
 LanguageFeatures/Simple-bounds/static/*: Skip # Not migrated to NNBD
 LanguageFeatures/Simple-bounds/static/type-aliases/*: Skip # Not migrated to NNBD
-LanguageFeatures/Spread-collections/*: Skip # Not migrated to NNBD
 LanguageFeatures/Triple-Shift/*: Skip # Triple shift is not implemented yet
 LanguageFeatures/regression/34560_t02/01: Skip # Type aliases are not fully implemented
 LibTest/io/RawDatagramSocket/*: Skip # https://github.com/dart-lang/co19/issues/195
diff --git a/tests/dart2js/native/native_null_assertions/flag_disabled_test.dart b/tests/dart2js/native/native_null_assertions/flag_disabled_test.dart
new file mode 100644
index 0000000..e307833
--- /dev/null
+++ b/tests/dart2js/native/native_null_assertions/flag_disabled_test.dart
@@ -0,0 +1,11 @@
+// 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.
+
+import 'null_assertions_test_lib.dart';
+
+void main() {
+  var flagEnabled = false;
+  testNativeNullAssertions(flagEnabled);
+  testJSInvocationNullAssertions(flagEnabled);
+}
diff --git a/tests/dart2js/native/native_null_assertions/flag_enabled_test.dart b/tests/dart2js/native/native_null_assertions/flag_enabled_test.dart
new file mode 100644
index 0000000..0eb3965
--- /dev/null
+++ b/tests/dart2js/native/native_null_assertions/flag_enabled_test.dart
@@ -0,0 +1,13 @@
+// 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.
+
+// dart2jsOptions=--native-null-assertions
+
+import 'null_assertions_test_lib.dart';
+
+void main() {
+  var flagEnabled = true;
+  testNativeNullAssertions(flagEnabled);
+  testJSInvocationNullAssertions(flagEnabled);
+}
diff --git a/tests/dart2js/native/native_null_assertions/js_invocations_in_non_web_library.dart b/tests/dart2js/native/native_null_assertions/js_invocations_in_non_web_library.dart
new file mode 100644
index 0000000..9dd2be1
--- /dev/null
+++ b/tests/dart2js/native/native_null_assertions/js_invocations_in_non_web_library.dart
@@ -0,0 +1,16 @@
+// 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.
+
+import '../native_testing.dart';
+import 'null_assertions_lib.dart';
+
+// Implementation of `JSInterface` except in a folder that is not part of the
+// allowlist for the `--native-null-assertions` flag. This file is not treated
+// as a web library, and therefore the `JS()` invocations should not be checked.
+
+@Native('CCCInNonWebLibrary')
+class CCCInNonWebLibrary implements JSInterface {
+  String get name => JS('String', '#.name', this);
+  String? get optName => JS('String|Null', '#.optName', this);
+}
diff --git a/tests/dart2js/native/native_null_assertions/js_invocations_in_web_library.dart b/tests/dart2js/native/native_null_assertions/js_invocations_in_web_library.dart
new file mode 100644
index 0000000..0554ab4
--- /dev/null
+++ b/tests/dart2js/native/native_null_assertions/js_invocations_in_web_library.dart
@@ -0,0 +1,16 @@
+// 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.
+
+import '../native_testing.dart';
+import 'null_assertions_lib.dart';
+
+// Implementation of `JSInterface` in a folder that is explicitly part of the
+// allowlist for the `--native-null-assertions` flag. This file is treated as a
+// web library, and therefore the `JS()` invocations should be checked.
+
+@Native('CCCInWebLibrary')
+class CCCInWebLibrary implements JSInterface {
+  String get name => JS('String', '#.name', this);
+  String? get optName => JS('String|Null', '#.optName', this);
+}
diff --git a/tests/dart2js/native/native_null_assertions/null_assertions_lib.dart b/tests/dart2js/native/native_null_assertions/null_assertions_lib.dart
new file mode 100644
index 0000000..894fdf0
--- /dev/null
+++ b/tests/dart2js/native/native_null_assertions/null_assertions_lib.dart
@@ -0,0 +1,38 @@
+// 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.
+
+import '../native_testing.dart';
+
+abstract class NativeInterface {
+  int get size;
+  String get name;
+  String? get optName;
+  int method1();
+  String method2();
+  String? optMethod();
+}
+
+@Native("AAA")
+class AAA implements NativeInterface {
+  int get size native;
+  String get name native;
+  String? get optName native;
+  int method1() native;
+  String method2() native;
+  String? optMethod() native;
+}
+
+abstract class JSInterface {
+  String get name;
+  String? get optName;
+}
+
+class BBB implements NativeInterface {
+  int get size => 300;
+  String get name => 'Brenda';
+  String? get optName => name;
+  int method1() => 400;
+  String method2() => 'brilliant!';
+  String? optMethod() => method2();
+}
diff --git a/tests/dart2js/native/native_null_assertions/null_assertions_test_lib.dart b/tests/dart2js/native/native_null_assertions/null_assertions_test_lib.dart
new file mode 100644
index 0000000..3f1f540
--- /dev/null
+++ b/tests/dart2js/native/native_null_assertions/null_assertions_test_lib.dart
@@ -0,0 +1,193 @@
+// 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.
+
+import '../native_testing.dart';
+import 'js_invocations_in_non_web_library.dart';
+import 'js_invocations_in_web_library.dart';
+import 'null_assertions_lib.dart';
+
+/// Returns an 'AAA' object that satisfies the interface.
+AAA makeA() native;
+
+/// Returns an 'AAA' object where each method breaks the interface's contract.
+AAA makeAX() native;
+
+/// Returns a 'JSInterface' object whose `JS()` invocations exist in a library
+/// that is part of the allowlist.
+CCCInWebLibrary makeWebC() native;
+
+/// Returns the same as above but where each method breaks the interface's
+/// contract.
+CCCInWebLibrary makeWebCX() native;
+
+/// Returns a 'JSInterface' object whose `JS()` invocations exist in a library
+/// that is not part of the allowlist.
+CCCInNonWebLibrary makeNonWebC() native;
+
+/// Returns the same as above but where each method breaks the interface's
+/// contract.
+CCCInNonWebLibrary makeNonWebCX() native;
+
+void setup() {
+  JS('', r"""
+(function(){
+  function AAA(s,n,m1,m2) {
+    this.size = s;
+    this.name = n;
+    this.optName = n;
+    this._m1 = m1;
+    this._m2 = m2;
+  }
+  AAA.prototype.method1 = function(){return this._m1};
+  AAA.prototype.method2 = function(){return this._m2};
+  AAA.prototype.optMethod = function(){return this._m2};
+
+  makeA = function() {
+    return new AAA(100, 'Albert', 200, 'amazing!');
+  };
+  makeAX = function() {
+    return new AAA(void 0, void 0, void 0, void 0);
+  };
+
+  self.nativeConstructor(AAA);
+
+  function CCCInWebLibrary(n) {
+    this.name = n;
+    this.optName = n;
+  }
+  function CCCInNonWebLibrary(n) {
+    this.name = n;
+    this.optName = n;
+  }
+
+  makeWebC = function() {
+    return new CCCInWebLibrary('Carol');
+  };
+  makeWebCX = function() {
+    return new CCCInWebLibrary(void 0);
+  };
+  makeNonWebC = function() {
+    return new CCCInNonWebLibrary('Carol');
+  };
+  makeNonWebCX = function() {
+    return new CCCInNonWebLibrary(void 0);
+  };
+
+  self.nativeConstructor(CCCInWebLibrary);
+  self.nativeConstructor(CCCInNonWebLibrary);
+})()""");
+}
+
+// The 'NativeInterface' version of the code is passed both native and Dart
+// objects, so there will be an interceptor dispatch to the method. This tests
+// that the null-check exists in the forwarding method.
+//
+// The 'AAA' version of the code is passed only objects of a single native
+// class, so the native method can be inlined (which happens in the optimizer).
+// This tests that the null-check exists in the 'inlined' code.
+
+@pragma('dart2js:noInline')
+String describeNativeInterface(NativeInterface o) {
+  return '${o.name} ${o.method2()} ${o.size} ${o.method1()}';
+}
+
+@pragma('dart2js:noInline')
+String describeAAA(AAA o) {
+  return '${o.name} ${o.method2()} ${o.size} ${o.method1()}';
+}
+
+@pragma('dart2js:noInline')
+String describeOptNativeInterface(NativeInterface o) {
+  return '${o.optName} ${o.optMethod()}';
+}
+
+@pragma('dart2js:noInline')
+String describeOptAAA(AAA o) {
+  return '${o.optName} ${o.optMethod()}';
+}
+
+@pragma('dart2js:noInline')
+String describeJSInterface(JSInterface o) {
+  return '${o.name}';
+}
+
+@pragma('dart2js:noInline')
+String describeOptJSInterface(JSInterface o) {
+  return '${o.optName}';
+}
+
+const expectedA = 'Albert amazing! 100 200';
+const expectedB = 'Brenda brilliant! 300 400';
+const expectedOptA = 'Albert amazing!';
+const expectedOptB = 'Brenda brilliant!';
+const expectedOptX = 'null null';
+
+const expectedC = 'Carol';
+const expectedOptC = 'Carol';
+const expectedOptCX = 'null';
+
+// Test that `--native-null-assertions` injects null-checks on the returned
+// value of native methods with a non-nullable return type in an opt-in library.
+void testNativeNullAssertions(bool flagEnabled) {
+  nativeTesting();
+  setup();
+  AAA a = makeA();
+  BBB b = BBB();
+
+  Expect.equals(expectedA, describeNativeInterface(a));
+  Expect.equals(expectedB, describeNativeInterface(b));
+
+  Expect.equals(expectedA, describeAAA(a));
+
+  AAA x = makeAX(); // This object returns `null`!
+  var checkExpectation = flagEnabled ? Expect.throws : (f) => f();
+  checkExpectation(() => describeNativeInterface(x));
+  checkExpectation(() => describeAAA(x));
+
+  checkExpectation(() => x.name);
+  checkExpectation(() => x.size);
+  checkExpectation(() => x.method1());
+  checkExpectation(() => x.method2());
+
+  // Now test that a nullable return type does not have a check.
+  Expect.equals(expectedOptA, describeOptNativeInterface(a));
+  Expect.equals(expectedOptB, describeOptNativeInterface(b));
+  Expect.equals(expectedOptX, describeOptNativeInterface(x));
+
+  Expect.equals(expectedOptA, describeOptAAA(a));
+  Expect.equals(expectedOptX, describeOptAAA(x));
+}
+
+// Test that `--native-null-assertions` injects null-checks on the returned
+// value of `JS()` invocations with a non-nullable static type in an opt-in
+// library.
+void testJSInvocationNullAssertions(bool flagEnabled) {
+  nativeTesting();
+  setup();
+
+  CCCInWebLibrary webC = makeWebC();
+  CCCInWebLibrary webCX = makeWebCX();
+
+  CCCInNonWebLibrary nonWebC = makeNonWebC();
+  CCCInNonWebLibrary nonWebCX = makeNonWebCX();
+
+  Expect.equals(expectedC, describeJSInterface(webC));
+  Expect.equals(expectedC, describeJSInterface(nonWebC));
+
+  // If invocations are in a web library, this should throw if null checks are
+  // enabled.
+  var checkExpectationWeb = flagEnabled ? Expect.throws : (f) => f();
+  checkExpectationWeb(() => describeJSInterface(webCX));
+
+  // If invocations are not in a web library, there should not be a null check
+  // regardless if the flag is enabled or not.
+  var checkExpectationNonWeb = (f) => f();
+  checkExpectationNonWeb(() => describeJSInterface(nonWebCX));
+
+  // Test that invocations with a nullable static type do not have checks.
+  Expect.equals(expectedOptC, describeOptJSInterface(webC));
+  Expect.equals(expectedOptC, describeOptJSInterface(nonWebC));
+  Expect.equals(expectedOptCX, describeOptJSInterface(webCX));
+  Expect.equals(expectedOptCX, describeOptJSInterface(nonWebCX));
+}
diff --git a/tests/dart2js/native/null_assertions_opt_in_lib.dart b/tests/dart2js/native/null_assertions_opt_in_lib.dart
deleted file mode 100644
index e08c788..0000000
--- a/tests/dart2js/native/null_assertions_opt_in_lib.dart
+++ /dev/null
@@ -1,58 +0,0 @@
-// 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.
-
-import 'native_testing.dart';
-
-abstract class Interface {
-  int get size;
-  String get name;
-  String? get optName;
-  int method1();
-  String method2();
-}
-
-@Native("AAA")
-class AAA implements Interface {
-  int get size native;
-  String get name native;
-  String? get optName native;
-  int method1() native;
-  String method2() native;
-}
-
-/// Returns an 'AAA' object that satisfies the interface.
-AAA makeA() native;
-
-/// Returns an 'AAA' object where each method breaks the interface's contract.
-AAA makeAX() native;
-
-void setup() {
-  JS('', r"""
-(function(){
-  function AAA(s,n,m1,m2) {
-    this.size = s;
-    this.name = n;
-    this.optName = n;
-    this._m1 = m1;
-    this._m2 = m2;
-  }
-  AAA.prototype.method1 = function(){return this._m1};
-  AAA.prototype.method2 = function(){return this._m2};
-
-  makeA = function() {return new AAA(100, 'Albert', 200, 'amazing!')};
-  makeAX = function() {return new AAA(void 0, void 0, void 0, void 0)};
-
-  self.nativeConstructor(AAA);
-})()""");
-}
-
-class BBB implements Interface {
-  int get size => 300;
-  String get name => 'Brenda';
-  String? get optName => name;
-  int method1() => 400;
-  String method2() => 'brilliant!';
-}
-
-List<Interface> items = [makeA(), BBB()];
diff --git a/tests/dart2js/native/null_assertions_test.dart b/tests/dart2js/native/null_assertions_test.dart
deleted file mode 100644
index 0a07785..0000000
--- a/tests/dart2js/native/null_assertions_test.dart
+++ /dev/null
@@ -1,74 +0,0 @@
-// 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.
-
-// Requirements=nnbd-weak
-// dart2jsOptions=--null-assertions
-
-// @dart=2.8
-
-// Test that `--null-assertions` injects null-checks on the returned value of
-// native methods with a non-nullable return type in an opt-in library.
-
-import 'native_testing.dart';
-import 'null_assertions_opt_in_lib.dart' as lib;
-
-// The 'Interface' version of the code is passed both native and Dart objects,
-// so there will be an interceptor dispatch to the method. This tests that the
-// null-check exists in the forwarding method.
-//
-// The 'AAA' version of the code is passed only objects of a single native
-// class, so the native method can be inlined (which happens in the optimizer).
-// This tests that the null-check exists in the 'inlined' code.
-
-@pragma('dart2js:noInline')
-String describeInterface(lib.Interface o) {
-  return '${o.name} ${o.method2()} ${o.size} ${o.method1()}';
-}
-
-@pragma('dart2js:noInline')
-String describeAAA(lib.AAA o) {
-  return '${o.name} ${o.method2()} ${o.size} ${o.method1()}';
-}
-
-@pragma('dart2js:noInline')
-void checkOptNameInterface(lib.Interface o, dynamic expected) {
-  Expect.equals(expected, o.optName);
-}
-
-@pragma('dart2js:noInline')
-void checkOptNameAAA(lib.AAA o, dynamic expected) {
-  Expect.equals(expected, o.optName);
-}
-
-const expectedA = 'Albert amazing! 100 200';
-const expectedB = 'Brenda brilliant! 300 400';
-
-void main() {
-  nativeTesting();
-  lib.setup();
-  lib.AAA a = lib.makeA();
-  lib.BBB b = lib.BBB();
-
-  Expect.equals(expectedA, describeInterface(a));
-  Expect.equals(expectedB, describeInterface(b));
-
-  Expect.equals(expectedA, describeAAA(a));
-
-  lib.AAA x = lib.makeAX(); // This object returns `null`!
-  Expect.throws(() => describeInterface(x));
-  Expect.throws(() => describeAAA(x));
-
-  Expect.throws(() => x.name);
-  Expect.throws(() => x.size);
-  Expect.throws(() => x.method1());
-  Expect.throws(() => x.method2());
-
-  // Now test that a nullable return type does not have a check.
-  checkOptNameInterface(a, 'Albert');
-  checkOptNameInterface(b, 'Brenda');
-  checkOptNameInterface(x, null);
-
-  checkOptNameAAA(a, 'Albert');
-  checkOptNameAAA(x, null);
-}
diff --git a/tests/language/nnbd/inference/variable_initialization_promotion_test.dart b/tests/language/nnbd/inference/variable_initialization_promotion_test.dart
new file mode 100644
index 0000000..634caaa
--- /dev/null
+++ b/tests/language/nnbd/inference/variable_initialization_promotion_test.dart
@@ -0,0 +1,338 @@
+// 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.
+
+import '../../static_type_helper.dart';
+
+/// Test that the type of a local variable is treated as a "type of interest"
+/// for the variable, and that for non-final variables, the initialization (if
+/// any) is treated as an assignment for the purposes of promotion.
+
+/// Verify that the declared type of a local variable is a type of interest.
+void declaredTypeIsATypeOfInterest() {
+  // Check that a variable declared with a non-nullable type can be assignment
+  // demoted back to its declared type after being promoted.
+  {
+    num x = 3;
+    x.expectStaticType<Exactly<num>>();
+    // Promote x to int
+    if (x is int) {
+      x.expectStaticType<Exactly<int>>();
+      // Verify that demotion back to num works
+      x = 3.5;
+      x.expectStaticType<Exactly<num>>();
+    }
+    x.expectStaticType<Exactly<num>>();
+  }
+
+  // Check that a variable declared with a nullable type can be assignment
+  // promoted to the non-nullable variant of its type, and demoted back to both
+  // the non-nullable variant and the declared type after being promoted.
+  {
+    num? x = (3 as num?);
+    x.expectStaticType<Exactly<num?>>();
+    // This should promote to num, since num and num? should both be types of
+    // interest.
+    x = 3;
+    x.expectStaticType<Exactly<num>>();
+    // Promote x to int
+    if (x is int) {
+      x.expectStaticType<Exactly<int>>();
+      // Verify that demotion back to num works
+      x = 3.5;
+      x.expectStaticType<Exactly<num>>();
+    }
+    x.expectStaticType<Exactly<num>>();
+    // Verify that demotion back to num? works
+    x = null;
+    x.expectStaticType<Exactly<num?>>();
+  }
+
+  // Check that a late variable declared with a non-nullable type can be
+  // assignment demoted back to its declared type after being promoted.
+  {
+    late num x = 3;
+    x.expectStaticType<Exactly<num>>();
+    // Promote x to int
+    if (x is int) {
+      x.expectStaticType<Exactly<int>>();
+      // Verify that demotion back to num works
+      x = 3.5;
+      x.expectStaticType<Exactly<num>>();
+    }
+    x.expectStaticType<Exactly<num>>();
+  }
+
+  // Check that a late variable declared with a nullable type can be assignment
+  // promoted to the non-nullable variant of its type, and demoted back to both
+  // the non-nullable variant and the declared type after being promoted.
+  {
+    late num? x = (3 as num?);
+    x.expectStaticType<Exactly<num?>>();
+    // This should promote to num, since num and num? should both be types of
+    // interest.
+    x = 3;
+    x.expectStaticType<Exactly<num>>();
+    // Promote x to int
+    if (x is int) {
+      x.expectStaticType<Exactly<int>>();
+      // Verify that demotion back to num works
+      x = 3.5;
+      x.expectStaticType<Exactly<num>>();
+    }
+    x.expectStaticType<Exactly<num>>();
+    // Verify that demotion back to num? works
+    x = null;
+    x.expectStaticType<Exactly<num?>>();
+  }
+
+  // Final variables are not re-assignable, but can still be subject to
+  // to assignment based promotion and demotion in a few situations.
+
+  // Check that a late final variable declared with a non-nullable type can be
+  // assignment demoted back to its declared type after being promoted.
+  {
+    late final num x;
+    // Make x potentially assigned, and initialize it
+    if (num == num) {
+      x = 3.5;
+    }
+    // Branch will not be taken to avoid a double initialization error
+    if (x is int) {
+      x.expectStaticType<Exactly<int>>();
+      x = 3.5; // Demote to num.
+      x.expectStaticType<Exactly<num>>();
+    }
+  }
+
+  // Check that a final variable declared with a non-nullable type can be
+  // assignment promoted to the non-nullable variant of its type.
+  {
+    final num? x;
+    // Promote to num, since num is a type of interest
+    x = 3;
+    // Verify that we have promoted to num
+    x.expectStaticType<Exactly<num>>();
+  }
+
+  // Check that a late final variable declared with a non-nullable type can be
+  // assignment promoted to the non-nullable variant of its type.
+  {
+    late final num? x;
+    // Promote to num, since num is a type of interest
+    x = 3;
+    // Verify that we have promoted to num
+    x.expectStaticType<Exactly<num>>();
+  }
+}
+
+/// Verify that the inferred type of a local variable is a type of interest.
+void inferredTypeIsATypeOfInterest() {
+  // Check that a variable inferred with a non-nullable type can be
+  // assignment demoted back to its declared type after being promoted.
+  {
+    var x = (3 as num);
+    x.expectStaticType<Exactly<num>>();
+    // Promote x to int
+    if (x is int) {
+      x.expectStaticType<Exactly<int>>();
+      // Verify that demotion back to num works
+      x = 3.5;
+      x.expectStaticType<Exactly<num>>();
+    }
+    x.expectStaticType<Exactly<num>>();
+  }
+
+  // Check that a variable inferred to have a nullable type can be assignment
+  // promoted to the non-nullable variant of its type, and demoted back to both
+  // the non-nullable variant and the declared type after being promoted.
+  {
+    var x = (3 as num?);
+    x.expectStaticType<Exactly<num?>>();
+    // This should promote to num, since num and num? should both be types of
+    // interest.
+    x = 3;
+    x.expectStaticType<Exactly<num>>();
+    // Promote x to int
+    if (x is int) {
+      x.expectStaticType<Exactly<int>>();
+      // Verify that demotion back to num works
+      x = 3.5;
+      x.expectStaticType<Exactly<num>>();
+    }
+    x.expectStaticType<Exactly<num>>();
+    // Verify that demotion back to num? works
+    x = null;
+    x.expectStaticType<Exactly<num?>>();
+  }
+
+  // Check that a variable inferred with a non-nullable type can be
+  // assignment demoted back to its declared type after being promoted.
+  {
+    late var x = (3 as num);
+    x.expectStaticType<Exactly<num>>();
+    // Promote x to int
+    if (x is int) {
+      x.expectStaticType<Exactly<int>>();
+      // Verify that demotion back to num works
+      x = 3.5;
+      x.expectStaticType<Exactly<num>>();
+    }
+    x.expectStaticType<Exactly<num>>();
+  }
+
+  // Check that a late variable inferred to have a nullable type can be
+  // assignment promoted to the non-nullable variant of its type, and demoted
+  // back to both the non-nullable variant and the declared type after being
+  // promoted.
+  {
+    late var x = (3 as num?);
+    x.expectStaticType<Exactly<num?>>();
+    // This should promote to num, since num and num? should both be types of
+    // interest.
+    x = 3;
+    x.expectStaticType<Exactly<num>>();
+    // Promote x to int
+    if (x is int) {
+      x.expectStaticType<Exactly<int>>();
+      // Verify that demotion back to num works
+      x = 3.5;
+      x.expectStaticType<Exactly<num>>();
+    }
+    x.expectStaticType<Exactly<num>>();
+    // Verify that demotion back to num? works
+    x = null;
+    x.expectStaticType<Exactly<num?>>();
+  }
+}
+
+/// Verify that the initializer on a mutable variable is treated as if it were
+/// an assignment for the purposes of promotion, and therefore assigning a
+/// non-nullable value can promote to a non-nullable variant of the declared
+/// type.
+void initializersOnVarPromote() {
+  // Check that a variable declared to have a nullable type can be promoted on
+  // initialization to the non-nullable variant of its type, demoted back to the
+  // declared type, and assignment promoted to the non-nullable variant of the
+  // declared type.
+  {
+    num? x = 3;
+    // Verify that we have promoted to num
+    x.expectStaticType<Exactly<num>>();
+    // Verify that num? is a type of interest by demoting to it
+    x = null;
+    x.expectStaticType<Exactly<num?>>();
+    // Verify that num is a type of interest by promoting to it.
+    x = 3;
+    x.expectStaticType<Exactly<num>>();
+  }
+
+  // Check that a late variable declared to have a nullable type can be promoted
+  // on initialization to the non-nullable variant of its type, demoted back to
+  // the declared type, and assignment promoted to the non-nullable variant of
+  // the declared type.
+  {
+    late num? x = 3;
+    // Verify that we have promoted to num
+    x.expectStaticType<Exactly<num>>();
+    // Verify that num? is a type of interest by demoting to it
+    x = null;
+    x.expectStaticType<Exactly<num?>>();
+    // Verify that num is a type of interest by promoting to it.
+    x = 3;
+    x.expectStaticType<Exactly<num>>();
+  }
+}
+
+/// Verify that the initializer on a final variable is not treated as if it were
+/// an assignment for the purposes of promotion, and therefore assigning a
+/// non-nullable value does not promote to a non-nullable variant of the
+/// declared type.
+void initializersOnFinalDoNotPromote() {
+  // Check that a final nullable variable initialized with a non-nullable value
+  // does not get promoted by the initializer to the non-nullable variant of the
+  // type.
+  {
+    final num? x = 3;
+    // Verify that we have not promoted to num
+    x.expectStaticType<Exactly<num?>>();
+  }
+
+  // Check that a late final nullable variable initialized with a non-nullable
+  // value does not get promoted by the initializer to the non-nullable variant
+  // of the type.
+  {
+    late final num? x = 3;
+    // Verify that we have not promoted to num
+    x.expectStaticType<Exactly<num?>>();
+  }
+}
+
+/// Check that when an initializer is a promoted type variable `X & T`, the
+/// inferred type of the variable is `X`, but that the variable is immediately
+/// promoted to `X & T`.
+void typeVariableTypedVariableInferencePromotes<T>(T x0, T x1) {
+  if (x0 is num) {
+    // Promote `x0` to T & num
+
+    {
+      // Declare y, which should have inferred type T, and be promoted to T &
+      // num
+      var y = x0;
+      // Check that y is assignable to z, and hence that y is still promoted to
+      // T & num
+      num z = y;
+      // Check that y can be demoted to T.
+      y = x1;
+      // T & num is still a type of interest, and hence this assignment should
+      // promote to T & num.
+      y = x0;
+      // Check that y is assignable to z, and hence that y has been promoted T &
+      // num
+      z = y;
+    }
+
+    {
+      // Declare y, which should have inferred type T, and be promoted to T &
+      // num
+      late var y = x0;
+      // Check that y is assignable to z, and hence that y is still promoted to
+      // T & num
+      num z = y;
+      // Check that y can be demoted to T.
+      y = x1;
+      // T & num is still a type of interest, and hence this assignment should
+      // promote to T & num.
+      y = x0;
+      // Check that y is assignable to z, and hence that y has been promoted T &
+      // num
+      z = y;
+    }
+
+    {
+      // Declare y, which should have inferred type T, and be promoted to T &
+      // num
+      final y = x0;
+      // Check that y is assignable to z, and hence that y is still promoted to
+      // T & num
+      num z = y;
+    }
+
+    {
+      // Declare y, which should have inferred type T, and be promoted to T &
+      // num
+      late final y = x0;
+      // Check that y is assignable to z, and hence that y is still promoted to
+      // T & num
+      num z = y;
+    }
+  }
+}
+
+void main() {
+  declaredTypeIsATypeOfInterest();
+  inferredTypeIsATypeOfInterest();
+  initializersOnVarPromote();
+  initializersOnFinalDoNotPromote();
+  typeVariableTypedVariableInferencePromotes<num>(3, 3.5);
+}
diff --git a/tests/language/nnbd/inference/variables_initialized_to_null_test.dart b/tests/language/nnbd/inference/variables_initialized_to_null_test.dart
new file mode 100644
index 0000000..77ffaa9
--- /dev/null
+++ b/tests/language/nnbd/inference/variables_initialized_to_null_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.
+
+import 'package:expect/expect.dart';
+
+/// Test that variables which are initialized to Null are inferred at type
+/// `dynamic`.
+
+var global0 = null;
+var global1 = null as Null;
+
+class Test {
+  static var static0 = null;
+  static var static1 = null as Null;
+
+  var instance0 = null;
+  var instance1 = null as Null;
+}
+
+/// For each category of variable and each style of initialization, we test that
+/// the variable verify that the type is not `Never` by verifying that a value
+/// of type `Object` may be assigned to it, and then check that the type is
+/// `dynamic` (or `Never` which has been eliminated) by verifying that an
+/// arbitrary method may be called on it.
+
+void test() {
+  final Object three = 3;
+  {
+    global0 = three;
+    Expect.isFalse(global0.isEven);
+    global1 = three;
+    Expect.isFalse(global1.isEven);
+  }
+  {
+    Test.static0 = three;
+    Expect.isFalse(Test.static0.isEven);
+    Test.static1 = three;
+    Expect.isFalse(Test.static1.isEven);
+  }
+  {
+    var o = new Test();
+    o.instance0 = three;
+    Expect.isFalse(o.instance0.isEven);
+    o.instance1 = three;
+    Expect.isFalse(o.instance1.isEven);
+  }
+  {
+    var local0 = null;
+    var local1 = null as Null;
+
+    local0 = three;
+    Expect.isFalse(local0.isEven);
+    local1 = three;
+    Expect.isFalse(local1.isEven);
+  }
+}
+
+void main() {
+  test();
+}
diff --git a/tests/language/nnbd/static_errors/await_in_late_local_variable_initializer_test.dart b/tests/language/nnbd/static_errors/await_in_late_local_variable_initializer_test.dart
index 6f5c2c0..4f39726 100644
--- a/tests/language/nnbd/static_errors/await_in_late_local_variable_initializer_test.dart
+++ b/tests/language/nnbd/static_errors/await_in_late_local_variable_initializer_test.dart
@@ -10,9 +10,9 @@
 import 'dart:core';
 
 main() async {
-  late a = 0; //# 01: ok
-  late b = await 0; //# 02: compile-time error
-  late c = () async => await 42; //# 03: ok
-  late d = () async { await 42; }; //# 04: ok
-  var e = () async { late e2 = await 42; }; //# 05: compile-time error
+  late final a = 0; //# 01: ok
+  late var b = await 0; //# 02: compile-time error
+  late Function c = () async => await 42; //# 03: ok
+  late var d = () async { await 42; }; //# 04: ok
+  var e = () async { late final e2 = await 42; }; //# 05: compile-time error
 }
diff --git a/tests/language/operator/number_operator_context_test.dart b/tests/language/operator/number_operator_context_test.dart
index 898f139..3c587d8 100644
--- a/tests/language/operator/number_operator_context_test.dart
+++ b/tests/language/operator/number_operator_context_test.dart
@@ -4,7 +4,7 @@
 
 // Test the new context type rules for number operators,
 // as modified by Null Safety
-import "static_type_helper.dart";
+import "../static_type_helper.dart";
 
 // The context rules for `e` of the form:
 // For e1 + e2, e1 - e2, e1 * e2, e1 % e2 or e1.remainder(e2),,
diff --git a/tests/language/operator/number_operator_error_test.dart b/tests/language/operator/number_operator_error_test.dart
index 90e4cf0..f402e51 100644
--- a/tests/language/operator/number_operator_error_test.dart
+++ b/tests/language/operator/number_operator_error_test.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 // Test the new context type rules for number operators,
-import "static_type_helper.dart";
+import "../static_type_helper.dart";
 
 // as modified by Null Safety
 void main() {
diff --git a/tests/language/operator/number_operator_typing_test.dart b/tests/language/operator/number_operator_typing_test.dart
index 62e452a..c650e61 100644
--- a/tests/language/operator/number_operator_typing_test.dart
+++ b/tests/language/operator/number_operator_typing_test.dart
@@ -4,7 +4,7 @@
 
 // Test the rules for static types of number operators,
 // as modified by Null Safety
-import "static_type_helper.dart";
+import "../static_type_helper.dart";
 
 // ignore_for_file: receiver_of_type_never
 
diff --git a/tests/language/spread_collections/type_error_test.dart b/tests/language/spread_collections/type_error_test.dart
index ccfc61a..3fe731a 100644
--- a/tests/language/spread_collections/type_error_test.dart
+++ b/tests/language/spread_collections/type_error_test.dart
@@ -20,7 +20,7 @@
   var _ = <int>{...<String>[]}; //# 09: compile-time error
 
   // Downcast element.
-  var _ = <int>[...<num>[1, 2]]); //# 10: compile-time error
-  var _ = <int, int>{...<num, num>{1: 1, 2: 2}}); //# 11: compile-time error
-  var _ = <int>{...<num>[1, 2]}); //# 12: compile-time error
+  var _ = <int>[...<num>[1, 2]]; //# 10: compile-time error
+  var _ = <int, int>{...<num, num>{1: 1, 2: 2}}; //# 11: compile-time error
+  var _ = <int>{...<num>[1, 2]}; //# 12: compile-time error
 }
diff --git a/tests/language/operator/static_type_helper.dart b/tests/language/static_type_helper.dart
similarity index 91%
rename from tests/language/operator/static_type_helper.dart
rename to tests/language/static_type_helper.dart
index 50cdace..9484387 100644
--- a/tests/language/operator/static_type_helper.dart
+++ b/tests/language/static_type_helper.dart
@@ -64,7 +64,7 @@
 
 /// Checks that an expression is assignable to [T1], [T2] and [Object].
 ///
-/// This ensures that the type of the expression is a non-`dynamic`
-/// type assignable to both [T1] and [T2], and if those are unrelated,
-/// it must be an intersection type.
+/// This ensures that the static type of the expression is either dynamic,
+/// Never, or a type assignable to both [T1] and [T2], and if those are
+/// unrelated, it must be an intersection type.
 void checkIntersectionType<T1, T2>(T1 v1, T2 v2, Object v3) {}
diff --git a/tests/standalone/check_for_aot_snapshot_jit_test.dart b/tests/standalone/check_for_aot_snapshot_jit_test.dart
index 851dc0c5..a1dd29d 100644
--- a/tests/standalone/check_for_aot_snapshot_jit_test.dart
+++ b/tests/standalone/check_for_aot_snapshot_jit_test.dart
@@ -20,7 +20,7 @@
   final kernelOutput = d.uri.resolve('pow_test.dill').path;
   final aotOutput = d.uri.resolve('pow_test.aot').path;
 
-  final genKernelResult = Process.runSync(
+  final genKernelResult = runAndPrintOutput(
     'pkg/vm/tool/gen_kernel',
     [
       '--aot',
@@ -31,8 +31,9 @@
     ],
   );
   Expect.equals(genKernelResult.exitCode, 0);
+  print("Ran successfully.\n");
 
-  final genAotResult = Process.runSync(
+  final genAotResult = runAndPrintOutput(
     genSnapshot,
     [
       '--snapshot_kind=app-aot-elf',
@@ -41,8 +42,9 @@
     ],
   );
   Expect.equals(genAotResult.exitCode, 0);
+  print("Ran successfully.\n");
 
-  final runAotResult = Process.runSync(
+  final runAotResult = runAndPrintOutput(
     exePath,
     [
       'run',
@@ -56,4 +58,19 @@
       "pow_test.aot is an AOT snapshot and should be run with 'dartaotruntime'",
     ],
   );
+  print('Got expected error result.');
+}
+
+ProcessResult runAndPrintOutput(String command, List<String> args) {
+  print('Running $command ${args.join(' ')}...');
+  final result = Process.runSync(command, args);
+  if (result.stdout.isNotEmpty) {
+    print("stdout: ");
+    print(result.stdout);
+  }
+  if (result.stderr.isNotEmpty) {
+    print("stderr: ");
+    print(result.stderr);
+  }
+  return result;
 }
diff --git a/tests/standalone/dwarf_stack_trace_obfuscate_test.dart b/tests/standalone/dwarf_stack_trace_obfuscate_test.dart
index 5750ab5..f6b3360 100644
--- a/tests/standalone/dwarf_stack_trace_obfuscate_test.dart
+++ b/tests/standalone/dwarf_stack_trace_obfuscate_test.dart
@@ -40,7 +40,7 @@
     return; // Generated dwarf.so not available on the test device.
   }
 
-  final dwarf = Dwarf.fromFile("dwarf_obfuscate.so");
+  final dwarf = Dwarf.fromFile("dwarf_obfuscate.so")!;
 
   await base.checkStackTrace(rawStack, dwarf, expectedCallsInfo);
 }
diff --git a/tests/standalone/dwarf_stack_trace_test.dart b/tests/standalone/dwarf_stack_trace_test.dart
index 9cf2cb0..236a21e 100644
--- a/tests/standalone/dwarf_stack_trace_test.dart
+++ b/tests/standalone/dwarf_stack_trace_test.dart
@@ -40,7 +40,7 @@
     return; // Generated dwarf.so not available on the test device.
   }
 
-  final dwarf = Dwarf.fromFile("dwarf.so");
+  final dwarf = Dwarf.fromFile("dwarf.so")!;
 
   await checkStackTrace(rawStack, dwarf, expectedCallsInfo);
 }
@@ -86,7 +86,7 @@
     Expect.isNotNull(externalCallInfo);
     final allCallInfo = dwarf.callInfoFor(addr, includeInternalFrames: true);
     Expect.isNotNull(allCallInfo);
-    for (final call in allCallInfo) {
+    for (final call in allCallInfo!) {
       Expect.isTrue(call is DartCallInfo, "got non-Dart call info ${call}");
     }
     Expect.deepEquals(externalCallInfo, allCallInfo);
diff --git a/tests/standalone/io/socket_connect_consume_write_close_test.dart b/tests/standalone/io/socket_connect_consume_write_close_test.dart
index 8b021abd..f593c79 100644
--- a/tests/standalone/io/socket_connect_consume_write_close_test.dart
+++ b/tests/standalone/io/socket_connect_consume_write_close_test.dart
@@ -18,7 +18,12 @@
   // without listening on the stream.
   asyncStart();
   ServerSocket.bind(InternetAddress.loopbackIPv4, 0).then((server) {
-    server.listen((_) {});
+    late Socket ref;
+    server.listen((socket) {
+      // Create a reference to the connected socket so it's not prematurely
+      // collected.
+      ref = socket;
+    });
     Socket.connect("127.0.0.1", server.port).then((socket) {
       socket.add([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
       socket.close();
diff --git a/tests/standalone_2/check_for_aot_snapshot_jit_test.dart b/tests/standalone_2/check_for_aot_snapshot_jit_test.dart
index 851dc0c5..a1dd29d 100644
--- a/tests/standalone_2/check_for_aot_snapshot_jit_test.dart
+++ b/tests/standalone_2/check_for_aot_snapshot_jit_test.dart
@@ -20,7 +20,7 @@
   final kernelOutput = d.uri.resolve('pow_test.dill').path;
   final aotOutput = d.uri.resolve('pow_test.aot').path;
 
-  final genKernelResult = Process.runSync(
+  final genKernelResult = runAndPrintOutput(
     'pkg/vm/tool/gen_kernel',
     [
       '--aot',
@@ -31,8 +31,9 @@
     ],
   );
   Expect.equals(genKernelResult.exitCode, 0);
+  print("Ran successfully.\n");
 
-  final genAotResult = Process.runSync(
+  final genAotResult = runAndPrintOutput(
     genSnapshot,
     [
       '--snapshot_kind=app-aot-elf',
@@ -41,8 +42,9 @@
     ],
   );
   Expect.equals(genAotResult.exitCode, 0);
+  print("Ran successfully.\n");
 
-  final runAotResult = Process.runSync(
+  final runAotResult = runAndPrintOutput(
     exePath,
     [
       'run',
@@ -56,4 +58,19 @@
       "pow_test.aot is an AOT snapshot and should be run with 'dartaotruntime'",
     ],
   );
+  print('Got expected error result.');
+}
+
+ProcessResult runAndPrintOutput(String command, List<String> args) {
+  print('Running $command ${args.join(' ')}...');
+  final result = Process.runSync(command, args);
+  if (result.stdout.isNotEmpty) {
+    print("stdout: ");
+    print(result.stdout);
+  }
+  if (result.stderr.isNotEmpty) {
+    print("stderr: ");
+    print(result.stderr);
+  }
+  return result;
 }
diff --git a/tests/standalone_2/io/socket_connect_consume_write_close_test.dart b/tests/standalone_2/io/socket_connect_consume_write_close_test.dart
index 8b021abd..3dc0ab5 100644
--- a/tests/standalone_2/io/socket_connect_consume_write_close_test.dart
+++ b/tests/standalone_2/io/socket_connect_consume_write_close_test.dart
@@ -18,7 +18,12 @@
   // without listening on the stream.
   asyncStart();
   ServerSocket.bind(InternetAddress.loopbackIPv4, 0).then((server) {
-    server.listen((_) {});
+    Socket ref;
+    server.listen((socket) {
+      // Create a reference to the connected socket so it's not prematurely
+      // collected.
+      ref = socket;
+    });
     Socket.connect("127.0.0.1", server.port).then((socket) {
       socket.add([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
       socket.close();
diff --git a/tools/VERSION b/tools/VERSION
index 6b0416f..e3ee7ca 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -25,7 +25,7 @@
 #
 CHANNEL dev
 MAJOR 2
-MINOR 10
+MINOR 11
 PATCH 0
-PRERELEASE 156
+PRERELEASE 157
 PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/bots/test_matrix.json b/tools/bots/test_matrix.json
index cb9855d..88ab3c4 100644
--- a/tools/bots/test_matrix.json
+++ b/tools/bots/test_matrix.json
@@ -822,39 +822,6 @@
         "builder-tag": "vm_nnbd"
       }
     },
-    "dartk-(linux|mac|win)-(debug|product|release)-(ia32|simarm|simarm64|x64)-ast": {
-      "options": {
-        "builder-tag": "ast",
-        "gen-kernel-options": [
-          "--no-gen-bytecode"
-        ]
-      }
-    },
-    "dartkp-(linux|mac)-(debug|product|release)-x64-ast": {
-      "options": {
-        "builder-tag": "ast",
-        "gen-kernel-options": [
-          "--no-gen-bytecode"
-        ]
-      }
-    },
-    "dartkp-(linux|mac)-(debug|product|release)-simarm64-ast": {
-      "options": {
-        "builder-tag": "ast",
-        "use-elf": true,
-        "gen-kernel-options": [
-          "--no-gen-bytecode"
-        ]
-      }
-    },
-    "dartkp-linux-(debug|product|release)-simarm-crossword-ast": {
-      "options": {
-        "builder-tag": "crossword_ast",
-        "gen-kernel-options": [
-          "--no-gen-bytecode"
-        ]
-      }
-    },
     "dartk-checked-(linux|mac|win)-(debug|product|release)-(ia32|x64)": {
       "options": {
         "enable-asserts": true
@@ -891,134 +858,6 @@
       }
     },
     "app_jitk-(linux|mac|win)-(debug|product|release)-(ia32|x64)": {},
-    "dartkb-interpret-(linux|mac|win)-product-(ia32|x64|arm|arm64|simarm|simarm64)": {
-      "options": {
-        "builder-tag": "bytecode_interpreter",
-        "gen-kernel-options": [
-          "--gen-bytecode",
-          "--drop-ast",
-          "--bytecode-options=source-positions,annotations"
-        ],
-        "vm-options": [
-          "--enable_interpreter",
-          "--compilation-counter-threshold=-1"
-        ]
-      }
-    },
-    "dartkb-interpret-(linux|mac|win)-(debug|release)-(ia32|x64|arm|arm64|simarm|simarm64)": {
-      "options": {
-        "builder-tag": "bytecode_interpreter",
-        "gen-kernel-options": [
-          "--gen-bytecode",
-          "--drop-ast",
-          "--bytecode-options=source-positions,annotations,local-var-info,debugger-stops"
-        ],
-        "vm-options": [
-          "--enable_interpreter",
-          "--compilation-counter-threshold=-1"
-        ]
-      }
-    },
-    "dartkb-mixed-(linux|mac|win)-(debug|release)-(ia32|x64|arm|arm64|simarm|simarm64)": {
-      "options": {
-        "builder-tag": "bytecode_mixed",
-        "gen-kernel-options": [
-          "--gen-bytecode",
-          "--drop-ast",
-          "--bytecode-options=source-positions,annotations,local-var-info,debugger-stops"
-        ],
-        "vm-options": [
-          "--enable_interpreter"
-        ]
-      }
-    },
-    "dartkb-mixed-(linux|mac|win)-product-(ia32|x64|arm|arm64|simarm|simarm64)": {
-      "options": {
-        "builder-tag": "bytecode_mixed",
-        "gen-kernel-options": [
-          "--gen-bytecode",
-          "--drop-ast",
-          "--bytecode-options=source-positions,annotations"
-        ],
-        "vm-options": [
-          "--enable_interpreter"
-        ]
-      }
-    },
-    "dartkb-interpret-strong-(linux|mac|win)-product-(ia32|x64|arm|arm64|simarm|simarm64)": {
-      "options": {
-        "builder-tag": "bytecode_interpreter_nnbd",
-        "enable-experiment": [
-          "non-nullable"
-        ],
-        "gen-kernel-options": [
-          "--gen-bytecode",
-          "--drop-ast",
-          "--bytecode-options=source-positions,annotations",
-          "--sound-null-safety"
-        ],
-        "vm-options": [
-          "--enable_interpreter",
-          "--compilation-counter-threshold=-1",
-          "--sound-null-safety"
-        ]
-      }
-    },
-    "dartkb-interpret-strong-(linux|mac|win)-(debug|release)-(ia32|x64|arm|arm64|simarm|simarm64)": {
-      "options": {
-        "builder-tag": "bytecode_interpreter_nnbd",
-        "enable-experiment": [
-          "non-nullable"
-        ],
-        "gen-kernel-options": [
-          "--gen-bytecode",
-          "--drop-ast",
-          "--bytecode-options=source-positions,annotations,local-var-info,debugger-stops",
-          "--sound-null-safety"
-        ],
-        "vm-options": [
-          "--enable_interpreter",
-          "--compilation-counter-threshold=-1",
-          "--sound-null-safety"
-        ]
-      }
-    },
-    "dartkb-mixed-strong-(linux|mac|win)-(debug|release)-(ia32|x64|arm|arm64|simarm|simarm64)": {
-      "options": {
-        "builder-tag": "bytecode_mixed_nnbd",
-        "enable-experiment": [
-          "non-nullable"
-        ],
-        "gen-kernel-options": [
-          "--gen-bytecode",
-          "--drop-ast",
-          "--bytecode-options=source-positions,annotations,local-var-info,debugger-stops",
-          "--sound-null-safety"
-        ],
-        "vm-options": [
-          "--enable_interpreter",
-          "--sound-null-safety"
-        ]
-      }
-    },
-    "dartkb-mixed-strong-(linux|mac|win)-product-(ia32|x64|arm|arm64|simarm|simarm64)": {
-      "options": {
-        "builder-tag": "bytecode_mixed_nnbd",
-        "enable-experiment": [
-          "non-nullable"
-        ],
-        "gen-kernel-options": [
-          "--gen-bytecode",
-          "--drop-ast",
-          "--bytecode-options=source-positions,annotations",
-          "--sound-null-safety"
-        ],
-        "vm-options": [
-          "--enable_interpreter",
-          "--sound-null-safety"
-        ]
-      }
-    },
     "dartdevk-checked-(linux|mac|win)-(debug|product|release)-(chrome|firefox)": {
       "options": {
         "checked": true,
@@ -1219,59 +1058,6 @@
     },
     {
       "builders": [
-        "vm-dartkb-linux-release-x64",
-        "vm-dartkb-linux-release-simarm64"
-      ],
-      "meta": {
-        "description": "This configuration is used by the vm kbc builders."
-      },
-      "steps": [
-        {
-          "name": "build dart",
-          "script": "tools/build.py",
-          "arguments": [
-            "--bytecode",
-            "runtime"
-          ]
-        },
-        {
-          "name": "vm mixed mode tests",
-          "arguments": [
-            "-ndartkb-mixed-linux-${mode}-${arch}"
-          ],
-          "fileset": "vm-kernel",
-          "shards": 4
-        },
-        {
-          "name": "vm mixed mode co19 tests",
-          "arguments": [
-            "-ndartkb-mixed-linux-${mode}-${arch}",
-            "co19_2"
-          ],
-          "fileset": "vm-kernel",
-          "shards": 4
-        },
-        {
-          "name": "vm interpreter tests",
-          "arguments": [
-            "-ndartkb-interpret-linux-${mode}-${arch}"
-          ],
-          "fileset": "vm-kernel",
-          "shards": 4
-        },
-        {
-          "name": "vm interpreter co19 tests",
-          "arguments": [
-            "-ndartkb-interpret-linux-${mode}-${arch}",
-            "co19_2"
-          ],
-          "fileset": "vm-kernel",
-          "shards": 4
-        }
-      ]
-    },
-    {
-      "builders": [
         "vm-canary-linux-debug"
       ],
       "meta": {
@@ -3616,7 +3402,6 @@
           "name": "build dart for simarm_x64",
           "script": "tools/build.py",
           "arguments": [
-            "--bytecode",
             "gen_snapshot"
           ]
         },
@@ -3625,7 +3410,6 @@
           "script": "tools/build.py",
           "arguments": [
             "--arch=simarm",
-            "--bytecode",
             "dart_precompiled_runtime",
             "vm_platform"
           ]
diff --git a/tools/bots/try_benchmarks.sh b/tools/bots/try_benchmarks.sh
index 920e30a..6029940 100755
--- a/tools/bots/try_benchmarks.sh
+++ b/tools/bots/try_benchmarks.sh
@@ -146,7 +146,6 @@
       out/ReleaseIA32/vm_platform_strong.dill \
       out/ReleaseIA32/gen/kernel_service.dill \
       out/ReleaseIA32/dart-sdk \
-      tools/dart2js/angular2_testing_deps \
       out/ReleaseIA32/dart \
       out/ReleaseIA32/gen_snapshot \
       out/ReleaseIA32/gen_kernel_bytecode.dill \
diff --git a/tools/experimental_features.yaml b/tools/experimental_features.yaml
index b7276b8..d750f93 100644
--- a/tools/experimental_features.yaml
+++ b/tools/experimental_features.yaml
@@ -93,7 +93,7 @@
 # default 'language' "category" with code generated for both CFE and Analyzer,
 # while other categories can be tailored more specifically.
 
-current-version: '2.10.0'
+current-version: '2.11.0'
 
 features:
   non-nullable:
diff --git a/utils/bazel/kernel_worker.dart b/utils/bazel/kernel_worker.dart
index 194fe55..a056905 100644
--- a/utils/bazel/kernel_worker.dart
+++ b/utils/bazel/kernel_worker.dart
@@ -198,7 +198,9 @@
   // compatible while we migrate existing clients of this tool.
   var targetName =
       (parsedArgs['target'] as String) ?? (summaryOnly ? 'ddc' : 'vm');
-  var targetFlags = new TargetFlags(trackWidgetCreation: trackWidgetCreation);
+  var targetFlags = new TargetFlags(
+      trackWidgetCreation: trackWidgetCreation,
+      enableNullSafety: nnbdMode == fe.NnbdMode.Strong);
   Target target;
   switch (targetName) {
     case 'vm':