Version 2.7.0-dev.2.0

Merge commit '16cbabec3a00e715173c68e8f761a8e1296cc9e5' into dev
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6707c5a..eb17626 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -85,15 +85,15 @@
 
 #### Linter
 
-The Linter was updated to `0.1.103`, which includes:
+The Linter was updated to `0.1.104`, which includes:
 
-* updates to `prefer_relative_imports` to use a faster and more robust way to check for self-package references
-* updates to our approach to checking for `lib` dir contents (speeding up `avoid_renaming_method_parameters` and
-  making `prefer_relative_imports` and `public_member_api_docs` amenable to internal package formats -- w/o pubspecs)
+* updated `unnecessary_overrides` to allow overrides when annotations (besides `@override` are specified)
+* updated `file_names` to allow names w/ leading `_`'s (and improved performance)
+* new lint: `unnecessary_final`
 
 #### Pub
 
-* `pub get` generates [`.dart_tools/package_config.json`](https://github.com/dart-lang/language/blob/62c036cc41b10fb543102d2f73ee132d1e2b2a0e/accepted/future-releases/language-versioning/package-config-file-v2.md)
+* `pub get` generates [`.dart_tool/package_config.json`](https://github.com/dart-lang/language/blob/62c036cc41b10fb543102d2f73ee132d1e2b2a0e/accepted/future-releases/language-versioning/package-config-file-v2.md)
   in addition to `.packages` to support language versioning.
 
 * `pub publish` now warns about the old flutter plugin registration format.
@@ -194,6 +194,12 @@
 * Added optional `parent` parameter to `TimelineTask` constructor to allow for
   linking of asynchronous timeline events in the DevTools timeline view.
 
+#### `dart:io`
+
+* Added `enableTimelineLogging` property to `HttpClient` which, when enabled,
+  will post HTTP connection and request information to the developer timeline
+  for all `HttpClient` instances.
+
 ### Dart VM
 
 * Added a new tool for AOT compiling Dart programs to native, self-contained
diff --git a/DEPS b/DEPS
index 4c62d63..8583d7a 100644
--- a/DEPS
+++ b/DEPS
@@ -100,7 +100,7 @@
   "intl_tag": "0.15.7",
   "jinja2_rev": "2222b31554f03e62600cd7e383376a7c187967a1",
   "json_rpc_2_tag": "2.0.9",
-  "linter_tag": "0.1.103",
+  "linter_tag": "0.1.104",
   "logging_tag": "0.11.3+2",
   "markupsafe_rev": "8f45f5cfa0009d2a70589bcda0349b8cb2b72783",
   "markdown_tag": "2.1.1",
@@ -143,7 +143,7 @@
   "typed_data_tag": "1.1.6",
   "unittest_rev": "2b8375bc98bb9dc81c539c91aaea6adce12e1072",
   "usage_tag": "3.4.0",
-  "watcher_rev": "0.9.7+12-pub",
+  "watcher_rev": "0.9.7+13",
   "web_components_rev": "8f57dac273412a7172c8ade6f361b407e2e4ed02",
   "web_socket_channel_tag": "1.0.9",
   "WebCore_rev": "fb11e887f77919450e497344da570d780e078bc8",
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn
index db31ad4..4457f43 100644
--- a/build/config/BUILDCONFIG.gn
+++ b/build/config/BUILDCONFIG.gn
@@ -133,6 +133,9 @@
 
   # Compile for Undefined Behavior Sanitizer to find reliance on undefined behavior.
   is_ubsan = false
+
+  # Compile for execution in user-mode QEMU.
+  is_qemu = false
 }
 
 # =============================================================================
diff --git a/build/config/linux/BUILD.gn b/build/config/linux/BUILD.gn
index 70bb890..9e23651 100644
--- a/build/config/linux/BUILD.gn
+++ b/build/config/linux/BUILD.gn
@@ -6,6 +6,7 @@
 
 config("sdk") {
   ldflags = []
+  cflags = []
 
   if (is_asan || is_lsan || is_msan || is_tsan || is_ubsan) {
     ldflags += [ "-lrt" ]
@@ -23,7 +24,7 @@
   }
 
   if (sysroot != "") {
-    cflags = [ "--sysroot=" + sysroot ]
+    cflags += [ "--sysroot=" + sysroot ]
     ldflags += [ "--sysroot=" + sysroot ]
 
     # Need to get some linker flags out of the sysroot.
@@ -44,10 +45,18 @@
       ]
     }
   }
+
+  if (is_qemu) {
+    cflags += ["-DDART_RUN_IN_QEMU_ARMv7"]
+  }
 }
 
 config("executable_config") {
-  if (current_cpu != "x86") {
+  # GDB cannot find the executable's mapping in QEMU when PIE is enabled.
+  if (is_qemu) {
+    cflags = [ "-fno-pie" ]
+    ldflags = [ "-no-pie" ]
+  } else if (current_cpu != "x86") {
     cflags = [ "-fPIE" ]
     ldflags = [ "-pie" ]
   }
diff --git a/pkg/_fe_analyzer_shared/analysis_options_no_lints.yaml b/pkg/_fe_analyzer_shared/analysis_options_no_lints.yaml
index 7bc4b9d9..a3e66b0 100644
--- a/pkg/_fe_analyzer_shared/analysis_options_no_lints.yaml
+++ b/pkg/_fe_analyzer_shared/analysis_options_no_lints.yaml
@@ -12,3 +12,4 @@
     - test/flow_analysis/nullability/data/**
     - test/flow_analysis/reachability/data/**
     - test/flow_analysis/type_promotion/data/**
+    - test/inheritance/data/**
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 3e51f3c..891df0b 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
@@ -808,10 +808,9 @@
   @override
   void finish() {
     if (_exceptionOccurred) {
-      print('finish() (skipped)');
+      _wrap('finish() (skipped)', () {}, isPure: true);
     } else {
-      print('finish()');
-      _wrapped.finish();
+      _wrap('finish()', () => _wrapped.finish(), isPure: true);
     }
   }
 
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 29f32d1..75251f5 100644
--- a/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
@@ -1358,8 +1358,9 @@
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const MessageCode messageConstructorWithTypeParameters = const MessageCode(
     "ConstructorWithTypeParameters",
-    analyzerCodes: <String>["TYPE_PARAMETER_ON_CONSTRUCTOR"],
-    message: r"""Constructors can't have type parameters.""");
+    index: 99,
+    message: r"""Constructors can't have type parameters.""",
+    tip: r"""Try removing the type parameters.""");
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Null> codeConstructorWithWrongName = messageConstructorWithWrongName;
@@ -7888,6 +7889,14 @@
     message: r"""Can't create typedef from non-function type.""");
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Null> codeTypedefNotType = messageTypedefNotType;
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const MessageCode messageTypedefNotType = const MessageCode("TypedefNotType",
+    analyzerCodes: <String>["INVALID_TYPE_IN_TYPEDEF"],
+    message: r"""Can't create typedef from non-type.""");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Null> codeUnexpectedDollarInString = messageUnexpectedDollarInString;
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/stack_listener.dart b/pkg/_fe_analyzer_shared/lib/src/parser/stack_listener.dart
index a9b9681..3442fe0 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/stack_listener.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/stack_listener.dart
@@ -71,7 +71,8 @@
 }
 
 abstract class StackListener extends Listener {
-  final Stack stack = new Stack();
+  static const bool debugStack = false;
+  final Stack stack = debugStack ? new DebugStack() : new StackImpl();
 
   /// Used to report an internal error encountered in the stack listener.
   dynamic internalProblem(Message message, int charOffset, Uri uri);
@@ -112,10 +113,9 @@
   bool checkState(Token token, List<ValueKind> kinds) {
     bool success = true;
     for (int kindIndex = 0; kindIndex < kinds.length; kindIndex++) {
-      int stackIndex = stack.arrayLength - kindIndex - 1;
       ValueKind kind = kinds[kindIndex];
-      if (stackIndex >= 0) {
-        Object value = stack.array[stackIndex];
+      if (kindIndex < stack.length) {
+        Object value = stack[kindIndex];
         if (!kind.check(value)) {
           success = false;
         }
@@ -154,8 +154,7 @@
       // Compute kind/stack frame information for all expected values plus 3 more
       // stack elements if available.
       for (int kindIndex = 0; kindIndex < kinds.length + 3; kindIndex++) {
-        int stackIndex = stack.arrayLength - kindIndex - 1;
-        if (stackIndex < 0 && kindIndex >= kinds.length) {
+        if (kindIndex >= stack.length && kindIndex >= kinds.length) {
           // No more stack elements nor kinds to display.
           break;
         }
@@ -168,8 +167,8 @@
         } else {
           sb.write(padRight('---', 60));
         }
-        if (stackIndex >= 0) {
-          Object value = stack.array[stackIndex];
+        if (kindIndex < stack.length) {
+          Object value = stack[kindIndex];
           if (kind == null || kind.check(value)) {
             sb.write(' ');
           } else {
@@ -496,7 +495,29 @@
       {bool wasHandled: false, List<LocatedMessage> context});
 }
 
-class Stack {
+abstract class Stack {
+  /// Pops [count] elements from the stack and puts it into [list].
+  /// Returns [null] if a [ParserRecovery] value is found, or [list] otherwise.
+  List<Object> popList(int count, List<Object> list, NullValue nullValue);
+
+  void push(Object value);
+
+  /// Will return [null] instead of [NullValue].
+  Object get last;
+
+  bool get isNotEmpty;
+
+  List<Object> get values;
+
+  Object pop(NullValue nullValue);
+
+  int get length;
+
+  /// Raw, i.e. [NullValue]s will be returned instead of [null].
+  Object operator [](int index);
+}
+
+class StackImpl implements Stack {
   List<Object> array = new List<Object>(8);
   int arrayLength = 0;
 
@@ -509,6 +530,10 @@
     return value is NullValue ? null : value;
   }
 
+  Object operator [](int index) {
+    return array[arrayLength - 1 - index];
+  }
+
   void push(Object value) {
     array[arrayLength++] = value;
     if (array.length == arrayLength) {
@@ -545,9 +570,7 @@
       } else if (value is ParserRecovery) {
         isParserRecovery = true;
       } else {
-        if (value is NullValue) {
-          print(value);
-        }
+        assert(value is! NullValue);
         list[i] = value;
       }
     }
@@ -571,6 +594,54 @@
   }
 }
 
+class DebugStack implements Stack {
+  Stack realStack = new StackImpl();
+  Stack stackTraceStack = new StackImpl();
+  List<StackTrace> latestStacktraces = new List<StackTrace>();
+
+  @override
+  Object operator [](int index) {
+    Object result = realStack[index];
+    latestStacktraces.clear();
+    latestStacktraces.add(stackTraceStack[index]);
+    return result;
+  }
+
+  @override
+  bool get isNotEmpty => realStack.isNotEmpty;
+
+  @override
+  Object get last => this[0];
+
+  @override
+  int get length => realStack.length;
+
+  @override
+  Object pop(NullValue nullValue) {
+    Object result = realStack.pop(nullValue);
+    latestStacktraces.clear();
+    latestStacktraces.add(stackTraceStack.pop(null));
+    return result;
+  }
+
+  @override
+  List<Object> popList(int count, List<Object> list, NullValue nullValue) {
+    List<Object> result = realStack.popList(count, list, nullValue);
+    latestStacktraces.length = count;
+    stackTraceStack.popList(count, latestStacktraces, null);
+    return result;
+  }
+
+  @override
+  void push(Object value) {
+    realStack.push(value);
+    stackTraceStack.push(StackTrace.current);
+  }
+
+  @override
+  List<Object> get values => realStack.values;
+}
+
 /// Helper constant for popping a list of the top of a [Stack].  This helper
 /// returns null instead of empty lists, and the lists returned are of fixed
 /// length.
diff --git a/pkg/_fe_analyzer_shared/lib/src/testing/id_testing.dart b/pkg/_fe_analyzer_shared/lib/src/testing/id_testing.dart
index 58acca5..4b7dd09 100644
--- a/pkg/_fe_analyzer_shared/lib/src/testing/id_testing.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/testing/id_testing.dart
@@ -214,7 +214,9 @@
   } else if (testFile is Directory) {
     testName = testFileUri.pathSegments[testFileUri.pathSegments.length - 2];
     additionalFiles = new Map<String, File>();
-    for (FileSystemEntity entry in testFile.listSync(recursive: true)) {
+    for (FileSystemEntity entry in testFile
+        .listSync(recursive: true)
+        .where((entity) => !entity.path.endsWith('~'))) {
       if (entry is! File) continue;
       if (entry.uri.pathSegments.last == "main.dart") {
         mainTestFile = entry;
diff --git a/pkg/_fe_analyzer_shared/test/inheritance/data/from_opt_out/main.dart b/pkg/_fe_analyzer_shared/test/inheritance/data/from_opt_out/main.dart
index 9a0cf4f..39c3c5f 100644
--- a/pkg/_fe_analyzer_shared/test/inheritance/data/from_opt_out/main.dart
+++ b/pkg/_fe_analyzer_shared/test/inheritance/data/from_opt_out/main.dart
@@ -9,13 +9,13 @@
 /*class: Class1:Class1,LegacyClass1,Object*/
 class Class1 extends LegacyClass1 {}
 
-/*class: Class2:Class2<T*>,LegacyClass2<T>,Object*/
+/*class: Class2:Class2<T>,LegacyClass2<T>,Object*/
 class Class2<T> extends LegacyClass2<T> {}
 
-/*class: Class3a:Class3a<T*>,GenericInterface<T*>,LegacyClass3<T>,Object*/
+/*class: Class3a:Class3a<T>,GenericInterface<T*>,LegacyClass3<T>,Object*/
 class Class3a<T> extends LegacyClass3<T> {}
 
-/*class: Class3b:Class3b<T*>,GenericInterface<T*>,LegacyClass3<T>,Object*/
+/*class: Class3b:Class3b<T>,GenericInterface<T*>,LegacyClass3<T>,Object*/
 class
 // TODO(johnniwinther): Avoid this error.
 /*error: AmbiguousSupertypes*/
diff --git a/pkg/analysis_server/doc/api.html b/pkg/analysis_server/doc/api.html
index 75207a9..6b68d27 100644
--- a/pkg/analysis_server/doc/api.html
+++ b/pkg/analysis_server/doc/api.html
@@ -257,7 +257,7 @@
 
 <p><a href="#domain_completion">Completion</a></p><ul><li><a href="#request_completion.getSuggestions">completion.getSuggestions</a></li>
 <li><a href="#request_completion.setSubscriptions">completion.setSubscriptions</a></li>
-<li><a href="#request_completion.registerLibraryPaths">completion.registerLibraryPaths</a></li>
+<li><a class="deprecated" href="#request_completion.registerLibraryPaths">completion.registerLibraryPaths</a></li>
 <li><a href="#request_completion.getSuggestionDetails">completion.getSuggestionDetails</a></li>
 </ul>
 
@@ -1518,7 +1518,7 @@
   <h4>parameters:</h4><dl><dt class="field"><b>subscriptions: List&lt;<a href="#type_CompletionService">CompletionService</a>&gt;</b></dt><dd>
         
         <p>A list of the services being subscribed to.</p>
-      </dd></dl></dd><dt class="request"><a name="request_completion.registerLibraryPaths">completion.registerLibraryPaths</a></dt><dd><div class="box"><pre>request: {
+      </dd></dl></dd><dt class="request deprecated"><a name="request_completion.registerLibraryPaths">completion.registerLibraryPaths</a></dt><dd><div class="box"><pre>request: {
   "id": String
   "method": "completion.registerLibraryPaths"
   "params": {
@@ -5131,6 +5131,11 @@
         <p>
           The given location does not have a supported widget.
         </p>
+      </dd><dt class="value">FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_EXPRESSION</dt><dd>
+        
+        <p>
+          The given property expression is invalid, e.g. has a syntax error.
+        </p>
       </dd><dt class="value">FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_ID</dt><dd>
         
         <p>
diff --git a/pkg/analysis_server/lib/protocol/protocol_generated.dart b/pkg/analysis_server/lib/protocol/protocol_generated.dart
index 9e8e335..a712f60 100644
--- a/pkg/analysis_server/lib/protocol/protocol_generated.dart
+++ b/pkg/analysis_server/lib/protocol/protocol_generated.dart
@@ -15780,6 +15780,9 @@
    * corresponds to an optional parameter, the corresponding named argument is
    * removed. If the property isRequired is true,
    * FLUTTER_SET_WIDGET_PROPERTY_VALUE_IS_REQUIRED error is generated.
+   *
+   * If the expression is not a syntactically valid Dart code, then
+   * FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_EXPRESSION is reported.
    */
   FlutterWidgetPropertyValue get value => _value;
 
@@ -15790,6 +15793,9 @@
    * corresponds to an optional parameter, the corresponding named argument is
    * removed. If the property isRequired is true,
    * FLUTTER_SET_WIDGET_PROPERTY_VALUE_IS_REQUIRED error is generated.
+   *
+   * If the expression is not a syntactically valid Dart code, then
+   * FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_EXPRESSION is reported.
    */
   void set value(FlutterWidgetPropertyValue value) {
     this._value = value;
@@ -19717,6 +19723,7 @@
  *   DEBUG_PORT_COULD_NOT_BE_OPENED
  *   FILE_NOT_ANALYZED
  *   FLUTTER_GET_WIDGET_DESCRIPTION_NO_WIDGET
+ *   FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_EXPRESSION
  *   FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_ID
  *   FLUTTER_SET_WIDGET_PROPERTY_VALUE_IS_REQUIRED
  *   FORMAT_INVALID_FILE
@@ -19778,6 +19785,14 @@
       const RequestErrorCode._("FLUTTER_GET_WIDGET_DESCRIPTION_NO_WIDGET");
 
   /**
+   * The given property expression is invalid, e.g. has a syntax error.
+   */
+  static const RequestErrorCode
+      FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_EXPRESSION =
+      const RequestErrorCode._(
+          "FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_EXPRESSION");
+
+  /**
    * The given property identifier is not valid. It might have never been
    * valid, or a change to code invalidated it, or its TTL was exceeded.
    */
@@ -19985,6 +20000,7 @@
     DEBUG_PORT_COULD_NOT_BE_OPENED,
     FILE_NOT_ANALYZED,
     FLUTTER_GET_WIDGET_DESCRIPTION_NO_WIDGET,
+    FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_EXPRESSION,
     FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_ID,
     FLUTTER_SET_WIDGET_PROPERTY_VALUE_IS_REQUIRED,
     FORMAT_INVALID_FILE,
@@ -20030,6 +20046,8 @@
         return FILE_NOT_ANALYZED;
       case "FLUTTER_GET_WIDGET_DESCRIPTION_NO_WIDGET":
         return FLUTTER_GET_WIDGET_DESCRIPTION_NO_WIDGET;
+      case "FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_EXPRESSION":
+        return FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_EXPRESSION;
       case "FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_ID":
         return FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_ID;
       case "FLUTTER_SET_WIDGET_PROPERTY_VALUE_IS_REQUIRED":
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index 66a68e8..5da8cbf 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -786,8 +786,8 @@
       bool isManaged = rootInfo._managesOrHasChildThatManages(includedPath);
       if (!isManaged) {
         ContextInfo parent = _getParentForNewContext(includedPath);
-        changeSubscriptions[includedFolder] =
-            includedFolder.changes.listen(_handleWatchEvent);
+        changeSubscriptions[includedFolder] = includedFolder.changes
+            .listen(_handleWatchEvent, onError: _handleWatchInterruption);
         _createContexts(parent, includedFolder, excludedPaths, false);
       }
     }
@@ -1407,6 +1407,15 @@
     callbacks.afterWatchEvent(event);
   }
 
+  /// On windows, the directory watcher may overflow, and we must recover.
+  void _handleWatchInterruption(dynamic error, StackTrace stackTrace) {
+    // We've handled the error, so we only have to log it.
+    AnalysisEngine.instance.instrumentationService
+        .logError('Watcher error; refreshing contexts.\n$error\n$stackTrace');
+    // TODO(mfairhurst): Optimize this, or perhaps be less complete.
+    refresh(null);
+  }
+
   void _handleWatchEventImpl(WatchEvent event) {
     // Figure out which context this event applies to.
     // TODO(brianwilkerson) If a file is explicitly included in one context
diff --git a/pkg/analysis_server/lib/src/domain_kythe.dart b/pkg/analysis_server/lib/src/domain_kythe.dart
index 4e7cffb..8acf1e6 100644
--- a/pkg/analysis_server/lib/src/domain_kythe.dart
+++ b/pkg/analysis_server/lib/src/domain_kythe.dart
@@ -16,7 +16,6 @@
 import 'package:analyzer/dart/analysis/results.dart';
 import 'package:analyzer/src/dart/analysis/driver.dart';
 import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
-import 'package:analyzer/src/generated/type_system.dart';
 import 'package:analyzer_plugin/protocol/protocol.dart' as plugin;
 import 'package:analyzer_plugin/protocol/protocol_common.dart';
 import 'package:analyzer_plugin/protocol/protocol_constants.dart' as plugin;
@@ -58,16 +57,11 @@
           <KytheGetKytheEntriesResult>[];
       ResolvedUnitResult result = await server.getResolvedUnit(file);
       if (result?.state == ResultState.VALID) {
-        TypeSystem typeSystem = await result.libraryElement.session.typeSystem;
         List<KytheEntry> entries = <KytheEntry>[];
         // TODO(brianwilkerson) Figure out how to get the list of files.
         List<String> files = <String>[];
-        result.unit.accept(new KytheDartVisitor(
-            server.resourceProvider,
-            entries,
-            file,
-            new InheritanceManager3(typeSystem),
-            result.content));
+        result.unit.accept(new KytheDartVisitor(server.resourceProvider,
+            entries, file, new InheritanceManager3(), result.content));
         allResults.add(new KytheGetKytheEntriesResult(entries, files));
       }
       //
diff --git a/pkg/analysis_server/lib/src/edit/fix/non_nullable_fix.dart b/pkg/analysis_server/lib/src/edit/fix/non_nullable_fix.dart
index 267a8c9..4fc9eb5 100644
--- a/pkg/analysis_server/lib/src/edit/fix/non_nullable_fix.dart
+++ b/pkg/analysis_server/lib/src/edit/fix/non_nullable_fix.dart
@@ -8,6 +8,7 @@
 import 'package:analysis_server/src/edit/fix/fix_code_task.dart';
 import 'package:analysis_server/src/edit/nnbd_migration/highlight_css.dart';
 import 'package:analysis_server/src/edit/nnbd_migration/highlight_js.dart';
+import 'package:analysis_server/src/edit/nnbd_migration/index_renderer.dart';
 import 'package:analysis_server/src/edit/nnbd_migration/info_builder.dart';
 import 'package:analysis_server/src/edit/nnbd_migration/instrumentation_listener.dart';
 import 'package:analysis_server/src/edit/nnbd_migration/instrumentation_renderer.dart';
@@ -82,7 +83,7 @@
   @override
   Future<void> finish() async {
     migration.finish();
-    if (outputDir != null && port == null) {
+    if (outputDir != null) {
       OverlayResourceProvider provider = listener.server.resourceProvider;
       Folder outputFolder = provider.getFolder(outputDir);
       if (!outputFolder.exists) {
@@ -92,23 +93,17 @@
     }
     if (port != null) {
       OverlayResourceProvider provider = listener.server.resourceProvider;
-      InfoBuilder infoBuilder =
-          InfoBuilder(instrumentationListener.data, listener);
+      InfoBuilder infoBuilder = InfoBuilder(
+          provider, includedRoot, instrumentationListener.data, listener);
       Set<UnitInfo> unitInfos = await infoBuilder.explainMigration();
       var pathContext = provider.pathContext;
       MigrationInfo migrationInfo = MigrationInfo(
           unitInfos, infoBuilder.unitMap, pathContext, includedRoot);
       PathMapper pathMapper = PathMapper(provider, outputDir, includedRoot);
-      // TODO(brianwilkerson) Print a URL that users can paste into the browser.
-      //  The code below is close to right, but computes the wrong path. We
-      //  don't have enough information to pick a single library inside `lib`,
-      //  so we might want to consider alternatives, such as a directory listing
-      //  page or an empty file page.
-//      print(Uri(
-//          scheme: 'http',
-//          host: 'localhost',
-//          port: 10501,
-//          path: pathMapper.map('$includedRoot/lib/logging.dart')));
+
+      print(Uri(
+          scheme: 'http', host: 'localhost', port: port, path: includedRoot));
+
       // TODO(brianwilkerson) Capture the server so that it can be closed
       //  cleanly.
       HttpPreviewServer(migrationInfo, pathMapper).serveHttp(port);
@@ -250,8 +245,8 @@
     // Remove any previously generated output.
     folder.getChildren().forEach((resource) => resource.delete());
     // Gather the data needed in order to produce the output.
-    InfoBuilder infoBuilder =
-        InfoBuilder(instrumentationListener.data, listener);
+    InfoBuilder infoBuilder = InfoBuilder(
+        provider, includedRoot, instrumentationListener.data, listener);
     Set<UnitInfo> unitInfos = await infoBuilder.explainMigration();
     var pathContext = provider.pathContext;
     MigrationInfo migrationInfo = MigrationInfo(
@@ -267,11 +262,23 @@
       output.writeAsStringSync(rendered);
     }
 
+    //
+    // Generate the index file.
+    //
+    String indexPath = pathContext.join(folder.path, 'index.html');
+    File output = provider.getFile(indexPath);
+    output.parent.create();
+    String rendered = IndexRenderer(migrationInfo, writeToDisk: true).render();
+    output.writeAsStringSync(rendered);
+    //
     // Generate the files in the package being migrated.
+    //
     for (UnitInfo unitInfo in unitInfos) {
       render(unitInfo);
     }
+    //
     // Generate other dart files.
+    //
     for (UnitInfo unitInfo in infoBuilder.unitMap.values) {
       if (!unitInfos.contains(unitInfo)) {
         if (unitInfo.content == null) {
@@ -344,7 +351,9 @@
 
   @override
   void addFix(SingleNullabilityFix fix) {
-    listener.addSuggestion(fix.description.appliedMessage, fix.location);
+    for (Location location in fix.locations) {
+      listener.addSuggestion(fix.description.appliedMessage, location);
+    }
   }
 
   @override
diff --git a/pkg/analysis_server/lib/src/edit/nnbd_migration/index_renderer.dart b/pkg/analysis_server/lib/src/edit/nnbd_migration/index_renderer.dart
new file mode 100644
index 0000000..cf34775c
--- /dev/null
+++ b/pkg/analysis_server/lib/src/edit/nnbd_migration/index_renderer.dart
@@ -0,0 +1,116 @@
+// Copyright (c) 2019, 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:analysis_server/src/edit/nnbd_migration/instrumentation_renderer.dart';
+import 'package:analysis_server/src/edit/nnbd_migration/migration_info.dart';
+import 'package:path/src/context.dart';
+
+/// The renderer used to displayed when the root of the included path is requested.
+class IndexRenderer {
+  /// Information for a whole migration, so that libraries can reference each
+  /// other.
+  final MigrationInfo migrationInfo;
+
+  /// A flag indicating whether the paths for the links should be computed for
+  /// the case where the rendered index will be written to disk.
+  final bool writeToDisk;
+
+  /// Initialize a newly index renderer.
+  IndexRenderer(this.migrationInfo, {this.writeToDisk = false});
+
+  /// Builds an HTML view of the included root directory.
+  String render() {
+    Context pathContext = migrationInfo.pathContext;
+    String includedRoot = migrationInfo.includedRoot;
+
+    StringBuffer buf = StringBuffer();
+    buf.write('''
+<html>
+  <head>
+    <title>Non-nullable fix instrumentation report</title>
+    <style>
+a:link {
+  color: inherit;
+  text-decoration-line: none;
+}
+
+a:visited {
+  color: inherit;
+  text-decoration-line: none;
+}
+
+a:hover {
+  text-decoration-line: underline;
+}
+
+body {
+  font-family: sans-serif;
+  padding: 1em;
+}
+
+.navigationHeader {
+  padding-left: 1em;
+}
+
+.navigationLinks {
+  padding-left: 2em;
+}
+
+.selectedFile {
+  font-weight: bold;
+}
+    </style>
+  </head>
+  <body>
+    <h1>Preview of NNBD migration</h1>
+    <p><b>
+    Select a migrated file to see the suggested modifications below.
+    </b></p>
+    <div class="navigationHeader">
+''');
+    buf.writeln(includedRoot);
+    buf.write('''
+    </div>
+    <div class="navigationLinks">
+''');
+    for (UnitInfo unit in migrationInfo.units) {
+      buf.write('<a href="');
+      buf.write(_pathTo(unit, pathContext, includedRoot));
+      buf.write('">');
+      buf.write(_name(unit, pathContext, includedRoot));
+      buf.write('</a> ');
+      buf.write(_modificationCount(unit));
+      buf.write('<br/>');
+    }
+    buf.write('''
+    </div>
+  </body>
+</html>
+''');
+    return buf.toString();
+  }
+
+  /// Return the number of modifications made to the [unit].
+  String _modificationCount(UnitInfo unit) {
+    int count = unit.fixRegions.length;
+    return count == 1 ? '(1 modification)' : '($count modifications)';
+  }
+
+  /// Return the path to [unit] from [includedRoot], to be used as a display
+  /// name for a library.
+  String _name(UnitInfo unit, Context pathContext, String includedRoot) =>
+      pathContext.relative(unit.path, from: includedRoot);
+
+  /// The path to [target], relative to [includedRoot].
+  String _pathTo(UnitInfo target, Context pathContext, String includedRoot) {
+    String targetPath;
+    if (writeToDisk) {
+      targetPath = pathContext.setExtension(target.path, '.html');
+    } else {
+      targetPath = target.path;
+    }
+    String sourceDir = pathContext.dirname(includedRoot);
+    return pathContext.relative(targetPath, from: sourceDir);
+  }
+}
diff --git a/pkg/analysis_server/lib/src/edit/nnbd_migration/info_builder.dart b/pkg/analysis_server/lib/src/edit/nnbd_migration/info_builder.dart
index c5592b5..611c890 100644
--- a/pkg/analysis_server/lib/src/edit/nnbd_migration/info_builder.dart
+++ b/pkg/analysis_server/lib/src/edit/nnbd_migration/info_builder.dart
@@ -15,6 +15,7 @@
 import 'package:analyzer/dart/analysis/session.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer_plugin/protocol/protocol_common.dart'
     show Location, SourceEdit, SourceFileEdit;
@@ -36,6 +37,11 @@
 
 /// A builder used to build the migration information for a library.
 class InfoBuilder {
+  /// The resource provider used to access the file system.
+  ResourceProvider provider;
+
+  String includedPath;
+
   /// The instrumentation information gathered while the migration engine was
   /// running.
   final InstrumentationInformation info;
@@ -52,7 +58,8 @@
   final Map<String, UnitInfo> unitMap = {};
 
   /// Initialize a newly created builder.
-  InfoBuilder(this.info, this.listener, {this.explainNonNullableTypes = false});
+  InfoBuilder(this.provider, this.includedPath, this.info, this.listener,
+      {this.explainNonNullableTypes = false});
 
   /// The analysis server used to get information about libraries.
   AnalysisServer get server => listener.server;
@@ -74,48 +81,94 @@
         for (ResolvedUnitResult unitResult in result.units) {
           SourceFileEdit edit =
               listener.sourceChange.getFileEdit(unitResult.path);
-          units.add(_explainUnit(sourceInfo, unitResult, edit));
+          UnitInfo unit = _explainUnit(sourceInfo, unitResult, edit);
+          if (provider.pathContext.isWithin(includedPath, unitResult.path)) {
+            units.add(unit);
+          }
         }
       }
     }
     return units;
   }
 
+  Iterable<EdgeInfo> upstreamTriggeredEdges(NullabilityNodeInfo node,
+      [List<RegionDetail> details]) {
+    var edges = <EdgeInfo>[];
+    for (EdgeInfo edge in node.upstreamEdges) {
+      if (node.isExactNullable && edge.sourceNode.isExactNullable) {
+        // When an exact nullable points here, the nullability propagated
+        // in the other direction.
+        continue;
+      }
+      if (edge.isTriggered) {
+        edges.add(edge);
+      }
+    }
+    for (final containerNode in node.outerCompoundNodes) {
+      edges.addAll(upstreamTriggeredEdges(containerNode, details));
+    }
+
+    return edges;
+  }
+
   /// Return detail text for a fix built from an edge with [node] as a
   /// destination.
-  String _baseDescriptionForOrigin(EdgeOriginInfo origin) {
+  String _baseDescriptionForOrigin(
+      EdgeOriginInfo origin, NullabilityFixKind fixKind) {
     AstNode node = origin.node;
     AstNode parent = node.parent;
 
-    if (node is DefaultFormalParameter) {
+    String aNullableDefault(DefaultFormalParameter node) {
       Expression defaultValue = node.defaultValue;
       if (defaultValue == null) {
-        return "This parameter has an implicit default value of 'null'";
+        return "an implicit default value of 'null'";
       } else if (defaultValue is NullLiteral) {
-        return "This parameter has an explicit default value of 'null'";
+        return "an explicit default value of 'null'";
       }
-      return "This parameter has a nullable default value";
+      return "a nullable default value";
+    }
+
+    if (node is DefaultFormalParameter) {
+      if (fixKind == NullabilityFixKind.addRequired) {
+        return "This parameter is non-nullable, so cannot have "
+            "${aNullableDefault(node)}";
+      } else {
+        return "This parameter has ${aNullableDefault(node)}";
+      }
     } else if (node is FieldFormalParameter) {
       AstNode parent = node.parent;
       if (parent is DefaultFormalParameter) {
-        Expression defaultValue = parent.defaultValue;
-        if (defaultValue == null) {
-          return "This field is initialized by an optional field formal "
-              "parameter that has an implicit default value of 'null'";
-        } else if (defaultValue is NullLiteral) {
-          return "This field is initialized by an optional field formal "
-              "parameter that has an explicit default value of 'null'";
-        }
         return "This field is initialized by an optional field formal "
-            "parameter that has a nullable default value";
+            "parameter that has ${aNullableDefault(parent)}";
       }
       return "This field is initialized by a field formal parameter and a "
           "nullable value is passed as an argument";
     } else if (parent is AsExpression) {
       return "The value of the expression is nullable";
     }
-    String nullableValue =
-        node is NullLiteral ? "an explicit 'null'" : "a nullable value";
+
+    // Text indicating the type of nullable value found.
+    String nullableValue;
+    if (node is NullLiteral) {
+      nullableValue = "an explicit 'null'";
+    } else if (origin.kind == EdgeOriginKind.dynamicAssignment) {
+      nullableValue = "a dynamic value, which is nullable";
+    } else {
+      nullableValue = "a nullable value";
+    }
+
+    CompilationUnit unit = node.thisOrAncestorOfType<CompilationUnit>();
+    int lineNumber = unit.lineInfo.getLocation(node.offset).lineNumber;
+
+    if (origin.kind == EdgeOriginKind.parameterInheritance) {
+      return "The corresponding parameter in the overridden method is "
+          "nullable";
+    } else if (origin.kind == EdgeOriginKind.returnTypeInheritance) {
+      return "An overridding method has a nullable return value";
+    } else if (origin.kind == EdgeOriginKind.uninitializedRead) {
+      return "Used on line $lineNumber, when it is possibly uninitialized";
+    }
+
     if (parent is ArgumentList) {
       return capitalize("$nullableValue is passed as an argument");
     }
@@ -145,8 +198,6 @@
       return (ancestor is TypedLiteral) ? ancestor : null;
     }
 
-    CompilationUnit unit = node.thisOrAncestorOfType<CompilationUnit>();
-    int lineNumber = unit.lineInfo.getLocation(node.offset).lineNumber;
     FunctionBody functionBody = findFunctionBody();
     if (functionBody != null) {
       AstNode function = functionBody.parent;
@@ -178,13 +229,24 @@
         return "This field is initialized to $nullableValue";
       }
       return "This variable is initialized to $nullableValue";
+    } else if (node is ConstructorDeclaration &&
+        origin.kind == EdgeOriginKind.fieldNotInitialized) {
+      String constructorName =
+          node.declaredElement.enclosingElement.displayName;
+      if (node.declaredElement.displayName.isNotEmpty) {
+        constructorName =
+            "$constructorName.${node.declaredElement.displayName}";
+      }
+      return "The constructor '$constructorName' does not initialize this "
+          "field in its initializer list";
     }
     return capitalize("$nullableValue is assigned");
   }
 
   /// Return a description of the given [origin].
-  String _buildDescriptionForOrigin(EdgeOriginInfo origin) {
-    String description = _baseDescriptionForOrigin(origin);
+  String _buildDescriptionForOrigin(
+      EdgeOriginInfo origin, NullabilityFixKind fixKind) {
+    String description = _baseDescriptionForOrigin(origin, fixKind);
     if (_inTestCode(origin.node)) {
       // TODO(brianwilkerson) Don't add this if the graph node with which the
       //  origin is associated is also in test code.
@@ -194,7 +256,8 @@
   }
 
   /// Return a description of the given [origin] associated with the [edge].
-  RegionDetail _buildDetailForOrigin(EdgeOriginInfo origin, EdgeInfo edge) {
+  RegionDetail _buildDetailForOrigin(
+      EdgeOriginInfo origin, EdgeInfo edge, NullabilityFixKind fixKind) {
     AstNode node = origin.node;
     NavigationTarget target;
     // Some nodes don't need a target; default formal parameters
@@ -202,27 +265,22 @@
     if (node is DefaultFormalParameter && node.defaultValue == null) {
       target = null;
     } else {
-      if (origin.kind == EdgeOriginKind.inheritance) {
+      if (origin.kind == EdgeOriginKind.parameterInheritance ||
+          origin.kind == EdgeOriginKind.returnTypeInheritance) {
         // The node is the method declaration in the subclass and we want to
-        // link to the corresponding parameter in the declaration in the
-        // superclass.
+        // link to the either the corresponding parameter in the declaration in
+        // the superclass, or the return type in the declaration in that
+        // subclass.
         TypeAnnotation type = info.typeAnnotationForNode(edge.sourceNode);
         if (type != null) {
           CompilationUnit unit = type.thisOrAncestorOfType<CompilationUnit>();
           target = _targetForNode(unit.declaredElement.source.fullName, type);
-          return RegionDetail(
-              "The corresponding parameter in the overridden method is "
-              "nullable",
-              target);
-          // TODO(srawlins): Also, this could be where a return type in an
-          //  overridden method is made nullable because an overriding method
-          //  was found with a nullable return type. Figure out how to tell
-          //  which situation we are in.
         }
+      } else {
+        target = _targetForNode(origin.source.fullName, node);
       }
-      target = _targetForNode(origin.source.fullName, node);
     }
-    return RegionDetail(_buildDescriptionForOrigin(origin), target);
+    return RegionDetail(_buildDescriptionForOrigin(origin, fixKind), target);
   }
 
   /// Compute the details for the fix with the given [fixInfo].
@@ -230,23 +288,48 @@
     List<RegionDetail> details = [];
     for (FixReasonInfo reason in fixInfo.reasons) {
       if (reason is NullabilityNodeInfo) {
-        for (EdgeInfo edge in reason.upstreamEdges) {
-          if (edge.isTriggered) {
-            EdgeOriginInfo origin = info.edgeOrigin[edge];
-            if (origin != null) {
-              details.add(_buildDetailForOrigin(origin, edge));
-            } else {
-              details.add(
-                  RegionDetail('upstream edge with no origin ($edge)', null));
+        if (reason.isExactNullable) {
+          // When the node is exact nullable, that nullability propagated from
+          // downstream.
+          for (EdgeInfo edge in reason.downstreamEdges) {
+            final exactNullableDownstream = edge.destinationNode;
+            if (!exactNullableDownstream.isExactNullable) {
+              // This wasn't the source of the nullability.
+              continue;
             }
+
+            var nodeInfo = info.nodeInfoFor(exactNullableDownstream);
+            if (nodeInfo != null) {
+              // TODO(mfairhurst): Give a better text description.
+              details.add(RegionDetail('This is later required to accept null.',
+                  _targetForNode(nodeInfo.filePath, nodeInfo.astNode)));
+            } else {
+              details.add(RegionDetail(
+                  'exact nullable node with no info ($exactNullableDownstream)',
+                  null));
+            }
+          }
+        }
+
+        for (EdgeInfo edge in upstreamTriggeredEdges(reason)) {
+          EdgeOriginInfo origin = info.edgeOrigin[edge];
+          if (origin != null) {
+            details.add(_buildDetailForOrigin(
+                origin, edge, fixInfo.fix.description.kind));
+          } else {
+            details.add(
+                RegionDetail('upstream edge with no origin ($edge)', null));
           }
         }
       } else if (reason is EdgeInfo) {
         NullabilityNodeInfo destination = reason.destinationNode;
-        var nodeInfo = info.nodeInfoFor(destination);
-        if (nodeInfo != null) {
-          details.add(RegionDetail(nodeInfo.descriptionForDestination,
-              _targetForNode(nodeInfo.filePath, nodeInfo.astNode)));
+        NodeInformation nodeInfo = info.nodeInfoFor(destination);
+        if (nodeInfo != null && nodeInfo.astNode != null) {
+          NavigationTarget target;
+          if (destination != info.never && destination != info.always) {
+            target = _targetForNode(nodeInfo.filePath, nodeInfo.astNode);
+          }
+          details.add(RegionDetail(nodeInfo.descriptionForDestination, target));
         } else {
           details.add(RegionDetail('node with no info ($destination)', null));
         }
@@ -258,6 +341,20 @@
     return details;
   }
 
+  /// Return a list of edits that can be applied.
+  List<EditDetail> _computeEdits(FixInfo fixInfo) {
+    // TODO(brianwilkerson) Add other kinds of edits, such as adding an assert.
+    List<EditDetail> edits = [];
+    SingleNullabilityFix fix = fixInfo.fix;
+    if (fix.description.kind == NullabilityFixKind.makeTypeNullable) {
+      for (Location location in fix.locations) {
+        edits.add(EditDetail(
+            'Force type to be non-nullable.', location.offset, 0, '/*!*/'));
+      }
+    }
+    return edits;
+  }
+
   /// Return the navigation sources for the unit associated with the [result].
   List<NavigationSource> _computeNavigationSources(ResolvedUnitResult result) {
     NavigationCollectorImpl collector = new NavigationCollectorImpl();
@@ -302,13 +399,6 @@
         details.add(RegionDetail(
             'This value is unconditionally used in a non-nullable context',
             target));
-      } else if (origin.kind == EdgeOriginKind.inheritance) {
-        // TODO(srawlins): Figure out why this EdgeOriginKind is used.
-        details.add(RegionDetail('Something about inheritance', target));
-      } else if (origin.kind == EdgeOriginKind.initializerInference) {
-        // TODO(srawlins): Figure out why this EdgeOriginKind is used.
-        details.add(
-            RegionDetail('Something about initializer inheritance', target));
       } else if (origin.kind == EdgeOriginKind.nonNullAssertion) {
         details
             .add(RegionDetail('This value is asserted to be non-null', target));
@@ -340,11 +430,11 @@
             _computeUpstreamTriggeredDetails(upstreamTriggeredEdgeInfos);
         TypeAnnotation node = nonNullableType.key;
         regions.add(RegionInfo(
+            RegionType.nonNullableType,
             mapper.map(node.offset),
             node.length,
             "This type is not changed; it is determined to be non-nullable",
-            details,
-            RegionType.nonNullableType));
+            details));
       }
     }
   }
@@ -377,12 +467,15 @@
       if (fixInfo != null) {
         String explanation = '${fixInfo.fix.description.appliedMessage}.';
         List<RegionDetail> details = _computeDetails(fixInfo);
+        List<EditDetail> edits = _computeEdits(fixInfo);
         if (length > 0) {
-          regions.add(RegionInfo(mapper.map(offset), length, explanation,
-              details, RegionType.fix));
+          regions.add(RegionInfo(
+              RegionType.fix, mapper.map(offset), length, explanation, details,
+              edits: edits));
         }
-        regions.add(RegionInfo(mapper.map(end), replacement.length, explanation,
-            details, RegionType.fix));
+        regions.add(RegionInfo(RegionType.fix, mapper.map(end),
+            replacement.length, explanation, details,
+            edits: edits));
       }
     }
     if (explainNonNullableTypes) {
@@ -400,9 +493,10 @@
   FixInfo _findFixInfo(SourceInformation sourceInfo, int offset) {
     for (MapEntry<SingleNullabilityFix, List<FixReasonInfo>> entry
         in sourceInfo.fixes.entries) {
-      Location location = entry.key.location;
-      if (location.offset == offset) {
-        return FixInfo(entry.key, entry.value);
+      for (Location location in entry.key.locations) {
+        if (location.offset == offset) {
+          return FixInfo(entry.key, entry.value);
+        }
       }
     }
     return null;
diff --git a/pkg/analysis_server/lib/src/edit/nnbd_migration/instrumentation_information.dart b/pkg/analysis_server/lib/src/edit/nnbd_migration/instrumentation_information.dart
index 6510931..0176e1e 100644
--- a/pkg/analysis_server/lib/src/edit/nnbd_migration/instrumentation_information.dart
+++ b/pkg/analysis_server/lib/src/edit/nnbd_migration/instrumentation_information.dart
@@ -63,17 +63,13 @@
 
   final Element element;
 
-  final String descriptionPrefix;
-
-  NodeInformation(
-      this.filePath, this.astNode, this.element, this.descriptionPrefix);
+  NodeInformation(this.filePath, this.astNode, this.element);
 
   /// Return detail text for a fix built from an edge with this node as a
   /// destination.
   String get descriptionForDestination {
-    // TODO(paulberry): describe AST nodes
-    var description = (element ?? '???').toString();
-    return "A nullable value can't be used as $descriptionPrefix$description";
+    // TODO(paulberry): describe AST nodes.
+    return "A nullable value can't be used here";
   }
 }
 
diff --git a/pkg/analysis_server/lib/src/edit/nnbd_migration/instrumentation_listener.dart b/pkg/analysis_server/lib/src/edit/nnbd_migration/instrumentation_listener.dart
index 0f977ed..db35c5e 100644
--- a/pkg/analysis_server/lib/src/edit/nnbd_migration/instrumentation_listener.dart
+++ b/pkg/analysis_server/lib/src/edit/nnbd_migration/instrumentation_listener.dart
@@ -22,21 +22,21 @@
   @override
   void explicitTypeNullability(
       Source source, TypeAnnotation typeAnnotation, NullabilityNodeInfo node) {
-    data.nodeInformation[node] = NodeInformation(
-        _filePathForSource(source), typeAnnotation, null, 'the explicit type ');
+    data.nodeInformation[node] =
+        NodeInformation(_filePathForSource(source), typeAnnotation, null);
     _sourceInfo(source).explicitTypeNullability[typeAnnotation] = node;
   }
 
   @override
   void externalDecoratedType(Element element, DecoratedTypeInfo decoratedType) {
-    _storeNodeInformation(decoratedType, element.source, null, element, '');
+    _storeNodeInformation(decoratedType, element.source, null, element);
   }
 
   @override
   void externalDecoratedTypeParameterBound(
       TypeParameterElement typeParameter, DecoratedTypeInfo decoratedType) {
     _storeNodeInformation(
-        decoratedType, typeParameter.source, null, typeParameter, 'bound of ');
+        decoratedType, typeParameter.source, null, typeParameter);
   }
 
   @override
@@ -59,24 +59,20 @@
   @override
   void implicitReturnType(
       Source source, AstNode node, DecoratedTypeInfo decoratedReturnType) {
-    _storeNodeInformation(
-        decoratedReturnType, source, node, null, 'return type of ');
+    _storeNodeInformation(decoratedReturnType, source, node, null);
   }
 
   @override
   void implicitType(
       Source source, AstNode node, DecoratedTypeInfo decoratedType) {
-    _storeNodeInformation(decoratedType, source, node, null, 'type of ');
+    _storeNodeInformation(decoratedType, source, node, null);
   }
 
   @override
   void implicitTypeArguments(
       Source source, AstNode node, Iterable<DecoratedTypeInfo> types) {
-    int i = 0;
     for (var type in types) {
-      _storeNodeInformation(
-          type, source, node, null, 'implicit type argument $i of ');
-      i++;
+      _storeNodeInformation(type, source, node, null);
     }
   }
 
@@ -94,30 +90,35 @@
   SourceInformation _sourceInfo(Source source) =>
       data.sourceInformation.putIfAbsent(source, () => SourceInformation());
 
+  // TODO(srawlins): This code is completely untested.
   void _storeNodeInformation(DecoratedTypeInfo decoratedType, Source source,
-      AstNode astNode, Element element, String description) {
+      AstNode astNode, Element element) {
     // Make sure source info exists for the given source.
     _sourceInfo(source);
-    data.nodeInformation[decoratedType.node] = NodeInformation(
-        _filePathForSource(source), astNode, element, description);
+    data.nodeInformation[decoratedType.node] =
+        NodeInformation(_filePathForSource(source), astNode, element);
     var dartType = decoratedType.type;
     if (dartType is InterfaceType) {
       for (int i = 0; i < dartType.typeArguments.length; i++) {
-        _storeNodeInformation(decoratedType.typeArgument(i), source, astNode,
-            element, 'type argument $i of $description');
+        _storeNodeInformation(
+            decoratedType.typeArgument(i), source, astNode, element);
       }
     } else if (dartType is FunctionType) {
-      _storeNodeInformation(decoratedType.returnType, source, astNode, element,
-          'return type of $description');
+      _storeNodeInformation(
+        decoratedType.returnType,
+        source,
+        astNode,
+        element,
+      );
       int i = 0;
       for (var parameter in dartType.parameters) {
         if (parameter.isNamed) {
           var name = parameter.name;
-          _storeNodeInformation(decoratedType.namedParameter(name), source,
-              astNode, element, 'named parameter $name of $description');
+          _storeNodeInformation(
+              decoratedType.namedParameter(name), source, astNode, element);
         } else {
-          _storeNodeInformation(decoratedType.positionalParameter(i), source,
-              astNode, element, 'positional parameter $i of $description');
+          _storeNodeInformation(
+              decoratedType.positionalParameter(i), source, astNode, element);
           i++;
         }
       }
diff --git a/pkg/analysis_server/lib/src/edit/nnbd_migration/instrumentation_renderer.dart b/pkg/analysis_server/lib/src/edit/nnbd_migration/instrumentation_renderer.dart
index cb4ae0c..e3070f9 100644
--- a/pkg/analysis_server/lib/src/edit/nnbd_migration/instrumentation_renderer.dart
+++ b/pkg/analysis_server/lib/src/edit/nnbd_migration/instrumentation_renderer.dart
@@ -77,6 +77,16 @@
   font-weight: bold;
 }
 
+.content {
+  font-family: monospace;
+  /* Vertical margin around content. */
+  margin: 1em 0;
+  /* Offset the margin introduced by the absolutely positioned child div. */
+  margin-left: -0.5em;
+  position: relative;
+  white-space: pre;
+}
+
 .code {
   left: 0.5em;
   /* Increase line height to make room for borders in non-nullable type
@@ -84,14 +94,16 @@
    */
   line-height: 1.3;
   padding-left: 60px;
-  position: absolute;
+  position: inherit;
   top: 0.5em;
 }
 
-.content {
-  font-family: monospace;
-  position: relative;
-  white-space: pre;
+.navigationHeader {
+  padding-left: 1em;
+}
+
+.navigationLinks {
+  padding-left: 2em;
 }
 
 .regions {
@@ -176,6 +188,10 @@
   visibility: visible;
 }
 
+.selectedFile {
+  font-weight: bold;
+}
+
 .target {
   background-color: #FFFF99;
   position: relative;
@@ -184,17 +200,25 @@
     </style>
   </head>
   <body>
-    <h1>Non-nullable fix instrumentation report</h1>
-    <p>Migrated files:</p>
-    <div class="navigation">
+    <h1>Preview of NNBD migration</h1>
+    <p><b>
+    Select a migrated file to see the suggested modifications below.
+    </b></p>
+    <div class="navigationHeader">
+    {{ root }}
+    </div>
+    <div class="navigationLinks">
       {{# links }}
         {{# isLink }}<a href="{{ href }}">{{ name }}</a>{{/ isLink }}
-        {{^ isLink }}{{ name }}{{/ isLink }}
-        <br />
+        {{^ isLink }}<span class="selectedFile">{{ name }}</span>{{/ isLink }}
+        {{ modificationCount }}
+        <br/>
       {{/ links }}
     </div>
-    {{# units }}'''
-    '<h2>{{{ path }}}</h2>'
+    {{# units }}
+    <p><b>
+    Hover over modified regions to see why the modification is suggested.
+    </b></p>'''
     '<div class="content">'
     '<div class="code">'
     '{{! Write the file content, modified to include navigation information, }}'
@@ -206,6 +230,9 @@
     '{{! the content, to provide tooltips for modified regions. }}'
     '{{{ regionContent }}}'
     '</div></div>'
+    '<div>'
+    '<i>Generated on {{ generationDate }}</i>'
+    '</div>'
     r'''
     {{/ units }}
     <script lang="javascript">
@@ -221,6 +248,9 @@
 /// Instrumentation display output for a library that was migrated to use
 /// non-nullable types.
 class InstrumentationRenderer {
+  /// A flag indicating whether the incremental workflow is currently supported.
+  static const bool supportsIncrementalWorkflow = false;
+
   /// Display information for a compilation unit.
   final UnitInfo unitInfo;
 
@@ -241,11 +271,13 @@
   /// Builds an HTML view of the instrumentation information in [unitInfo].
   String render() {
     Map<String, dynamic> mustacheContext = {
+      'root': migrationInfo.includedRoot,
       'units': <Map<String, dynamic>>[],
       'links': migrationInfo.unitLinks(unitInfo),
       'highlightJsPath': migrationInfo.highlightJsPath(unitInfo),
       'highlightStylePath': migrationInfo.highlightStylePath(unitInfo),
       'navContent': _computeNavigationContent(unitInfo),
+      'generationDate': migrationInfo.migrationDate,
     };
     mustacheContext['units'].add({
       'path': unitInfo.path,
@@ -269,12 +301,12 @@
       if (regionLength > 0) {
         int openOffset = mapper.map(region.offset);
         String openInsertion = openInsertions[openOffset] ?? '';
-        openInsertion = '<a id="o${region.offset}">$openInsertion';
+        openInsertion = '<span id="o${region.offset}">$openInsertion';
         openInsertions[openOffset] = openInsertion;
 
         int closeOffset = openOffset + regionLength;
         String closeInsertion = closeInsertions[closeOffset] ?? '';
-        closeInsertion = '$closeInsertion</a>';
+        closeInsertion = '$closeInsertion</span>';
         closeInsertions[closeOffset] = closeInsertion;
       }
     }
@@ -367,24 +399,46 @@
           '${content.substring(offset, offset + length)}'
           '<span class="tooltip">'
           '<p>${region.explanation}</p>');
+      //
+      // Write out any details.
+      //
       if (region.details.isNotEmpty) {
         regions.write('<ul>');
-      }
-      for (var detail in region.details) {
-        regions.write('<li>');
-
-        if (detail.target != null) {
-          regions.write('<a href="${_uriForTarget(detail.target, unitDir)}">');
+        for (var detail in region.details) {
+          regions.write('<li>');
+          if (detail.target != null) {
+            String targetUri = _uriForTarget(detail.target, unitDir);
+            regions.write('<a href="$targetUri">');
+          }
+          writeSplitLines(detail.description);
+          if (detail.target != null) {
+            regions.write('</a>');
+          }
+          regions.write('</li>');
         }
-        writeSplitLines(detail.description);
-        if (detail.target != null) {
-          regions.write('</a>');
-        }
-        regions.write('</li>');
-      }
-      if (region.details.isNotEmpty) {
         regions.write('</ul>');
       }
+      //
+      // Write out any edits.
+      //
+      if (supportsIncrementalWorkflow && region.edits.isNotEmpty) {
+        for (EditDetail edit in region.edits) {
+          int offset = edit.offset;
+          String targetUri = Uri(
+              scheme: 'http',
+              path: pathContext.basename(unitInfo.path),
+              queryParameters: {
+                'offset': offset.toString(),
+                'end': (offset + edit.length).toString(),
+                'replacement': edit.replacement
+              }).toString();
+          regions.write('<p>');
+          regions.write('<a href="$targetUri">');
+          regions.write(edit.description);
+          regions.write('</a>');
+          regions.write('</p>');
+        }
+      }
       regions.write('</span></span>');
     }
     if (previousOffset < content.length) {
@@ -433,7 +487,10 @@
   /// The filesystem root used to create relative paths for each unit.
   final String includedRoot;
 
-  MigrationInfo(this.units, this.unitMap, this.pathContext, this.includedRoot);
+  final String migrationDate;
+
+  MigrationInfo(this.units, this.unitMap, this.pathContext, this.includedRoot)
+      : migrationDate = DateTime.now().toString();
 
   /// The path to the highlight.js script, relative to [unitInfo].
   String highlightJsPath(UnitInfo unitInfo) {
@@ -460,16 +517,22 @@
   }
 
   /// Generate mustache context for unit links, for navigation in the
-  /// instrumentation document for [thisUnit].
-  List<Map<String, Object>> unitLinks(UnitInfo thisUnit) {
-    return [
-      for (var unit in units)
-        {
-          'name': _computeName(unit),
-          'isLink': unit != thisUnit,
-          if (unit != thisUnit) 'href': _pathTo(target: unit, source: thisUnit)
-        }
-    ];
+  /// instrumentation document for [currentUnit].
+  List<Map<String, Object>> unitLinks(UnitInfo currentUnit) {
+    List<Map<String, Object>> links = [];
+    for (UnitInfo unit in units) {
+      int count = unit.fixRegions.length;
+      String modificationCount =
+          count == 1 ? '(1 modification)' : '($count modifications)';
+      bool isNotCurrent = unit != currentUnit;
+      links.add({
+        'name': _computeName(unit),
+        'modificationCount': modificationCount,
+        'isLink': isNotCurrent,
+        if (isNotCurrent) 'href': _pathTo(target: unit, source: currentUnit)
+      });
+    }
+    return links;
   }
 
   /// Return the path to [unit] from [includedRoot], to be used as a display
diff --git a/pkg/analysis_server/lib/src/edit/nnbd_migration/migration_info.dart b/pkg/analysis_server/lib/src/edit/nnbd_migration/migration_info.dart
index 3738015..d608c07 100644
--- a/pkg/analysis_server/lib/src/edit/nnbd_migration/migration_info.dart
+++ b/pkg/analysis_server/lib/src/edit/nnbd_migration/migration_info.dart
@@ -5,6 +5,25 @@
 import 'package:analysis_server/src/edit/nnbd_migration/offset_mapper.dart';
 import 'package:analyzer/src/generated/utilities_general.dart';
 
+/// A description of an edit that can be applied before rerunning the migration
+/// in order to improve the migration results.
+class EditDetail {
+  /// A description of the edit that will be performed.
+  final String description;
+
+  /// The offset of the range to be replaced.
+  final int offset;
+
+  /// The length of the range to be replaced.
+  final int length;
+
+  /// The string with which the range will be replaced.
+  final String replacement;
+
+  /// Initialize a newly created detail.
+  EditDetail(this.description, this.offset, this.length, this.replacement);
+}
+
 /// The migration information associated with a single library.
 class LibraryInfo {
   /// The information about the units in the library. The information about the
@@ -76,6 +95,9 @@
 /// A description of an explanation associated with a region of code that was
 /// modified.
 class RegionInfo {
+  /// Type type of region.
+  final RegionType regionType;
+
   /// The offset to the beginning of the region.
   final int offset;
 
@@ -88,16 +110,20 @@
   /// Details that further explain why a change was made.
   final List<RegionDetail> details;
 
-  /// Type type of region.
-  final RegionType regionType;
+  /// A list of the edits that are related to this range.
+  List<EditDetail> edits;
 
   /// Initialize a newly created region.
-  RegionInfo(this.offset, this.length, this.explanation, this.details,
-      this.regionType);
+  RegionInfo(
+      this.regionType, this.offset, this.length, this.explanation, this.details,
+      {this.edits = const []});
 }
 
 /// Different types of regions that are called out.
 enum RegionType {
+  // TODO(brianwilkerson) 'fix' indicates whether the code was modified, while
+  //  'nonNullableType' indicates why the code wasn't modified. It would be good
+  //  to be consistent between the "whether" and "why" descriptions.
   /// This is a region of code that was fixed (changed) in migration.
   fix,
 
diff --git a/pkg/analysis_server/lib/src/edit/preview/dart_file_page.dart b/pkg/analysis_server/lib/src/edit/preview/dart_file_page.dart
index 84df2c7..bf099ba 100644
--- a/pkg/analysis_server/lib/src/edit/preview/dart_file_page.dart
+++ b/pkg/analysis_server/lib/src/edit/preview/dart_file_page.dart
@@ -51,6 +51,9 @@
   String get includedRoot => wrappedInfo.includedRoot;
 
   @override
+  String get migrationDate => wrappedInfo.migrationDate;
+
+  @override
   Context get pathContext => wrappedInfo.pathContext;
 
   @override
@@ -70,15 +73,21 @@
   }
 
   @override
-  List<Map<String, Object>> unitLinks(UnitInfo thisUnit) {
-    return [
-      for (var unit in units)
-        {
-          'name': _computeName(unit),
-          'isLink': unit != thisUnit,
-          if (unit != thisUnit) 'href': _pathTo(target: unit, source: thisUnit)
-        }
-    ];
+  List<Map<String, Object>> unitLinks(UnitInfo currentUnit) {
+    List<Map<String, Object>> links = [];
+    for (UnitInfo unit in units) {
+      int count = unit.fixRegions.length;
+      String modificationCount =
+          count == 1 ? '(1 modification)' : '($count modifications)';
+      bool isNotCurrent = unit != currentUnit;
+      links.add({
+        'name': _computeName(unit),
+        'modificationCount': modificationCount,
+        'isLink': isNotCurrent,
+        if (isNotCurrent) 'href': _pathTo(target: unit, source: currentUnit)
+      });
+    }
+    return links;
   }
 
   /// Return the path to [unit] from [includedRoot], to be used as a display
diff --git a/pkg/analysis_server/lib/src/edit/preview/index_file_page.dart b/pkg/analysis_server/lib/src/edit/preview/index_file_page.dart
new file mode 100644
index 0000000..d3e8fa6
--- /dev/null
+++ b/pkg/analysis_server/lib/src/edit/preview/index_file_page.dart
@@ -0,0 +1,25 @@
+// Copyright (c) 2019, 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:analysis_server/src/edit/nnbd_migration/index_renderer.dart';
+import 'package:analysis_server/src/edit/preview/preview_page.dart';
+import 'package:analysis_server/src/edit/preview/preview_site.dart';
+
+/// The page that is displayed when the root of the included path is requested.
+class IndexFilePage extends PreviewPage {
+  /// Initialize a newly created index file page within the given [site].
+  IndexFilePage(PreviewSite site)
+      : super(site, site.migrationInfo.includedRoot);
+
+  @override
+  void generateBody(Map<String, String> params) {
+    throw UnsupportedError('generateBody');
+  }
+
+  @override
+  Future<void> generatePage(Map<String, String> params) async {
+    IndexRenderer renderer = IndexRenderer(site.migrationInfo);
+    buf.write(renderer.render());
+  }
+}
diff --git a/pkg/analysis_server/lib/src/edit/preview/preview_site.dart b/pkg/analysis_server/lib/src/edit/preview/preview_site.dart
index 2f3f778..dfee4ac 100644
--- a/pkg/analysis_server/lib/src/edit/preview/preview_site.dart
+++ b/pkg/analysis_server/lib/src/edit/preview/preview_site.dart
@@ -13,6 +13,7 @@
 import 'package:analysis_server/src/edit/preview/highlight_css_page.dart';
 import 'package:analysis_server/src/edit/preview/highlight_js_page.dart';
 import 'package:analysis_server/src/edit/preview/http_preview_server.dart';
+import 'package:analysis_server/src/edit/preview/index_file_page.dart';
 import 'package:analysis_server/src/edit/preview/not_found_page.dart';
 import 'package:analysis_server/src/status/pages.dart';
 import 'package:analyzer/file_system/file_system.dart';
@@ -83,12 +84,19 @@
 
   @override
   Future<void> handleGetRequest(HttpRequest request) async {
-    String path = request.uri.path;
+    Uri uri = request.uri;
+    if (uri.query.isNotEmpty) {
+      performEdit(uri);
+      performMigration();
+    }
+    String path = uri.path;
     try {
       if (path == highlightCssPagePath) {
         return respond(request, HighlightCssPage(this));
       } else if (path == highlightJSPagePath) {
         return respond(request, HighlightJSPage(this));
+      } else if (path == migrationInfo.includedRoot) {
+        return respond(request, IndexFilePage(this));
       }
       UnitInfo unitInfo = unitInfoMap[path];
       if (unitInfo != null) {
@@ -111,6 +119,28 @@
     }
   }
 
+  /// Perform the edit indicated by the [uri].
+  void performEdit(Uri uri) {
+    // We might want to allow edits to files other than the file to be displayed
+    // after the edit is performed, in which case we'll need to encode the file
+    // path as a query parameter.
+    Map<String, String> params = uri.queryParameters;
+    String path = uri.path;
+    int offset = int.parse(params['offset']);
+    int end = int.parse(params['end']);
+    String replacement = params['replacement'];
+    File file = pathMapper.provider.getFile(path);
+    String oldContent = file.readAsStringSync();
+    String newContent = oldContent.replaceRange(offset, end, replacement);
+    file.writeAsStringSync(newContent);
+  }
+
+  /// Perform the migration again and update this site to serve up the results
+  /// of the new migration.
+  void performMigration() {
+    // TODO(brianwilkerson) Implement this.
+  }
+
   @override
   Future<void> respond(HttpRequest request, Page page,
       [int code = HttpStatus.ok]) async {
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
index f7af4f1..f2e16e3 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_completion.dart
@@ -136,15 +136,18 @@
         new CompletionRequestImpl(unit, offset, performance);
 
     Set<ElementKind> includedElementKinds;
+    Set<String> includedElementNames;
     List<IncludedSuggestionRelevanceTag> includedSuggestionRelevanceTags;
     if (includeSuggestionSets) {
       includedElementKinds = Set<ElementKind>();
+      includedElementNames = Set<String>();
       includedSuggestionRelevanceTags = <IncludedSuggestionRelevanceTag>[];
     }
 
     try {
       CompletionContributor contributor = new DartCompletionManager(
         includedElementKinds: includedElementKinds,
+        includedElementNames: includedElementNames,
         includedSuggestionRelevanceTags: includedSuggestionRelevanceTags,
       );
       final suggestions =
@@ -167,7 +170,6 @@
 
       // Now compute items in suggestion sets.
       List<IncludedSuggestionSet> includedSuggestionSets = [];
-      Set<String> includedElementNames = Set<String>();
       if (includedElementKinds != null && unit != null) {
         computeIncludedSetList(
           server.declarationsTracker,
diff --git a/pkg/analysis_server/lib/src/server/crash_reporting.dart b/pkg/analysis_server/lib/src/server/crash_reporting.dart
index 498a45b..44e4c66 100644
--- a/pkg/analysis_server/lib/src/server/crash_reporting.dart
+++ b/pkg/analysis_server/lib/src/server/crash_reporting.dart
@@ -2,6 +2,7 @@
 // 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/exception/exception.dart';
 import 'package:analyzer/instrumentation/noop_service.dart';
 import 'package:analyzer/instrumentation/plugin_data.dart';
 import 'package:telemetry/crash_reporting.dart';
@@ -13,6 +14,14 @@
 
   @override
   void logException(dynamic exception, [StackTrace stackTrace]) {
+    if (exception is CaughtException) {
+      // Get the root CaughtException, which matters most for debugging.
+      exception = exception.rootCaughtException;
+      // Report the root exception stack trace.
+      stackTrace = exception.stackTrace;
+      // Report the dynamic exception object that the CaughtException holds.
+      exception = exception.exception;
+    }
     reporter
         .sendReport(exception, stackTrace: stackTrace ?? StackTrace.current)
         .catchError((error) {
diff --git a/pkg/analysis_server/lib/src/server/driver.dart b/pkg/analysis_server/lib/src/server/driver.dart
index 4714d6e..85cddcd 100644
--- a/pkg/analysis_server/lib/src/server/driver.dart
+++ b/pkg/analysis_server/lib/src/server/driver.dart
@@ -653,13 +653,15 @@
     // server was configured to load a language model on disk.
     CompletionRanking.instance =
         CompletionRanking(analysisServerOptions.completionModelFolder);
-    CompletionRanking.instance.start().catchError((error, stackTrace) {
+    CompletionRanking.instance.start().catchError((exception, stackTrace) {
       // Disable smart ranking if model startup fails.
       analysisServerOptions.completionModelFolder = null;
+      // TODO(brianwilkerson) Shutdown the isolates that have already been
+      //  started.
       CompletionRanking.instance = null;
       AnalysisEngine.instance.instrumentationService.logException(
           CaughtException.withMessage(
-              'Failed to start ranking model isolate', error, stackTrace));
+              'Failed to start ranking model isolate', exception, stackTrace));
     });
   }
 
diff --git a/pkg/analysis_server/lib/src/server/error_notifier.dart b/pkg/analysis_server/lib/src/server/error_notifier.dart
index 57bd646..0547cd4 100644
--- a/pkg/analysis_server/lib/src/server/error_notifier.dart
+++ b/pkg/analysis_server/lib/src/server/error_notifier.dart
@@ -16,7 +16,12 @@
 
     var message = 'Internal error';
     if (exception is CaughtException && exception.message != null) {
-      message = exception.message;
+      // TODO(mfairhurst): Use the outermost exception once crash reporting is
+      // fixed and this becomes purely user-facing.
+      exception = exception.rootCaughtException;
+      // TODO(mfairhurst): Use the outermost message rather than the innermost
+      // exception as its own message.
+      message = exception.exception;
     }
 
     server.sendServerErrorNotification(message, exception, stackTrace,
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart b/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
index 626caf1..11b9e48 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
@@ -39,6 +39,7 @@
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/exception/exception.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/src/dart/analysis/driver_based_analysis_context.dart';
 import 'package:analyzer/src/generated/engine.dart';
@@ -84,8 +85,6 @@
   @override
   Future<List<CompletionSuggestion>> computeSuggestions(
       CompletionRequest request) async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     request.checkAborted();
     if (!AnalysisEngine.isDartFileName(request.result.path)) {
       return const <CompletionSuggestion>[];
@@ -185,16 +184,30 @@
     List<CompletionSuggestion> suggestions = suggestionMap.values.toList();
     const SORT_TAG = 'DartCompletionManager - sort';
     performance.logStartTime(SORT_TAG);
-    await contributionSorter.sort(dartRequest, suggestions);
     if (ranking != null) {
       request.checkAborted();
-      suggestions = await ranking.rerank(
-          probabilityFuture,
-          suggestions,
-          includedElementNames,
-          includedSuggestionRelevanceTags,
-          dartRequest,
-          request.result.unit.featureSet);
+      try {
+        suggestions = await ranking.rerank(
+            probabilityFuture,
+            suggestions,
+            includedElementNames,
+            includedSuggestionRelevanceTags,
+            dartRequest,
+            request.result.unit.featureSet);
+      } catch (exception, stackTrace) {
+        // TODO(brianwilkerson) Shutdown the isolates that have already been
+        //  started.
+        // Disable smart ranking if prediction fails.
+        CompletionRanking.instance = null;
+        AnalysisEngine.instance.instrumentationService.logException(
+            CaughtException.withMessage(
+                'Failed to rerank completion suggestions',
+                exception,
+                stackTrace));
+        await contributionSorter.sort(dartRequest, suggestions);
+      }
+    } else {
+      await contributionSorter.sort(dartRequest, suggestions);
     }
     performance.logElapseTime(SORT_TAG);
     request.checkAborted();
@@ -450,8 +463,6 @@
    * if the completion request has been aborted.
    */
   static Future<DartCompletionRequest> from(CompletionRequest request) async {
-    // TODO(brianwilkerson) Determine whether this await is necessary.
-    await null;
     request.checkAborted();
     CompletionPerformance performance =
         (request as CompletionRequestImpl).performance;
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/extension_member_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/extension_member_contributor.dart
index f2815f2..4b21997 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/extension_member_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/extension_member_contributor.dart
@@ -9,10 +9,12 @@
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/dart/element/type_system.dart';
 import 'package:analyzer/src/dart/element/type_algebra.dart';
 import 'package:analyzer/src/dart/resolver/scope.dart';
-import 'package:analyzer/src/generated/resolver.dart';
-import 'package:analyzer/src/generated/type_system.dart';
+import 'package:analyzer/src/generated/resolver.dart'
+    show GenericInferrer, LibraryScope, TypeProvider;
+import 'package:analyzer/src/generated/type_system.dart' show GenericInferrer;
 
 import '../../../protocol_server.dart' show CompletionSuggestion;
 
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/field_formal_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/field_formal_contributor.dart
index 2b1de7a..cc3878a 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/field_formal_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/field_formal_contributor.dart
@@ -25,17 +25,14 @@
       return const <CompletionSuggestion>[];
     }
 
-    // If this is a constructor declaration
-    // then compute fields already referenced
-    ConstructorDeclaration constructorDecl =
-        node.thisOrAncestorOfType<ConstructorDeclaration>();
-    if (constructorDecl == null) {
+    ConstructorDeclaration constructor = node.thisOrAncestorOfType();
+    if (constructor == null) {
       return const <CompletionSuggestion>[];
     }
 
     // Compute the list of fields already referenced in the constructor
     List<String> referencedFields = new List<String>();
-    for (FormalParameter param in constructorDecl.parameters.parameters) {
+    for (FormalParameter param in constructor.parameters.parameters) {
       if (param is DefaultFormalParameter &&
           param.parameter is FieldFormalParameter) {
         param = (param as DefaultFormalParameter).parameter;
@@ -51,11 +48,14 @@
       }
     }
 
+    ClassDeclaration class_ = constructor.thisOrAncestorOfType();
+    if (class_ == null) {
+      return const <CompletionSuggestion>[];
+    }
+
     // Add suggestions for fields that are not already referenced
-    ClassDeclaration classDecl =
-        constructorDecl.thisOrAncestorOfType<ClassDeclaration>();
     List<CompletionSuggestion> suggestions = <CompletionSuggestion>[];
-    for (ClassMember member in classDecl.members) {
+    for (ClassMember member in class_.members) {
       if (member is FieldDeclaration && !member.isStatic) {
         for (VariableDeclaration varDecl in member.fields.variables) {
           SimpleIdentifier fieldId = varDecl.name;
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/override_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/override_contributor.dart
index ae865b9..01c9e0e 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/override_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/override_contributor.dart
@@ -39,7 +39,7 @@
       return const <CompletionSuggestion>[];
     }
 
-    var inheritance = new InheritanceManager3(request.result.typeSystem);
+    var inheritance = new InheritanceManager3();
 
     // Generate a collection of inherited members
     var classElem = classDecl.declaredElement;
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/type_member_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/type_member_contributor.dart
index 9b4e58a..7f0ace0 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/type_member_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/type_member_contributor.dart
@@ -184,7 +184,7 @@
   @override
   void declaredGenericTypeAlias(GenericTypeAlias declaration) {
     if (declaration.name.name == targetName) {
-      TypeAnnotation typeName = declaration.functionType.returnType;
+      TypeAnnotation typeName = declaration.functionType?.returnType;
       if (typeName != null) {
         typeFound = typeName.type;
       }
diff --git a/pkg/analysis_server/lib/src/services/completion/postfix/postfix_completion.dart b/pkg/analysis_server/lib/src/services/completion/postfix/postfix_completion.dart
index c93417d..3657667 100644
--- a/pkg/analysis_server/lib/src/services/completion/postfix/postfix_completion.dart
+++ b/pkg/analysis_server/lib/src/services/completion/postfix/postfix_completion.dart
@@ -11,9 +11,10 @@
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/dart/element/type_system.dart';
 import 'package:analyzer/src/dart/ast/utilities.dart';
 import 'package:analyzer/src/generated/java_core.dart';
-import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart';
 import 'package:analyzer_plugin/utilities/range_factory.dart';
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index 1f5f28c..b2f83d2 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -26,6 +26,7 @@
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/nullability_suffix.dart';
 import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/dart/element/type_system.dart';
 import 'package:analyzer/error/error.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/src/dart/analysis/session_helper.dart';
@@ -39,7 +40,7 @@
 import 'package:analyzer/src/generated/error_verifier.dart';
 import 'package:analyzer/src/generated/java_core.dart';
 import 'package:analyzer/src/generated/parser.dart';
-import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/hint/sdk_constraint_extractor.dart';
 import 'package:analyzer_plugin/protocol/protocol_common.dart'
@@ -2796,6 +2797,10 @@
         if (alreadyImportedWithPrefix.contains(declaration.path)) {
           continue;
         }
+        // Check that the import doesn't end with '.template.dart'
+        if (declaration.uri.path.endsWith('.template.dart')) {
+          continue;
+        }
         // Compute the fix kind.
         FixKind fixKind;
         if (declaration.uri.isScheme('dart')) {
diff --git a/pkg/analysis_server/lib/src/services/flutter/widget_descriptions.dart b/pkg/analysis_server/lib/src/services/flutter/widget_descriptions.dart
index 85a0e5e..35bcdd0 100644
--- a/pkg/analysis_server/lib/src/services/flutter/widget_descriptions.dart
+++ b/pkg/analysis_server/lib/src/services/flutter/widget_descriptions.dart
@@ -13,6 +13,7 @@
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/dart/analysis/session_helper.dart';
 import 'package:analyzer/src/dart/ast/utilities.dart';
+import 'package:dart_style/dart_style.dart';
 
 /// The result of [WidgetDescriptions.setPropertyValue] invocation.
 class SetPropertyValueResult {
@@ -77,8 +78,15 @@
       var change = await property.removeValue();
       return SetPropertyValueResult._(change: change);
     } else {
-      var change = await property.changeValue(value);
-      return SetPropertyValueResult._(change: change);
+      try {
+        var change = await property.changeValue(value);
+        return SetPropertyValueResult._(change: change);
+      } on FormatterException {
+        return SetPropertyValueResult._(
+          errorCode: protocol.RequestErrorCode
+              .FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_EXPRESSION,
+        );
+      }
     }
   }
 
diff --git a/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart b/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
index 74d6eb3..dc4ebf4 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
@@ -24,13 +24,13 @@
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/dart/element/type_system.dart';
 import 'package:analyzer/src/dart/analysis/session_helper.dart';
 import 'package:analyzer/src/dart/ast/utilities.dart';
 import 'package:analyzer/src/generated/java_core.dart';
-import 'package:analyzer/src/generated/resolver.dart' show ExitDetector;
-import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/resolver.dart'
+    show ExitDetector, TypeProvider;
 import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/generated/type_system.dart';
 import 'package:analyzer_plugin/utilities/range_factory.dart';
 
 const String _TOKEN_SEPARATOR = '\uFFFF';
@@ -1375,7 +1375,7 @@
       if (returnType is InterfaceType && type is InterfaceType) {
         returnType = InterfaceType.getSmartLeastUpperBound(returnType, type);
       } else {
-        returnType = typeSystem.getLeastUpperBound(returnType, type);
+        returnType = typeSystem.leastUpperBound(returnType, type);
       }
     }
   }
diff --git a/pkg/analysis_server/lib/src/utilities/mocks.dart b/pkg/analysis_server/lib/src/utilities/mocks.dart
new file mode 100644
index 0000000..ccc91a6
--- /dev/null
+++ b/pkg/analysis_server/lib/src/utilities/mocks.dart
@@ -0,0 +1,248 @@
+// Copyright (c) 2017, 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:async';
+
+import 'package:analysis_server/protocol/protocol.dart';
+import 'package:analysis_server/src/analysis_server.dart';
+import 'package:analysis_server/src/channel/channel.dart';
+import 'package:analysis_server/src/plugin/notification_manager.dart';
+import 'package:analysis_server/src/plugin/plugin_manager.dart';
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/instrumentation/instrumentation.dart';
+import 'package:analyzer/src/context/context_root.dart' as analyzer;
+import 'package:analyzer_plugin/protocol/protocol.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:test/test.dart';
+import 'package:watcher/watcher.dart';
+
+/// A mock [ServerCommunicationChannel] for testing [AnalysisServer].
+class MockServerChannel implements ServerCommunicationChannel {
+  StreamController<Request> requestController = new StreamController<Request>();
+  StreamController<Response> responseController =
+      new StreamController<Response>.broadcast();
+  StreamController<Notification> notificationController =
+      new StreamController<Notification>(sync: true);
+  Completer<Response> errorCompleter;
+
+  List<Response> responsesReceived = [];
+  List<Notification> notificationsReceived = [];
+
+  bool _closed = false;
+
+  String name;
+
+  MockServerChannel();
+
+  @override
+  void close() {
+    _closed = true;
+  }
+
+  void expectMsgCount({responseCount = 0, notificationCount = 0}) {
+    expect(responsesReceived, hasLength(responseCount));
+    expect(notificationsReceived, hasLength(notificationCount));
+  }
+
+  @override
+  void listen(void onRequest(Request request),
+      {Function onError, void onDone()}) {
+    requestController.stream
+        .listen(onRequest, onError: onError, onDone: onDone);
+  }
+
+  @override
+  void sendNotification(Notification notification) {
+    // Don't deliver notifications after the connection is closed.
+    if (_closed) {
+      return;
+    }
+    notificationsReceived.add(notification);
+    if (errorCompleter != null && notification.event == 'server.error') {
+      print(
+          '[server.error] test: $name message: ${notification.params['message']}');
+      errorCompleter.completeError(
+          new ServerError(notification.params['message']),
+          new StackTrace.fromString(notification.params['stackTrace']));
+    }
+    // Wrap send notification in future to simulate websocket
+    // TODO(scheglov) ask Dan why and decide what to do
+//    new Future(() => notificationController.add(notification));
+    notificationController.add(notification);
+  }
+
+  /// Send the given [request] to the server and return a future that will
+  /// complete when a response associated with the [request] has been received.
+  /// The value of the future will be the received response. If [throwOnError] is
+  /// `true` (the default) then the returned future will throw an exception if a
+  /// server error is reported before the response has been received.
+  Future<Response> sendRequest(Request request, {bool throwOnError = true}) {
+    // TODO(brianwilkerson) Attempt to remove the `throwOnError` parameter and
+    // have the default behavior be the only behavior.
+    // No further requests should be sent after the connection is closed.
+    if (_closed) {
+      throw new Exception('sendRequest after connection closed');
+    }
+    // Wrap send request in future to simulate WebSocket.
+    new Future(() => requestController.add(request));
+    return waitForResponse(request, throwOnError: throwOnError);
+  }
+
+  @override
+  void sendResponse(Response response) {
+    // Don't deliver responses after the connection is closed.
+    if (_closed) {
+      return;
+    }
+    responsesReceived.add(response);
+    // Wrap send response in future to simulate WebSocket.
+    new Future(() => responseController.add(response));
+  }
+
+  /// Return a future that will complete when a response associated with the
+  /// given [request] has been received. The value of the future will be the
+  /// received response. If [throwOnError] is `true` (the default) then the
+  /// returned future will throw an exception if a server error is reported
+  /// before the response has been received.
+  ///
+  /// Unlike [sendRequest], this method assumes that the [request] has already
+  /// been sent to the server.
+  Future<Response> waitForResponse(Request request,
+      {bool throwOnError = true}) {
+    // TODO(brianwilkerson) Attempt to remove the `throwOnError` parameter and
+    // have the default behavior be the only behavior.
+    String id = request.id;
+    Future<Response> response =
+        responseController.stream.firstWhere((response) => response.id == id);
+    if (throwOnError) {
+      errorCompleter = new Completer<Response>();
+      try {
+        return Future.any([response, errorCompleter.future]);
+      } finally {
+        errorCompleter = null;
+      }
+    }
+    return response;
+  }
+}
+
+class ServerError implements Exception {
+  final message;
+
+  ServerError(this.message);
+
+  String toString() {
+    return "Server Error: $message";
+  }
+}
+
+/// A plugin manager that simulates broadcasting requests to plugins by
+/// hard-coding the responses.
+class TestPluginManager implements PluginManager {
+  plugin.AnalysisSetPriorityFilesParams analysisSetPriorityFilesParams;
+  plugin.AnalysisSetSubscriptionsParams analysisSetSubscriptionsParams;
+  plugin.AnalysisUpdateContentParams analysisUpdateContentParams;
+  plugin.RequestParams broadcastedRequest;
+  Map<PluginInfo, Future<plugin.Response>> broadcastResults;
+
+  @override
+  String get byteStorePath {
+    fail('Unexpected invocation of byteStorePath');
+  }
+
+  @override
+  InstrumentationService get instrumentationService {
+    fail('Unexpected invocation of instrumentationService');
+  }
+
+  @override
+  NotificationManager get notificationManager {
+    fail('Unexpected invocation of notificationManager');
+  }
+
+  @override
+  List<PluginInfo> get plugins {
+    fail('Unexpected invocation of plugins');
+  }
+
+  @override
+  ResourceProvider get resourceProvider {
+    fail('Unexpected invocation of resourceProvider');
+  }
+
+  @override
+  String get sdkPath {
+    fail('Unexpected invocation of sdkPath');
+  }
+
+  @override
+  Future<void> addPluginToContextRoot(
+      analyzer.ContextRoot contextRoot, String path) async {
+    fail('Unexpected invocation of addPluginToContextRoot');
+  }
+
+  @override
+  Map<PluginInfo, Future<plugin.Response>> broadcastRequest(
+      plugin.RequestParams params,
+      {analyzer.ContextRoot contextRoot}) {
+    broadcastedRequest = params;
+    return broadcastResults ?? <PluginInfo, Future<plugin.Response>>{};
+  }
+
+  @override
+  Future<List<Future<plugin.Response>>> broadcastWatchEvent(
+      WatchEvent watchEvent) async {
+    return <Future<plugin.Response>>[];
+  }
+
+  @override
+  List<String> pathsFor(String pluginPath) {
+    fail('Unexpected invocation of pathsFor');
+  }
+
+  @override
+  List<PluginInfo> pluginsForContextRoot(analyzer.ContextRoot contextRoot) {
+    fail('Unexpected invocation of pluginsForContextRoot');
+  }
+
+  @override
+  void recordPluginFailure(String hostPackageName, String message) {
+    fail('Unexpected invocation of recordPluginFailure');
+  }
+
+  @override
+  void removedContextRoot(analyzer.ContextRoot contextRoot) {
+    fail('Unexpected invocation of removedContextRoot');
+  }
+
+  @override
+  Future<void> restartPlugins() async {
+    // Nothing to restart.
+    return null;
+  }
+
+  @override
+  void setAnalysisSetPriorityFilesParams(
+      plugin.AnalysisSetPriorityFilesParams params) {
+    analysisSetPriorityFilesParams = params;
+  }
+
+  @override
+  void setAnalysisSetSubscriptionsParams(
+      plugin.AnalysisSetSubscriptionsParams params) {
+    analysisSetSubscriptionsParams = params;
+  }
+
+  @override
+  void setAnalysisUpdateContentParams(
+      plugin.AnalysisUpdateContentParams params) {
+    analysisUpdateContentParams = params;
+  }
+
+  @override
+  Future<List<void>> stopAll() async {
+    fail('Unexpected invocation of stopAll');
+  }
+}
diff --git a/pkg/analysis_server/lib/src/utilities/request_statistics.dart b/pkg/analysis_server/lib/src/utilities/request_statistics.dart
index b9e3b4b..d76c1bb 100644
--- a/pkg/analysis_server/lib/src/utilities/request_statistics.dart
+++ b/pkg/analysis_server/lib/src/utilities/request_statistics.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'dart:convert';
+import 'dart:io';
 
 import 'package:analysis_server/protocol/protocol.dart';
 import 'package:analysis_server/protocol/protocol_generated.dart';
@@ -12,6 +13,8 @@
 ///
 /// All [DateTime] are local, not UTC.
 class RequestStatisticsHelper {
+  final String _sdkVersion = Platform.version.split(' ').first;
+
   final Map<String, _RequestStatistics> _statisticsMap = {};
 
   /// The [StringSink] to which performance logger should copy its output.
@@ -167,6 +170,7 @@
           'time': DateTime.now().millisecondsSinceEpoch,
           'kind': kind.toJson(),
           'data': data,
+          'sdkVersion': _sdkVersion,
         },
       ),
     );
diff --git a/pkg/analysis_server/lib/src/watch_manager.dart b/pkg/analysis_server/lib/src/watch_manager.dart
deleted file mode 100644
index f7bd8c9..0000000
--- a/pkg/analysis_server/lib/src/watch_manager.dart
+++ /dev/null
@@ -1,285 +0,0 @@
-// Copyright (c) 2015, 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:async';
-import 'dart:collection';
-import 'dart:core';
-
-import 'package:analyzer/file_system/file_system.dart';
-import 'package:watcher/watcher.dart';
-
-/**
- * A function called when a watch [event] associated with a watched resource is
- * received. The list of [tokens] will contain all of the tokens associated with
- * folders containing (or the same as) the watched resource.
- */
-typedef void HandleWatchEvent<T>(WatchEvent event, List<T> tokens);
-
-/**
- * An object that manages a collections of folders that need to be watched in
- * order to ensure that we are watching the minimum number of folders.
- *
- * Each folder can be watched multiple times. In order to differentiate between
- * the watch requests, each watch request has a *token* associated with it. The
- * tokens that are used must correctly implement both [==] and [hashCode].
- */
-class WatchManager<T> {
-  /**
-   * The resource provider used to convert paths to resources.
-   */
-  final ResourceProvider provider;
-
-  /**
-   * The function that is invoked when a watch event is received.
-   */
-  final HandleWatchEvent<T> handleWatchEvent;
-
-  /**
-   * A node representing the (conceptual) root of all other folders.
-   */
-  final WatchNode<T> rootNode = new WatchNode<T>(null);
-
-  /**
-   * A table mapping the folders that are being watched to the nodes
-   * representing those folders.
-   */
-  final Map<Folder, WatchNode<T>> _watchedFolders =
-      new HashMap<Folder, WatchNode<T>>();
-
-  /**
-   * Initialize a newly created watch manager to use the resource [provider] to
-   * convert file paths to resources and to call the [handleWatchEvent] function
-   * to notify the owner of the manager when resources have been changed.
-   */
-  WatchManager(this.provider, this.handleWatchEvent);
-
-  /**
-   * Record the fact that we are now watching the given [folder], and associate
-   * that folder with the given [token]. If the folder is already being watched
-   * and is already associated with the token, then this request is effectively
-   * ignored.
-   */
-  void addFolder(Folder folder, T token) {
-    WatchNode<T> folderNode = _watchedFolders[folder];
-    //
-    // If the folder was already being watched, just record the new token.
-    //
-    if (folderNode != null) {
-      folderNode.tokens.add(token);
-      return;
-    }
-    //
-    // Otherwise, add the folder to the tree.
-    //
-    folderNode = new WatchNode<T>(folder);
-    _watchedFolders[folder] = folderNode;
-    folderNode.tokens.add(token);
-    WatchNode<T> parentNode = rootNode.insert(folderNode);
-    //
-    // If we are not watching a folder that contains the folder, then create a
-    // subscription for it.
-    //
-    if (parentNode == rootNode) {
-      folderNode.subscription = folder.changes.listen(_handleWatchEvent);
-      //
-      // Any nodes that became children of the newly added folder would have
-      // been top-level folders and would have been watched. We need to cancel
-      // their subscriptions.
-      //
-      for (WatchNode<T> childNode in folderNode.children) {
-        assert(childNode.subscription != null);
-        if (childNode.subscription != null) {
-          childNode.subscription.cancel();
-          childNode.subscription = null;
-        }
-      }
-    }
-  }
-
-  /**
-   * Record that we are no longer watching the given [folder] with the given
-   * [token].
-   *
-   * Throws a [StateError] if the folder is not be watched or is not associated
-   * with the given token.
-   */
-  void removeFolder(Folder folder, T token) {
-    WatchNode<T> folderNode = _watchedFolders[folder];
-    if (folderNode == null) {
-      assert(false);
-      return;
-    }
-    Set<T> tokens = folderNode.tokens;
-    if (!tokens.remove(token)) {
-      assert(false);
-    }
-    //
-    // If this was the last token associated with this folder, then remove the
-    // folder from the tree.
-    //
-    if (tokens.isEmpty) {
-      //
-      // If the folder was a top-level folder, then we need to create
-      // subscriptions for all of its children and cancel its subscription.
-      //
-      if (folderNode.subscription != null) {
-        for (WatchNode<T> childNode in folderNode.children) {
-          assert(childNode.subscription == null);
-          childNode.subscription =
-              childNode.folder.changes.listen(_handleWatchEvent);
-        }
-        folderNode.subscription.cancel();
-        folderNode.subscription = null;
-      }
-      folderNode.delete();
-      _watchedFolders.remove(folder);
-    }
-  }
-
-  /**
-   * Dispatch the given event by finding all of the tokens that contain the
-   * resource and invoke the [handleWatchEvent] function.
-   */
-  void _handleWatchEvent(WatchEvent event) {
-    String path = event.path;
-    List<T> tokens = <T>[];
-    WatchNode<T> parent = rootNode.findParent(path);
-    while (parent != rootNode) {
-      tokens.addAll(parent.tokens);
-      parent = parent.parent;
-    }
-    if (tokens.isNotEmpty) {
-      handleWatchEvent(event, tokens);
-    }
-  }
-}
-
-/**
- * The information kept by a [WatchManager] about a single folder that is being
- * watched.
- *
- * Watch nodes form a tree in which one node is a child of another node if the
- * child's folder is contained in the parent's folder and none of the folders
- * between the parent's folder and the child's folder are being watched.
- */
-class WatchNode<T> {
-  /**
-   * The folder for which information is being maintained. This is `null` for
-   * the unique "root" node that maintains references to all of the top-level
-   * folders being watched.
-   */
-  final Folder folder;
-
-  /**
-   * The parent of this node.
-   */
-  WatchNode<T> parent;
-
-  /**
-   * The information for the children of this node.
-   */
-  final List<WatchNode<T>> _children = <WatchNode<T>>[];
-
-  /**
-   * The tokens that were used to register interest in watching this folder.
-   */
-  final Set<T> tokens = new HashSet<T>();
-
-  /**
-   * The subscription being used to watch the folder, or `null` if the folder
-   * is being watched as part of a containing folder (in other words, if the
-   * parent is not the special "root").
-   */
-  StreamSubscription<WatchEvent> subscription;
-
-  /**
-   * Initialize a newly created node to represent the given [folder].
-   */
-  WatchNode(this.folder);
-
-  /**
-   * Return a list containing the children of this node.
-   */
-  Iterable<WatchNode<T>> get children => _children;
-
-  /**
-   * Remove this node from the tree of watched folders.
-   */
-  void delete() {
-    if (parent != null) {
-      parent._removeChild(this);
-      parent = null;
-    }
-  }
-
-  /**
-   * Return the highest node reachable from this node that contains the given
-   * [filePath]. If no other node is found, return this node, even if this node
-   * does not contain the path.
-   */
-  WatchNode<T> findParent(String filePath) {
-    if (_children == null) {
-      return this;
-    }
-    for (WatchNode<T> childNode in _children) {
-      if (childNode.folder.isOrContains(filePath)) {
-        return childNode.findParent(filePath);
-      }
-    }
-    return this;
-  }
-
-  /**
-   * Insert the given [node] into the tree of watched folders, either as a child
-   * of this node or as a descendent of one of this node's children. Return the
-   * immediate parent of the newly added node.
-   */
-  WatchNode<T> insert(WatchNode<T> node) {
-    WatchNode<T> parentNode = findParent(node.folder.path);
-    parentNode._addChild(node, true);
-    return parentNode;
-  }
-
-  @override
-  String toString() => 'WatchNode ('
-      'folder = ${folder == null ? '<root>' : folder.path}, '
-      'tokens = $tokens, '
-      'subscription = ${subscription == null ? 'null' : 'non-null'})';
-
-  /**
-   * Add the given [newChild] as an immediate child of this node.
-   *
-   * If [checkChildren] is `true`, check to see whether any of the previously
-   * existing children of this node should now be children of the new child, and
-   * if so, move them.
-   */
-  void _addChild(WatchNode<T> newChild, bool checkChildren) {
-    if (checkChildren) {
-      Folder folder = newChild.folder;
-      for (int i = _children.length - 1; i >= 0; i--) {
-        WatchNode<T> existingChild = _children[i];
-        if (folder.contains(existingChild.folder.path)) {
-          newChild._addChild(existingChild, false);
-          _children.removeAt(i);
-        }
-      }
-    }
-    newChild.parent = this;
-    _children.add(newChild);
-  }
-
-  /**
-   * Remove the given [node] from the list of children of this node. Any
-   * children of the [node] will become children of this node.
-   */
-  void _removeChild(WatchNode<T> child) {
-    _children.remove(child);
-    Iterable<WatchNode<T>> grandchildren = child.children;
-    for (WatchNode<T> grandchild in grandchildren) {
-      grandchild.parent = this;
-      _children.add(grandchild);
-    }
-    child._children.clear();
-  }
-}
diff --git a/pkg/analysis_server/test/analysis_abstract.dart b/pkg/analysis_server/test/analysis_abstract.dart
index c6b6de9..1562690 100644
--- a/pkg/analysis_server/test/analysis_abstract.dart
+++ b/pkg/analysis_server/test/analysis_abstract.dart
@@ -10,21 +10,15 @@
     hide AnalysisOptions;
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/domain_analysis.dart';
-import 'package:analysis_server/src/plugin/notification_manager.dart';
-import 'package:analysis_server/src/plugin/plugin_manager.dart';
+import 'package:analysis_server/src/utilities/mocks.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/instrumentation/instrumentation.dart';
-import 'package:analyzer/src/context/context_root.dart' as analyzer;
 import 'package:analyzer/src/dart/analysis/driver.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/test_utilities/mock_sdk.dart';
 import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
-import 'package:analyzer_plugin/protocol/protocol.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:test/test.dart';
-import 'package:watcher/watcher.dart';
 
 import 'mocks.dart';
 
@@ -249,114 +243,3 @@
     return serverChannel.sendRequest(request, throwOnError: throwOnError);
   }
 }
-
-/**
- * A plugin manager that simulates broadcasting requests to plugins by
- * hard-coding the responses.
- */
-class TestPluginManager implements PluginManager {
-  plugin.AnalysisSetPriorityFilesParams analysisSetPriorityFilesParams;
-  plugin.AnalysisSetSubscriptionsParams analysisSetSubscriptionsParams;
-  plugin.AnalysisUpdateContentParams analysisUpdateContentParams;
-  plugin.RequestParams broadcastedRequest;
-  Map<PluginInfo, Future<plugin.Response>> broadcastResults;
-
-  @override
-  String get byteStorePath {
-    fail('Unexpected invocation of byteStorePath');
-  }
-
-  @override
-  InstrumentationService get instrumentationService {
-    fail('Unexpected invocation of instrumentationService');
-  }
-
-  @override
-  NotificationManager get notificationManager {
-    fail('Unexpected invocation of notificationManager');
-  }
-
-  @override
-  List<PluginInfo> get plugins {
-    fail('Unexpected invocation of plugins');
-  }
-
-  @override
-  ResourceProvider get resourceProvider {
-    fail('Unexpected invocation of resourceProvider');
-  }
-
-  @override
-  String get sdkPath {
-    fail('Unexpected invocation of sdkPath');
-  }
-
-  @override
-  Future<void> addPluginToContextRoot(
-      analyzer.ContextRoot contextRoot, String path) async {
-    fail('Unexpected invocation of addPluginToContextRoot');
-  }
-
-  @override
-  Map<PluginInfo, Future<plugin.Response>> broadcastRequest(
-      plugin.RequestParams params,
-      {analyzer.ContextRoot contextRoot}) {
-    broadcastedRequest = params;
-    return broadcastResults ?? <PluginInfo, Future<plugin.Response>>{};
-  }
-
-  @override
-  Future<List<Future<plugin.Response>>> broadcastWatchEvent(
-      WatchEvent watchEvent) async {
-    return <Future<plugin.Response>>[];
-  }
-
-  @override
-  List<String> pathsFor(String pluginPath) {
-    fail('Unexpected invocation of pathsFor');
-  }
-
-  @override
-  List<PluginInfo> pluginsForContextRoot(analyzer.ContextRoot contextRoot) {
-    fail('Unexpected invocation of pluginsForContextRoot');
-  }
-
-  @override
-  void recordPluginFailure(String hostPackageName, String message) {
-    fail('Unexpected invocation of recordPluginFailure');
-  }
-
-  @override
-  void removedContextRoot(analyzer.ContextRoot contextRoot) {
-    fail('Unexpected invocation of removedContextRoot');
-  }
-
-  @override
-  Future<void> restartPlugins() async {
-    // Nothing to restart.
-    return null;
-  }
-
-  @override
-  void setAnalysisSetPriorityFilesParams(
-      plugin.AnalysisSetPriorityFilesParams params) {
-    analysisSetPriorityFilesParams = params;
-  }
-
-  @override
-  void setAnalysisSetSubscriptionsParams(
-      plugin.AnalysisSetSubscriptionsParams params) {
-    analysisSetSubscriptionsParams = params;
-  }
-
-  @override
-  void setAnalysisUpdateContentParams(
-      plugin.AnalysisUpdateContentParams params) {
-    analysisUpdateContentParams = params;
-  }
-
-  @override
-  Future<List<void>> stopAll() async {
-    fail('Unexpected invocation of stopAll');
-  }
-}
diff --git a/pkg/analysis_server/test/analysis_server_test.dart b/pkg/analysis_server/test/analysis_server_test.dart
index 8a9ea74..04e0f45 100644
--- a/pkg/analysis_server/test/analysis_server_test.dart
+++ b/pkg/analysis_server/test/analysis_server_test.dart
@@ -9,6 +9,7 @@
 import 'package:analysis_server/protocol/protocol_generated.dart';
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/domain_server.dart';
+import 'package:analysis_server/src/utilities/mocks.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/instrumentation/instrumentation.dart';
 import 'package:analyzer/src/generated/sdk.dart';
@@ -18,8 +19,6 @@
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
-import 'mocks.dart';
-
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(AnalysisServerTest);
diff --git a/pkg/analysis_server/test/context_manager_test.dart b/pkg/analysis_server/test/context_manager_test.dart
index e8ac58f..1af2b10 100644
--- a/pkg/analysis_server/test/context_manager_test.dart
+++ b/pkg/analysis_server/test/context_manager_test.dart
@@ -13,12 +13,12 @@
 import 'package:analyzer/instrumentation/instrumentation.dart';
 import 'package:analyzer/source/error_processor.dart';
 import 'package:analyzer/src/context/builder.dart';
+import 'package:analyzer/src/context/context.dart';
 import 'package:analyzer/src/context/context_root.dart';
 import 'package:analyzer/src/dart/analysis/byte_store.dart';
 import 'package:analyzer/src/dart/analysis/driver.dart';
 import 'package:analyzer/src/dart/analysis/file_state.dart';
 import 'package:analyzer/src/dart/analysis/performance_logger.dart';
-import 'package:analyzer/src/dart/analysis/restricted_analysis_context.dart';
 import 'package:analyzer/src/dart/analysis/session.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/generated/engine.dart';
@@ -1750,20 +1750,6 @@
     manager.callbacks = callbacks;
   }
 
-  /**
-   * Verify that package URI's for source files in [path] will be resolved
-   * using a package root matching [expectation].
-   */
-  void _checkPackageRoot(String path, expectation) {
-    // TODO(brianwilkerson) Figure out how to test this. Possibly by comparing
-    // the contents of the package map (although that approach doesn't work at
-    // the moment).
-//    FolderDisposition disposition = callbacks.currentContextDispositions[path];
-//    expect(disposition.packageRoot, expectation);
-    // TODO(paulberry): we should also verify that the package map itself is
-    // correct.  See dartbug.com/23909.
-  }
-
   Map<String, List<Folder>> _packageMap(String contextPath) {
     Folder folder = resourceProvider.getFolder(contextPath);
     ContextInfo info = manager.getContextInfoFor(folder);
@@ -1981,9 +1967,9 @@
     newFile('$projPath/test', content: 'test.dart');
     newFile('$sdkExtPath/entry.dart');
     var synchronousSession = SynchronousSession(analysisOptions, null);
-    List<int> bytes = new SummaryBuilder(
-            [], RestrictedAnalysisContext(synchronousSession, null))
-        .build();
+    List<int> bytes =
+        new SummaryBuilder([], AnalysisContextImpl(synchronousSession, null))
+            .build();
     newFileWithBytes('$projPath/sdk.ds', bytes);
     // Setup _embedder.yaml.
     newFile('$libPath/_embedder.yaml', content: r'''
diff --git a/pkg/analysis_server/test/domain_analysis_test.dart b/pkg/analysis_server/test/domain_analysis_test.dart
index ae88bc8..10f0d83 100644
--- a/pkg/analysis_server/test/domain_analysis_test.dart
+++ b/pkg/analysis_server/test/domain_analysis_test.dart
@@ -9,6 +9,7 @@
 import 'package:analysis_server/protocol/protocol_generated.dart';
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/domain_analysis.dart';
+import 'package:analysis_server/src/utilities/mocks.dart';
 import 'package:analyzer/instrumentation/instrumentation.dart';
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/test_utilities/mock_sdk.dart';
diff --git a/pkg/analysis_server/test/domain_execution_test.dart b/pkg/analysis_server/test/domain_execution_test.dart
index d3d2908..6a7e774 100644
--- a/pkg/analysis_server/test/domain_execution_test.dart
+++ b/pkg/analysis_server/test/domain_execution_test.dart
@@ -7,6 +7,7 @@
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/domain_execution.dart';
 import 'package:analysis_server/src/protocol_server.dart';
+import 'package:analysis_server/src/utilities/mocks.dart';
 import 'package:analyzer/file_system/memory_file_system.dart';
 import 'package:analyzer/instrumentation/instrumentation.dart';
 import 'package:analyzer/src/generated/sdk.dart';
diff --git a/pkg/analysis_server/test/domain_server_test.dart b/pkg/analysis_server/test/domain_server_test.dart
index 120b2de..554eba5 100644
--- a/pkg/analysis_server/test/domain_server_test.dart
+++ b/pkg/analysis_server/test/domain_server_test.dart
@@ -7,6 +7,7 @@
 import 'package:analysis_server/protocol/protocol_generated.dart';
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/domain_server.dart';
+import 'package:analysis_server/src/utilities/mocks.dart';
 import 'package:analyzer/file_system/memory_file_system.dart';
 import 'package:analyzer/instrumentation/instrumentation.dart';
 import 'package:analyzer/src/generated/sdk.dart';
diff --git a/pkg/analysis_server/test/edit/fixes_test.dart b/pkg/analysis_server/test/edit/fixes_test.dart
index efdb5d0..07c1026 100644
--- a/pkg/analysis_server/test/edit/fixes_test.dart
+++ b/pkg/analysis_server/test/edit/fixes_test.dart
@@ -147,6 +147,8 @@
 bbb:${toUri('/bbb/lib')}
 ''');
     newFile('/bbb/lib/target.dart', content: 'class Foo() {}');
+    newFile('/bbb/lib/target.generated.dart', content: 'class Foo() {}');
+    newFile('/bbb/lib/target.template.dart', content: 'class Foo() {}');
 
     handleSuccessfulRequest(
         new AnalysisSetAnalysisRootsParams(
@@ -167,6 +169,12 @@
         .map((f) => f.message)
         .toList();
     expect(fixes, contains("Import library 'package:bbb/target.dart'"));
+    expect(
+        fixes, contains("Import library 'package:bbb/target.generated.dart'"));
+
+    // Context: http://dartbug.com/39401
+    expect(fixes.contains("Import library 'package:bbb/target.template.dart'"),
+        isFalse);
   }
 
   void _addOverlay(String name, String contents) {
diff --git a/pkg/analysis_server/test/edit/nnbd_migration/instrumentation_output_test.dart b/pkg/analysis_server/test/edit/nnbd_migration/instrumentation_output_test.dart
index e4e9f2d..59c2b7d 100644
--- a/pkg/analysis_server/test/edit/nnbd_migration/instrumentation_output_test.dart
+++ b/pkg/analysis_server/test/edit/nnbd_migration/instrumentation_output_test.dart
@@ -23,8 +23,8 @@
   // TODO(srawlins): Add tests for navigation links, which use multiple
   // libraries.
   List<String> renderLibrary(LibraryInfo libraryInfo) {
-    String packageRoot = resourceProvider.convertPath('/package');
-    String outputDir = resourceProvider.convertPath('/output');
+    String packageRoot = convertPath('/package');
+    String outputDir = convertPath('/output');
     MigrationInfo migrationInfo = MigrationInfo(
         libraryInfo.units, {}, resourceProvider.pathContext, packageRoot);
     List<String> contents = [];
@@ -37,26 +37,26 @@
   }
 
   test_outputContainsEachPath() async {
+    String convert(String path) => path.replaceAll('/', '&#x2F;');
+
     LibraryInfo info = LibraryInfo({
       unit('/package/lib/a.dart', 'int? a = null;',
-          regions: [RegionInfo(3, 1, 'null was assigned', [], RegionType.fix)]),
+          regions: [RegionInfo(RegionType.fix, 3, 1, 'null was assigned', [])]),
       unit('/package/lib/part1.dart', 'int? b = null;',
-          regions: [RegionInfo(3, 1, 'null was assigned', [], RegionType.fix)]),
+          regions: [RegionInfo(RegionType.fix, 3, 1, 'null was assigned', [])]),
       unit('/package/lib/part2.dart', 'int? c = null;',
-          regions: [RegionInfo(3, 1, 'null was assigned', [], RegionType.fix)]),
+          regions: [RegionInfo(RegionType.fix, 3, 1, 'null was assigned', [])]),
     });
     List<String> contents = renderLibrary(info);
-    expect(contents[0], contains(resourceProvider.convertPath('lib/a.dart')));
-    expect(
-        contents[1], contains(resourceProvider.convertPath('lib/part1.dart')));
-    expect(
-        contents[2], contains(resourceProvider.convertPath('lib/part2.dart')));
+    expect(contents[0], contains(convert('lib/a.dart')));
+    expect(contents[1], contains(convert('lib/part1.dart')));
+    expect(contents[2], contains(convert('lib/part2.dart')));
   }
 
   test_outputContainsEscapedHtml() async {
     LibraryInfo info = LibraryInfo({
       unit('/package/lib/a.dart', 'List<String>? a = null;', regions: [
-        RegionInfo(12, 1, 'null was assigned', [], RegionType.fix)
+        RegionInfo(RegionType.fix, 12, 1, 'null was assigned', [])
       ]),
     });
     String output = renderLibrary(info)[0];
@@ -78,7 +78,7 @@
   test_outputContainsModifiedAndUnmodifiedRegions() async {
     LibraryInfo info = LibraryInfo({
       unit('/package/lib/a.dart', 'int? a = null;',
-          regions: [RegionInfo(3, 1, 'null was assigned', [], RegionType.fix)]),
+          regions: [RegionInfo(RegionType.fix, 3, 1, 'null was assigned', [])]),
     });
     String output = renderLibrary(info)[0];
     expect(
@@ -89,7 +89,7 @@
   }
 
   UnitInfo unit(String path, String content, {List<RegionInfo> regions}) {
-    return UnitInfo(resourceProvider.convertPath(path))
+    return UnitInfo(convertPath(path))
       ..content = content
       ..regions.addAll(regions);
   }
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 7213f72..c7ec891 100644
--- a/pkg/analysis_server/test/integration/support/integration_test_methods.dart
+++ b/pkg/analysis_server/test/integration/support/integration_test_methods.dart
@@ -1105,6 +1105,7 @@
    *   If one configured path is beneath another, the descendent will override
    *   the ancestors' configured libraries of interest.
    */
+  @deprecated
   Future sendCompletionRegisterLibraryPaths(List<LibraryPathSet> paths) async {
     var params = new CompletionRegisterLibraryPathsParams(paths).toJson();
     var result = await server.send("completion.registerLibraryPaths", params);
@@ -2674,6 +2675,9 @@
    *   argument is removed. If the property isRequired is true,
    *   FLUTTER_SET_WIDGET_PROPERTY_VALUE_IS_REQUIRED error is generated.
    *
+   *   If the expression is not a syntactically valid Dart code, then
+   *   FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_EXPRESSION is reported.
+   *
    * Returns
    *
    * change: SourceChange
diff --git a/pkg/analysis_server/test/integration/support/protocol_matchers.dart b/pkg/analysis_server/test/integration/support/protocol_matchers.dart
index 8b5bbf4..c24dbef 100644
--- a/pkg/analysis_server/test/integration/support/protocol_matchers.dart
+++ b/pkg/analysis_server/test/integration/support/protocol_matchers.dart
@@ -1526,6 +1526,7 @@
  *   DEBUG_PORT_COULD_NOT_BE_OPENED
  *   FILE_NOT_ANALYZED
  *   FLUTTER_GET_WIDGET_DESCRIPTION_NO_WIDGET
+ *   FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_EXPRESSION
  *   FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_ID
  *   FLUTTER_SET_WIDGET_PROPERTY_VALUE_IS_REQUIRED
  *   FORMAT_INVALID_FILE
@@ -1561,6 +1562,7 @@
   "DEBUG_PORT_COULD_NOT_BE_OPENED",
   "FILE_NOT_ANALYZED",
   "FLUTTER_GET_WIDGET_DESCRIPTION_NO_WIDGET",
+  "FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_EXPRESSION",
   "FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_ID",
   "FLUTTER_SET_WIDGET_PROPERTY_VALUE_IS_REQUIRED",
   "FORMAT_INVALID_FILE",
diff --git a/pkg/analysis_server/test/mock_packages/meta/lib/meta.dart b/pkg/analysis_server/test/mock_packages/meta/lib/meta.dart
index 9fd9fca..834640c 100644
--- a/pkg/analysis_server/test/mock_packages/meta/lib/meta.dart
+++ b/pkg/analysis_server/test/mock_packages/meta/lib/meta.dart
@@ -12,7 +12,7 @@
 /// function's name differently.
 ///
 /// For information on installing and importing this library, see the
-/// [meta package on pub.dartlang.org] (https://pub.dartlang.org/packages/meta).
+/// [meta package on pub.dev] (https://pub.dev/packages/meta).
 /// For examples of using annotations, see
 /// [Metadata](https://www.dartlang.org/docs/dart-up-and-running/ch02.html#metadata)
 /// in the language tour.
diff --git a/pkg/analysis_server/test/mocks.dart b/pkg/analysis_server/test/mocks.dart
index 4756c84..c95121c 100644
--- a/pkg/analysis_server/test/mocks.dart
+++ b/pkg/analysis_server/test/mocks.dart
@@ -11,8 +11,6 @@
 import 'package:analysis_server/lsp_protocol/protocol_special.dart';
 import 'package:analysis_server/protocol/protocol.dart';
 import 'package:analysis_server/protocol/protocol_generated.dart';
-import 'package:analysis_server/src/analysis_server.dart';
-import 'package:analysis_server/src/channel/channel.dart';
 import 'package:analysis_server/src/lsp/channel/lsp_channel.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/timestamped_data.dart';
@@ -202,122 +200,6 @@
   }
 }
 
-/**
- * A mock [ServerCommunicationChannel] for testing [AnalysisServer].
- */
-class MockServerChannel implements ServerCommunicationChannel {
-  StreamController<Request> requestController = new StreamController<Request>();
-  StreamController<Response> responseController =
-      new StreamController<Response>.broadcast();
-  StreamController<Notification> notificationController =
-      new StreamController<Notification>(sync: true);
-  Completer<Response> errorCompleter;
-
-  List<Response> responsesReceived = [];
-  List<Notification> notificationsReceived = [];
-
-  bool _closed = false;
-
-  String name;
-
-  MockServerChannel();
-
-  @override
-  void close() {
-    _closed = true;
-  }
-
-  void expectMsgCount({responseCount = 0, notificationCount = 0}) {
-    expect(responsesReceived, hasLength(responseCount));
-    expect(notificationsReceived, hasLength(notificationCount));
-  }
-
-  @override
-  void listen(void onRequest(Request request),
-      {Function onError, void onDone()}) {
-    requestController.stream
-        .listen(onRequest, onError: onError, onDone: onDone);
-  }
-
-  @override
-  void sendNotification(Notification notification) {
-    // Don't deliver notifications after the connection is closed.
-    if (_closed) {
-      return;
-    }
-    notificationsReceived.add(notification);
-    if (errorCompleter != null && notification.event == 'server.error') {
-      print(
-          '[server.error] test: $name message: ${notification.params['message']}');
-      errorCompleter.completeError(
-          new ServerError(notification.params['message']),
-          new StackTrace.fromString(notification.params['stackTrace']));
-    }
-    // Wrap send notification in future to simulate websocket
-    // TODO(scheglov) ask Dan why and decide what to do
-//    new Future(() => notificationController.add(notification));
-    notificationController.add(notification);
-  }
-
-  /**
-   * Send the given [request] to the server and return a future that will
-   * complete when a response associated with the [request] has been received.
-   * The value of the future will be the received response. If [throwOnError] is
-   * `true` (the default) then the returned future will throw an exception if a
-   * server error is reported before the response has been received.
-   */
-  Future<Response> sendRequest(Request request, {bool throwOnError = true}) {
-    // TODO(brianwilkerson) Attempt to remove the `throwOnError` parameter and
-    // have the default behavior be the only behavior.
-    // No further requests should be sent after the connection is closed.
-    if (_closed) {
-      throw new Exception('sendRequest after connection closed');
-    }
-    // Wrap send request in future to simulate WebSocket.
-    new Future(() => requestController.add(request));
-    return waitForResponse(request, throwOnError: throwOnError);
-  }
-
-  @override
-  void sendResponse(Response response) {
-    // Don't deliver responses after the connection is closed.
-    if (_closed) {
-      return;
-    }
-    responsesReceived.add(response);
-    // Wrap send response in future to simulate WebSocket.
-    new Future(() => responseController.add(response));
-  }
-
-  /**
-   * Return a future that will complete when a response associated with the
-   * given [request] has been received. The value of the future will be the
-   * received response. If [throwOnError] is `true` (the default) then the
-   * returned future will throw an exception if a server error is reported
-   * before the response has been received.
-   *
-   * Unlike [sendRequest], this method assumes that the [request] has already
-   * been sent to the server.
-   */
-  Future<Response> waitForResponse(Request request,
-      {bool throwOnError = true}) {
-    // TODO(brianwilkerson) Attempt to remove the `throwOnError` parameter and
-    // have the default behavior be the only behavior.
-    String id = request.id;
-    Future<Response> response =
-        responseController.stream.firstWhere((response) => response.id == id);
-    if (throwOnError) {
-      errorCompleter = new Completer<Response>();
-      try {
-        return Future.any([response, errorCompleter.future]);
-      } finally {
-        errorCompleter = null;
-      }
-    }
-    return response;
-  }
-}
-
 class MockSource extends StringTypedMock implements Source {
   @override
   TimestampedData<String> contents = null;
@@ -355,16 +237,6 @@
   bool exists() => null;
 }
 
-class ServerError implements Exception {
-  final message;
-
-  ServerError(this.message);
-
-  String toString() {
-    return "Server Error: $message";
-  }
-}
-
 class StringTypedMock {
   String _toString;
 
diff --git a/pkg/analysis_server/test/services/completion/dart/field_formal_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/field_formal_contributor_test.dart
index 2bdff61..5781bf8 100644
--- a/pkg/analysis_server/test/services/completion/dart/field_formal_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/field_formal_contributor_test.dart
@@ -22,6 +22,17 @@
     return new FieldFormalContributor();
   }
 
+  /// https://github.com/dart-lang/sdk/issues/39028
+  test_mixin_constructor() async {
+    addTestSource('''
+mixin M {
+  M(this.^);
+}
+''');
+    await computeSuggestions();
+    expect(suggestions, isEmpty);
+  }
+
   test_ThisExpression_constructor_param() async {
     // SimpleIdentifier  FieldFormalParameter  FormalParameterList
     addTestSource('''
diff --git a/pkg/analysis_server/test/services/completion/dart/local_reference_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/local_reference_contributor_test.dart
index da8dc4c..93baaf3 100644
--- a/pkg/analysis_server/test/services/completion/dart/local_reference_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/local_reference_contributor_test.dart
@@ -2537,6 +2537,51 @@
     assertNoSuggestions();
   }
 
+  test_forEachPartsWithIdentifier_class() async {
+    addTestSource('''
+class C {}
+
+main() {
+ for(C in [0, 1, 2]) {
+   ^
+ }
+}
+''');
+    await computeSuggestions();
+    // Using `C` in for-each is invalid, but we should not crash.
+  }
+
+  test_forEachPartsWithIdentifier_localLevelVariable() async {
+    addTestSource('''
+main() {
+  int v;
+ for(v in [0, 1, 2]) {
+   ^
+ }
+}
+''');
+    await computeSuggestions();
+    // We don't actually use anything from the `for`, and `v` is suggested
+    // just because it is a visible top-level declaration.
+    assertSuggestLocalVariable('v', 'int');
+  }
+
+  test_forEachPartsWithIdentifier_topLevelVariable() async {
+    addTestSource('''
+int v;
+main() {
+ for(v in [0, 1, 2]) {
+   ^
+ }
+}
+''');
+    await computeSuggestions();
+    // We don't actually use anything from the `for`, and `v` is suggested
+    // just because it is a visible top-level declaration.
+    assertSuggestTopLevelVar('v', 'int',
+        relevance: DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE);
+  }
+
   test_ForEachStatement() async {
     // SimpleIdentifier  ForEachStatement
     addTestSource('main() {List<int> values; for (int index in ^)}');
@@ -2584,7 +2629,7 @@
 
   test_ForEachStatement_body_untyped() async {
     // Block  ForEachStatement
-    addTestSource('main(args) {for (foo in bar) {^}}');
+    addTestSource('main(args) {for (var foo in bar) {^}}');
     await computeSuggestions();
 
     expect(replacementOffset, completionOffset);
diff --git a/pkg/analysis_server/test/services/completion/dart/type_member_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/type_member_contributor_test.dart
index 79c7091..29d2508 100644
--- a/pkg/analysis_server/test/services/completion/dart/type_member_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/type_member_contributor_test.dart
@@ -2068,6 +2068,14 @@
     expect(suggestion.element.parameters, '(int value)');
   }
 
+  test_genericTypeAlias_noFunctionType() async {
+    addTestSource('''
+typedef F=;
+g(F.^
+''');
+    await computeSuggestions();
+  }
+
   test_IfStatement() async {
     // SimpleIdentifier  IfStatement
     addTestSource('''
diff --git a/pkg/analysis_server/test/socket_server_test.dart b/pkg/analysis_server/test/socket_server_test.dart
index 56119bb..b45a779 100644
--- a/pkg/analysis_server/test/socket_server_test.dart
+++ b/pkg/analysis_server/test/socket_server_test.dart
@@ -10,12 +10,11 @@
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/server/error_notifier.dart';
 import 'package:analysis_server/src/socket_server.dart';
+import 'package:analysis_server/src/utilities/mocks.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:test/test.dart';
 
-import 'mocks.dart';
-
 main() {
   group('SocketServer', () {
     test('createAnalysisServer_successful',
@@ -55,7 +54,7 @@
 
   static Future createAnalysisServer_successful() {
     MockServerChannel channel = new MockServerChannel();
-    SocketServer server = _createSocketServer(channel);
+    _createSocketServer(channel);
     channel.expectMsgCount(notificationCount: 1);
     expect(
         channel.notificationsReceived[0].event, SERVER_NOTIFICATION_CONNECTED);
diff --git a/pkg/analysis_server/test/src/edit/nnbd_migration/info_builder_test.dart b/pkg/analysis_server/test/src/edit/nnbd_migration/info_builder_test.dart
index 593a8fd..7b42502 100644
--- a/pkg/analysis_server/test/src/edit/nnbd_migration/info_builder_test.dart
+++ b/pkg/analysis_server/test/src/edit/nnbd_migration/info_builder_test.dart
@@ -73,8 +73,8 @@
   /// in [infos].
   Future<void> buildInfo() async {
     // Compute the analysis results.
-    server.setAnalysisRoots(
-        '0', [resourceProvider.pathContext.dirname(testFile)], [], {});
+    String includedRoot = resourceProvider.pathContext.dirname(testFile);
+    server.setAnalysisRoots('0', [includedRoot], [], {});
     ResolvedUnitResult result = await server
         .getAnalysisDriver(testFile)
         .currentSession
@@ -91,8 +91,9 @@
     migration.finish();
     // Build the migration info.
     InstrumentationInformation info = instrumentationListener.data;
-    InfoBuilder builder =
-        InfoBuilder(info, listener, explainNonNullableTypes: true);
+    InfoBuilder builder = InfoBuilder(
+        resourceProvider, includedRoot, info, listener,
+        explainNonNullableTypes: true);
     infos = (await builder.explainMigration()).toList();
   }
 
@@ -158,6 +159,104 @@
         details: ["The value of the expression is nullable"]);
   }
 
+  test_discardCondition() async {
+    UnitInfo unit = await buildInfoForSingleTestFile('''
+void g(int i) {
+  print(i.isEven);
+  if (i != null) print('NULL');
+}
+''', migratedContent: '''
+void g(int i) {
+  print(i.isEven);
+  /* if (i != null) */ print('NULL');
+}
+''');
+    List<RegionInfo> regions = unit.fixRegions;
+    expect(regions, hasLength(2));
+    assertRegion(region: regions[0], offset: 37, length: 3);
+    assertRegion(region: regions[1], offset: 55, length: 3);
+  }
+
+  test_discardElse() async {
+    UnitInfo unit = await buildInfoForSingleTestFile('''
+void g(int i) {
+  print(i.isEven);
+  if (i != null) print('NULL');
+  else print('NOT NULL');
+}
+''', migratedContent: '''
+void g(int i) {
+  print(i.isEven);
+  /* if (i != null) */ print('NULL'); /*
+  else print('NOT NULL'); */
+}
+''');
+    List<RegionInfo> regions = unit.fixRegions;
+    expect(regions, hasLength(4));
+    assertRegion(region: regions[0], offset: 37, length: 3);
+    assertRegion(region: regions[1], offset: 55, length: 3);
+    assertRegion(region: regions[2], offset: 72, length: 3);
+    assertRegion(region: regions[3], offset: 101, length: 3);
+  }
+
+  test_dynamicValueIsUsed() async {
+    UnitInfo unit = await buildInfoForSingleTestFile('''
+bool f(int i) {
+  if (i == null) return true;
+  else return false;
+}
+void g() {
+  dynamic i = null;
+  f(i);
+}
+''', migratedContent: '''
+bool f(int? i) {
+  if (i == null) return true;
+  else return false;
+}
+void g() {
+  dynamic i = null;
+  f(i);
+}
+''');
+    List<RegionInfo> regions = unit.regions;
+    expect(regions, hasLength(1));
+    assertRegion(region: regions[0], offset: 10, details: [
+      "A dynamic value, which is nullable is passed as an argument"
+    ]);
+    assertDetail(detail: regions[0].details[0], offset: 104, length: 1);
+  }
+
+  test_exactNullable() async {
+    UnitInfo unit = await buildInfoForSingleTestFile('''
+void f(List<int> list) {
+  list[0] = null;
+}
+
+void g() {
+  f(<int>[]);
+}
+''', migratedContent: '''
+void f(List<int?> list) {
+  list[0] = null;
+}
+
+void g() {
+  f(<int?>[]);
+}
+''');
+    List<RegionInfo> regions = unit.regions;
+    expect(regions, hasLength(3));
+    // regions[0] is the hard edge that f's parameter is non-nullable.
+    assertRegion(region: regions[1], offset: 15, details: [
+      "An explicit 'null' is assigned",
+    ]);
+    assertRegion(
+        region: regions[2],
+        offset: 66,
+        details: ["This is later required to accept null."]);
+  }
+
   test_expressionFunctionReturnTarget() async {
     UnitInfo unit = await buildInfoForSingleTestFile('''
 String g() => 1 == 2 ? "Hello" : null;
@@ -247,81 +346,120 @@
         details: ["This field is initialized to a nullable value"]);
   }
 
-  test_listAndSetLiteralTypeArgument() async {
-    // TODO(srawlins): Simplify this test with `var x` once #38341 is fixed.
+  test_insertedRequired_fieldFormal() async {
     UnitInfo unit = await buildInfoForSingleTestFile('''
-void f() {
-  String s = null;
-  List<String> x = <String>["hello", s];
-  Set<String> y = <String>{"hello", s};
+class C {
+  int level;
+  int level2;
+  C({this.level}) : this.level2 = level + 1;
 }
 ''', migratedContent: '''
-void f() {
-  String? s = null;
-  List<String?> x = <String?>["hello", s];
-  Set<String?> y = <String?>{"hello", s};
+class C {
+  int level;
+  int level2;
+  C({required this.level}) : this.level2 = level + 1;
 }
 ''');
     List<RegionInfo> regions = unit.fixRegions;
-    expect(regions, hasLength(5));
-    // regions[0] is the `String? s` fix.
-    // regions[1] is the `List<String?> x` fix.
-    assertRegion(
-        region: regions[2],
-        offset: 58,
-        details: ["This list is initialized with a nullable value on line 3"]);
-    assertDetail(detail: regions[2].details[0], offset: 67, length: 1);
-    // regions[3] is the `Set<String?> y` fix.
-    assertRegion(
-        region: regions[4],
-        offset: 100,
-        details: ["This set is initialized with a nullable value on line 4"]);
-    assertDetail(detail: regions[4].details[0], offset: 107, length: 1);
+    expect(regions, hasLength(1));
+    assertRegion(region: regions[0], offset: 42, length: 9, details: [
+      "This parameter is non-nullable, so cannot have an implicit default "
+          "value of 'null'"
+    ]);
   }
 
-  test_listLiteralTypeArgument_collectionIf() async {
-    // TODO(srawlins): Simplify this test with `var x` once #38341 is fixed.
+  test_insertedRequired_parameter() async {
+    UnitInfo unit = await buildInfoForSingleTestFile('''
+class C {
+  int level;
+  bool f({int lvl}) => lvl >= level;
+}
+''', migratedContent: '''
+class C {
+  int? level;
+  bool f({required int lvl}) => lvl >= level!;
+}
+''');
+    List<RegionInfo> regions = unit.fixRegions;
+    expect(regions, hasLength(3));
+    // regions[0] is the `int? s` fix.
+    assertRegion(region: regions[1], offset: 34, length: 9, details: [
+      "This parameter is non-nullable, so cannot have an implicit default "
+          "value of 'null'"
+    ]);
+    // regions[2] is the `level!` fix.
+  }
+
+  test_listAndSetLiteralTypeArgument() async {
     UnitInfo unit = await buildInfoForSingleTestFile('''
 void f() {
   String s = null;
-  List<String> x = <String>[
-    "hello",
-    if (1 == 2) s
-  ];
+  var x = <String>["hello", s];
+  var y = <String>{"hello", s};
 }
 ''', migratedContent: '''
 void f() {
   String? s = null;
-  List<String?> x = <String?>[
-    "hello",
-    if (1 == 2) s
-  ];
+  var x = <String?>["hello", s];
+  var y = <String?>{"hello", s};
 }
 ''');
     List<RegionInfo> regions = unit.fixRegions;
     expect(regions, hasLength(3));
     // regions[0] is the `String? s` fix.
-    // regions[1] is the `List<String?> x` fix.
+    assertRegion(
+        region: regions[1],
+        offset: 48,
+        details: ["This list is initialized with a nullable value on line 3"]);
+    assertDetail(detail: regions[1].details[0], offset: 58, length: 1);
     assertRegion(
         region: regions[2],
-        offset: 58,
+        offset: 81,
+        details: ["This set is initialized with a nullable value on line 4"]);
+    assertDetail(detail: regions[2].details[0], offset: 90, length: 1);
+  }
+
+  test_listLiteralTypeArgument_collectionIf() async {
+    UnitInfo unit = await buildInfoForSingleTestFile('''
+void f() {
+  String s = null;
+  var x = <String>[
+    "hello",
+    if (1 == 2) s
+  ];
+}
+''', migratedContent: '''
+void f() {
+  String? s = null;
+  var x = <String?>[
+    "hello",
+    if (1 == 2) s
+  ];
+}
+''');
+    List<RegionInfo> regions = unit.fixRegions;
+    expect(regions, hasLength(2));
+    // regions[0] is the `String? s` fix.
+    assertRegion(
+        region: regions[1],
+        offset: 48,
         details: ["This list is initialized with a nullable value on line 5"]);
-    assertDetail(detail: regions[2].details[0], offset: 88, length: 1);
+    assertDetail(detail: regions[1].details[0], offset: 79, length: 1);
   }
 
   test_localVariable() async {
     UnitInfo unit = await buildInfoForSingleTestFile('''
 void f() {
-  int _v1 = null;
-  int _v2 = _v1;
+  int v1 = null;
+  int v2 = v1;
 }
 ''', migratedContent: '''
 void f() {
-  int? _v1 = null;
-  int? _v2 = _v1;
+  int? v1 = null;
+  int? v2 = v1;
 }
 ''');
-    List<RegionInfo> regions = unit.regions;
+    List<RegionInfo> regions = unit.fixRegions;
     expect(regions, hasLength(2));
     assertRegion(
         region: regions[0],
@@ -329,40 +467,37 @@
         details: ["This variable is initialized to an explicit 'null'"]);
     assertRegion(
         region: regions[1],
-        offset: 35,
+        offset: 34,
         details: ["This variable is initialized to a nullable value"]);
   }
 
   test_mapLiteralTypeArgument() async {
-    // TODO(srawlins): Simplify this test with `var x` once #38341 is fixed.
     UnitInfo unit = await buildInfoForSingleTestFile('''
 void f() {
   String s = null;
-  Map<String, bool> x = <String, bool>{"hello": false, s: true};
-  Map<bool, String> y = <bool, String>{false: "hello", true: s};
+  var x = <String, bool>{"hello": false, s: true};
+  var y = <bool, String>{false: "hello", true: s};
 }
 ''', migratedContent: '''
 void f() {
   String? s = null;
-  Map<String?, bool> x = <String?, bool>{"hello": false, s: true};
-  Map<bool, String?> y = <bool, String?>{false: "hello", true: s};
+  var x = <String?, bool>{"hello": false, s: true};
+  var y = <bool, String?>{false: "hello", true: s};
 }
 ''');
     List<RegionInfo> regions = unit.fixRegions;
-    expect(regions, hasLength(5));
+    expect(regions, hasLength(3));
     // regions[0] is the `String? s` fix.
-    // regions[1] is the `Map<String?, bool> x` fix.
+    assertRegion(
+        region: regions[1],
+        offset: 48,
+        details: ["This map is initialized with a nullable value on line 3"]);
+    assertDetail(detail: regions[1].details[0], offset: 71, length: 1);
     assertRegion(
         region: regions[2],
-        offset: 63,
-        details: ["This map is initialized with a nullable value on line 3"]);
-    assertDetail(detail: regions[2].details[0], offset: 85, length: 1);
-    // regions[3] is the `Map<bool, String?> y` fix.
-    assertRegion(
-        region: regions[4],
-        offset: 136,
+        offset: 106,
         details: ["This map is initialized with a nullable value on line 4"]);
-    assertDetail(detail: regions[4].details[0], offset: 156, length: 1);
+    assertDetail(detail: regions[2].details[0], offset: 128, length: 1);
   }
 
   test_nonNullableType_assert() async {
@@ -414,6 +549,33 @@
     ]);
   }
 
+  test_nullCheck_onFunctionArgument() async {
+    UnitInfo unit = await buildInfoForSingleTestFile('''
+class C {
+  int value;
+  C([this.value]);
+  void f() {
+    value.abs();
+  }
+}
+''', migratedContent: '''
+class C {
+  int? value;
+  C([this.value]);
+  void f() {
+    value!.abs();
+  }
+}
+''');
+    List<RegionInfo> regions = unit.regions;
+    expect(regions, hasLength(2));
+    // regions[0] is `int?`.
+    assertRegion(
+        region: regions[1],
+        offset: 65,
+        details: ["A nullable value can't be used here"]);
+  }
+
   test_parameter_fromInvocation_explicit() async {
     UnitInfo unit = await buildInfoForSingleTestFile('''
 void f(String s) {}
@@ -491,6 +653,7 @@
     ]);
   }
 
+  @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/39378')
   test_parameter_fromOverriden_implicit() async {
     UnitInfo unit = await buildInfoForSingleTestFile('''
 class A {
@@ -600,7 +763,6 @@
         details: ["This parameter has an implicit default value of 'null'"]);
   }
 
-  @failingTest
   test_return_fromOverriden() async {
     UnitInfo unit = await buildInfoForSingleTestFile('''
 abstract class A {
@@ -623,6 +785,7 @@
         region: regions[0],
         offset: 27,
         details: ["An overridding method has a nullable return value"]);
+    assertDetail(detail: regions[0].details[0], offset: 60, length: 6);
   }
 
   test_return_multipleReturns() async {
@@ -742,11 +905,10 @@
   }
 
   test_setLiteralTypeArgument_nestedList() async {
-    // TODO(srawlins): Simplify this test with `var x` once #38341 is fixed.
     UnitInfo unit = await buildInfoForSingleTestFile('''
 void f() {
   String s = null;
-  Set<List<String>> x = <List<String>>{
+  var x = <List<String>>{
     ["hello"],
     if (1 == 2) [s]
   };
@@ -754,23 +916,22 @@
 ''', migratedContent: '''
 void f() {
   String? s = null;
-  Set<List<String?>> x = <List<String?>>{
+  var x = <List<String?>>{
     ["hello"],
     if (1 == 2) [s]
   };
 }
 ''');
     List<RegionInfo> regions = unit.fixRegions;
-    expect(regions, hasLength(3));
+    expect(regions, hasLength(2));
     // regions[0] is the `String? s` fix.
-    // regions[1] is the `Set<List<String?>> x` fix.
     assertRegion(
-        region: regions[2],
-        offset: 68,
+        region: regions[1],
+        offset: 53,
         details: ["This set is initialized with a nullable value on line 5"]);
     // TODO(srawlins): Actually, this is marking the `[s]`, but I think only
     //  `s` should be marked. Minor bug for now.
-    assertDetail(detail: regions[2].details[0], offset: 101, length: 3);
+    assertDetail(detail: regions[1].details[0], offset: 87, length: 3);
   }
 
   test_topLevelVariable() async {
@@ -792,4 +953,66 @@
         offset: 19,
         details: ["This variable is initialized to a nullable value"]);
   }
+
+  test_uninitializedField() async {
+    UnitInfo unit = await buildInfoForSingleTestFile('''
+class C {
+  int value;
+  C();
+  C.one() {
+    this.value = 7;
+  }
+  C.two() {}
+}
+''', migratedContent: '''
+class C {
+  int? value;
+  C();
+  C.one() {
+    this.value = 7;
+  }
+  C.two() {}
+}
+''');
+    List<RegionInfo> regions = unit.regions;
+    expect(regions, hasLength(1));
+    RegionInfo region = regions.single;
+    assertRegion(region: region, offset: 15, details: [
+      "The constructor 'C' does not initialize this field in its initializer "
+          "list",
+      "The constructor 'C.one' does not initialize this field in its "
+          "initializer list",
+      "The constructor 'C.two' does not initialize this field in its "
+          "initializer list",
+    ]);
+
+    assertDetail(detail: region.details[0], offset: 25, length: 1);
+    assertDetail(detail: region.details[1], offset: 34, length: 3);
+    assertDetail(detail: region.details[2], offset: 70, length: 3);
+  }
+
+  test_uninitializedVariable_notLate_uninitializedUse() async {
+    UnitInfo unit = await buildInfoForSingleTestFile('''
+void f() {
+  int v1;
+  if (1 == 2) v1 = 7;
+  g(v1);
+}
+void g(int i) => print(i.isEven);
+''', migratedContent: '''
+void f() {
+  int? v1;
+  if (1 == 2) v1 = 7;
+  g(v1!);
+}
+void g(int i) => print(i.isEven);
+''');
+    List<RegionInfo> regions = unit.fixRegions;
+    expect(regions, hasLength(2));
+    assertRegion(
+        region: regions[0],
+        offset: 16,
+        details: ["Used on line 4, when it is possibly uninitialized"]);
+    // regions[1] is the `v1!` fix.
+  }
 }
diff --git a/pkg/analysis_server/test/src/services/flutter/widget_descriptions_test.dart b/pkg/analysis_server/test/src/services/flutter/widget_descriptions_test.dart
index 8fe158f..980d4b4 100644
--- a/pkg/analysis_server/test/src/services/flutter/widget_descriptions_test.dart
+++ b/pkg/analysis_server/test/src/services/flutter/widget_descriptions_test.dart
@@ -321,6 +321,29 @@
 ''');
   }
 
+  test_expression_formatError() async {
+    await resolveTestUnit('''
+import 'package:flutter/material.dart';
+
+void main() {
+  Text('', maxLines: 1);
+}
+''');
+    var property = await getWidgetProperty('Text(', 'maxLines');
+
+    var result = await descriptions.setPropertyValue(
+      property.id,
+      protocol.FlutterWidgetPropertyValue(expression: 'foo <'),
+    );
+
+    expect(
+      result.errorCode,
+      protocol.RequestErrorCode
+          .FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_EXPRESSION,
+    );
+    expect(result.change, isNull);
+  }
+
   test_format_dontFormatOther() async {
     await resolveTestUnit('''
 import 'package:flutter/material.dart';
diff --git a/pkg/analysis_server/test/src/test_all.dart b/pkg/analysis_server/test/src/test_all.dart
index 39637af..fa37c50 100644
--- a/pkg/analysis_server/test/src/test_all.dart
+++ b/pkg/analysis_server/test/src/test_all.dart
@@ -13,7 +13,6 @@
 import 'plugin/test_all.dart' as plugin;
 import 'services/test_all.dart' as services;
 import 'utilities/test_all.dart' as utilities;
-import 'watch_manager_test.dart' as watch_manager;
 
 /**
  * Utility for manually running all tests.
@@ -29,6 +28,5 @@
     plugin.main();
     services.main();
     utilities.main();
-    watch_manager.main();
   }, name: 'src');
 }
diff --git a/pkg/analysis_server/test/src/watch_manager_test.dart b/pkg/analysis_server/test/src/watch_manager_test.dart
deleted file mode 100644
index a5a4a93..0000000
--- a/pkg/analysis_server/test/src/watch_manager_test.dart
+++ /dev/null
@@ -1,345 +0,0 @@
-// Copyright (c) 2015, 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:async';
-
-import 'package:analysis_server/src/watch_manager.dart';
-import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
-import 'package:test/test.dart';
-import 'package:test_reflective_loader/test_reflective_loader.dart';
-import 'package:watcher/watcher.dart';
-
-main() {
-  defineReflectiveSuite(() {
-    defineReflectiveTests(WatchManagerTest);
-    defineReflectiveTests(WatchNodeTest);
-  });
-}
-
-/**
- * Tokens that can be used for testing purposes.
- */
-class Token {
-  /**
-   * A name used for debugging.
-   */
-  final String name;
-
-  /**
-   * Initialize a newly created token to have the given name.
-   */
-  Token(this.name);
-
-  @override
-  String toString() => name;
-}
-
-/**
- * A listener that captures the state of watch events so that they can be
- * tested.
- */
-class WatchListener {
-  /**
-   * The event that was passed to the listener method.
-   */
-  WatchEvent event;
-
-  /**
-   * The tokens that were passed to the listener method.
-   */
-  List<Token> tokens;
-
-  /**
-   * Clear the state so that we can distinguish between not receiving an event
-   * and receiving the wrong event.
-   */
-  void clear() {
-    this.event = null;
-    this.tokens = null;
-  }
-
-  /**
-   * The listener method.
-   */
-  void handleWatchEvent(WatchEvent event, List<Token> tokens) {
-    this.event = event;
-    this.tokens = tokens;
-  }
-}
-
-@reflectiveTest
-class WatchManagerTest with ResourceProviderMixin {
-  WatchListener listener;
-  WatchManager<Token> manager;
-
-  void setUp() {
-    listener = new WatchListener();
-    manager =
-        new WatchManager<Token>(resourceProvider, listener.handleWatchEvent);
-  }
-
-  Future test_addFolder_folderAndSubfolder() async {
-    Folder topFolder = getFolder('/a/b');
-    Folder childFolder = getFolder('/a/b/c/d');
-    Token topToken = new Token('topToken');
-    Token childToken = new Token('childToken');
-    manager.addFolder(topFolder, topToken);
-    manager.addFolder(childFolder, childToken);
-
-    File newFile1 = newFile('/a/b/c/lib.dart');
-    await _expectEvent(ChangeType.ADD, newFile1.path, [topToken]);
-
-    File newFile2 = newFile('/a/b/c/d/lib.dart');
-    return _expectEvent(ChangeType.ADD, newFile2.path, [topToken, childToken]);
-  }
-
-  Future test_addFolder_singleFolder_multipleTokens() {
-    Folder folder = getFolder('/a/b');
-    Token token1 = new Token('token1');
-    Token token2 = new Token('token2');
-    manager.addFolder(folder, token1);
-    manager.addFolder(folder, token2);
-
-    File addedFile = newFile('/a/b/lib.dart');
-    return _expectEvent(ChangeType.ADD, addedFile.path, [token1, token2]);
-  }
-
-  Future test_addFolder_singleFolder_singleToken() async {
-    Folder folder = getFolder('/a/b');
-    Token token = new Token('token');
-    manager.addFolder(folder, token);
-
-    Folder addedFolder = newFolder('/a/b/c');
-    await _expectEvent(ChangeType.ADD, addedFolder.path, [token]);
-
-    File addedFile = newFile('/a/b/c/lib.dart');
-    return _expectEvent(ChangeType.ADD, addedFile.path, [token]);
-  }
-
-  Future test_addFolder_unrelatedFolders() async {
-    Folder folder1 = getFolder('/a/b');
-    Folder folder2 = getFolder('/c/d');
-    Token token1 = new Token('token1');
-    Token token2 = new Token('token2');
-    manager.addFolder(folder1, token1);
-    manager.addFolder(folder2, token2);
-
-    File newFile1 = newFile('/a/b/lib.dart');
-    await _expectEvent(ChangeType.ADD, newFile1.path, [token1]);
-
-    File newFile2 = newFile('/c/d/lib.dart');
-    return _expectEvent(ChangeType.ADD, newFile2.path, [token2]);
-  }
-
-  void test_creation() {
-    expect(manager, isNotNull);
-  }
-
-  Future test_removeFolder_multipleTokens() {
-    Folder folder = getFolder('/a/b');
-    Token token1 = new Token('token1');
-    Token token2 = new Token('token2');
-    manager.addFolder(folder, token1);
-    manager.addFolder(folder, token2);
-    manager.removeFolder(folder, token2);
-
-    File addedFile = newFile('/a/b/lib.dart');
-    return _expectEvent(ChangeType.ADD, addedFile.path, [token1]);
-  }
-
-  Future test_removeFolder_withChildren() async {
-    Folder topFolder = getFolder('/a/b');
-    Folder childFolder = getFolder('/a/b/c/d');
-    Token topToken = new Token('topToken');
-    Token childToken = new Token('childToken');
-    manager.addFolder(topFolder, topToken);
-    manager.addFolder(childFolder, childToken);
-    manager.removeFolder(topFolder, topToken);
-
-    File addedFile = newFile('/a/b/c/d/lib.dart');
-    await _expectEvent(ChangeType.ADD, addedFile.path, [childToken]);
-
-    newFile('/a/b/lib.dart');
-    return _expectNoEvent();
-  }
-
-  Future test_removeFolder_withNoChildren() {
-    Folder folder = getFolder('/a/b');
-    Token token = new Token('token');
-    manager.addFolder(folder, token);
-    manager.removeFolder(folder, token);
-
-    newFile('/a/b/lib.dart');
-    return _expectNoEvent();
-  }
-
-  Future _expectEvent(ChangeType expectedType, String expectedPath,
-      List<Token> expectedTokens) async {
-    await pumpEventQueue();
-    WatchEvent event = listener.event;
-    expect(event, isNotNull);
-    expect(event.type, expectedType);
-    expect(event.path, expectedPath);
-    expect(listener.tokens, unorderedEquals(expectedTokens));
-    listener.clear();
-  }
-
-  Future _expectNoEvent() async {
-    await pumpEventQueue();
-    expect(listener.event, isNull);
-    expect(listener.tokens, isNull);
-  }
-}
-
-@reflectiveTest
-class WatchNodeTest with ResourceProviderMixin {
-  void test_creation_folder() {
-    Folder folder = getFolder('/a/b');
-    WatchNode node = new WatchNode(folder);
-    expect(node, isNotNull);
-    expect(node.children, isEmpty);
-    expect(node.folder, folder);
-    expect(node.parent, isNull);
-    expect(node.subscription, isNull);
-    expect(node.tokens, isEmpty);
-  }
-
-  void test_creation_noFolder() {
-    WatchNode node = new WatchNode(null);
-    expect(node, isNotNull);
-    expect(node.children, isEmpty);
-    expect(node.folder, isNull);
-    expect(node.parent, isNull);
-    expect(node.subscription, isNull);
-    expect(node.tokens, isEmpty);
-  }
-
-  void test_delete_nested_child() {
-    WatchNode rootNode = new WatchNode(null);
-    WatchNode topNode = new WatchNode(getFolder('/a/b'));
-    WatchNode childNode = new WatchNode(getFolder('/a/b/c/d'));
-    WatchNode grandchildNode = new WatchNode(getFolder('/a/b/c/d/e'));
-    rootNode.insert(topNode);
-    rootNode.insert(childNode);
-    rootNode.insert(grandchildNode);
-
-    childNode.delete();
-    expect(rootNode.children, equals([topNode]));
-    expect(topNode.children, equals([grandchildNode]));
-    expect(topNode.parent, rootNode);
-    expect(grandchildNode.parent, topNode);
-  }
-
-  void test_delete_nested_noChild() {
-    WatchNode rootNode = new WatchNode(null);
-    WatchNode topNode = new WatchNode(getFolder('/a/b'));
-    WatchNode childNode = new WatchNode(getFolder('/a/b/c/d'));
-    rootNode.insert(topNode);
-    rootNode.insert(childNode);
-
-    childNode.delete();
-    expect(rootNode.children, equals([topNode]));
-    expect(topNode.children, isEmpty);
-    expect(topNode.parent, rootNode);
-  }
-
-  void test_delete_top_child() {
-    WatchNode rootNode = new WatchNode(null);
-    WatchNode topNode = new WatchNode(getFolder('/a/b'));
-    WatchNode childNode = new WatchNode(getFolder('/a/b/c/d'));
-    rootNode.insert(topNode);
-    rootNode.insert(childNode);
-
-    topNode.delete();
-    expect(rootNode.children, equals([childNode]));
-    expect(childNode.parent, rootNode);
-  }
-
-  void test_delete_top_noChild() {
-    WatchNode rootNode = new WatchNode(null);
-    WatchNode topNode = new WatchNode(getFolder('/a/b'));
-    rootNode.insert(topNode);
-
-    topNode.delete();
-    expect(rootNode.children, isEmpty);
-  }
-
-  void test_findParent_childOfLeaf() {
-    WatchNode rootNode = new WatchNode(null);
-    WatchNode topNode = new WatchNode(getFolder('/a/b'));
-    rootNode.insert(topNode);
-
-    expect(rootNode.findParent('/a/b/c'), topNode);
-  }
-
-  void test_findParent_childOfNonLeaf() {
-    WatchNode rootNode = new WatchNode(null);
-    WatchNode topNode = new WatchNode(getFolder('/a/b'));
-    WatchNode childNode = new WatchNode(getFolder('/a/b/c/d'));
-    rootNode.insert(topNode);
-    rootNode.insert(childNode);
-
-    expect(rootNode.findParent('/a/b/c'), topNode);
-  }
-
-  void test_findParent_noMatch() {
-    WatchNode rootNode = new WatchNode(null);
-    WatchNode topNode = new WatchNode(getFolder('/a/b'));
-    rootNode.insert(topNode);
-
-    expect(rootNode.findParent('/c/d'), rootNode);
-  }
-
-  void test_insert_intermediate_afterParentAndChild() {
-    WatchNode rootNode = new WatchNode(null);
-    WatchNode topNode = new WatchNode(getFolder('/a/b'));
-    WatchNode childNode = new WatchNode(getFolder('/a/b/c/d'));
-    WatchNode intermediateNode = new WatchNode(getFolder('/a/b/c'));
-
-    rootNode.insert(topNode);
-    rootNode.insert(childNode);
-    rootNode.insert(intermediateNode);
-    expect(topNode.parent, rootNode);
-    expect(topNode.children, equals([intermediateNode]));
-    expect(intermediateNode.parent, topNode);
-    expect(intermediateNode.children, equals([childNode]));
-    expect(childNode.parent, intermediateNode);
-    expect(childNode.children, isEmpty);
-  }
-
-  void test_insert_nested_afterParent() {
-    WatchNode rootNode = new WatchNode(null);
-    WatchNode topNode = new WatchNode(getFolder('/a/b'));
-    WatchNode childNode = new WatchNode(getFolder('/a/b/c/d'));
-
-    rootNode.insert(topNode);
-    rootNode.insert(childNode);
-    expect(childNode.parent, topNode);
-    expect(childNode.children, isEmpty);
-    expect(topNode.children, equals([childNode]));
-  }
-
-  void test_insert_nested_beforeParent() {
-    WatchNode rootNode = new WatchNode(null);
-    WatchNode topNode = new WatchNode(getFolder('/a/b'));
-    WatchNode childNode = new WatchNode(getFolder('/a/b/c/d'));
-
-    rootNode.insert(childNode);
-    rootNode.insert(topNode);
-    expect(childNode.parent, topNode);
-    expect(childNode.children, isEmpty);
-    expect(topNode.children, equals([childNode]));
-  }
-
-  void test_insert_top() {
-    WatchNode rootNode = new WatchNode(null);
-    WatchNode topNode = new WatchNode(getFolder('/a/b'));
-
-    rootNode.insert(topNode);
-    expect(rootNode.children, equals([topNode]));
-    expect(topNode.parent, rootNode);
-    expect(topNode.children, isEmpty);
-  }
-}
diff --git a/pkg/analysis_server/tool/lsp_spec/README.md b/pkg/analysis_server/tool/lsp_spec/README.md
index ea364d4..17348dd 100644
--- a/pkg/analysis_server/tool/lsp_spec/README.md
+++ b/pkg/analysis_server/tool/lsp_spec/README.md
@@ -117,6 +117,6 @@
 ### dart/textDocument/publishClosingLabels Notification
 
 Direction: Server -> Client
-Params: `{ uri: string, abels: { label: string, range: Range }[] }`
+Params: `{ uri: string, labels: { label: string, range: Range }[] }`
 
 Notifies the client when closing label information is available (or updated) for a file.
diff --git a/pkg/analysis_server/tool/migration_runner.dart b/pkg/analysis_server/tool/migration_runner.dart
new file mode 100644
index 0000000..c826d61
--- /dev/null
+++ b/pkg/analysis_server/tool/migration_runner.dart
@@ -0,0 +1,176 @@
+// Copyright (c) 2019, 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.
+
+/// This executable provides the ability to run the migration tool in process
+/// on a single package.  It should be invoked with two command-line arguments:
+/// a path to a configuration file and the name of a package to migrate.
+///
+/// The configuration file format is a JSON map, with the following keys:
+/// - `sdk_root`: path to the SDK source code on the user's machine (this is the
+///   directory that contains `pkg`, `third_party`, `tests`, etc.
+/// - `output_root`: if present, path to the directory on the user's machine
+///   where output HTML files should go.  A subdirectory will be created for
+///   each package that is migrated.
+/// - `external_packages`: a map (name => path) of additional non-SDK packages
+///   that may need to be migrated.
+/// - `port`: if present, the port where a server should be spawned serving HTML
+///   pages.
+library migration_runner;
+
+import 'dart:convert';
+import 'dart:io' as io;
+
+import 'package:analysis_server/protocol/protocol.dart';
+import 'package:analysis_server/protocol/protocol_constants.dart';
+import 'package:analysis_server/protocol/protocol_generated.dart';
+import 'package:analysis_server/src/analysis_server.dart';
+import 'package:analysis_server/src/utilities/mocks.dart';
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/file_system/physical_file_system.dart';
+import 'package:analyzer/instrumentation/instrumentation.dart';
+import 'package:analyzer/src/dart/sdk/sdk.dart';
+import 'package:analyzer/src/generated/sdk.dart';
+import 'package:path/path.dart' as path;
+import 'package:test/test.dart';
+
+main(List<String> args) async {
+  if (args.length != 2) {
+    throw StateError(
+        'Exactly two arguments are required: the path to a JSON configuration '
+        'file, and the name of the package to migrate');
+  }
+  var testInfoJsonPath = args[0];
+  var testInfoJson = json.decode(io.File(testInfoJsonPath).readAsStringSync());
+  var packageName = args[1];
+  var testInfo = TestInfo(testInfoJson);
+  var packageRoot = testInfo.packageRoot(packageName);
+  var outputRoot = testInfo.outputRoot;
+  var port = testInfo.port;
+  String outputDir =
+      outputRoot == null ? null : path.join(outputRoot, packageName);
+  print('Preparing to migrate');
+  var migrationTest = MigrationTest();
+  migrationTest.setUp();
+  print('Migrating');
+  await migrationTest.run(packageRoot, outputDir, port);
+  if (port == null) {
+    print('Done');
+    io.exit(0);
+  } else {
+    print('Done.  Please point your browser to localhost:$port/\$filePath');
+  }
+}
+
+class MigrationBase {
+  ResourceProvider resourceProvider = PhysicalResourceProvider.INSTANCE;
+  MockServerChannel serverChannel;
+  AnalysisServer server;
+
+  AnalysisServer createAnalysisServer() {
+    //
+    // Create server
+    //
+    AnalysisServerOptions options = new AnalysisServerOptions();
+    String sdkPath = FolderBasedDartSdk.defaultSdkDirectory(
+      PhysicalResourceProvider.INSTANCE,
+    ).path;
+    return new AnalysisServer(serverChannel, resourceProvider, options,
+        new DartSdkManager(sdkPath, true), InstrumentationService.NULL_SERVICE);
+  }
+
+  void processNotification(Notification notification) {
+    if (notification.event == SERVER_NOTIFICATION_ERROR) {
+      fail('${notification.toJson()}');
+    }
+  }
+
+  Future<Response> sendAnalysisSetAnalysisRoots(List<String> directories) {
+    var request =
+        AnalysisSetAnalysisRootsParams(directories, []).toRequest('0');
+    return waitResponse(request);
+  }
+
+  Future<Response> sendEditDartfix(
+      List<String> directories, String outputDir, int port) {
+    var request = EditDartfixParams(directories,
+            includedFixes: ['non-nullable'], outputDir: outputDir, port: port)
+        .toRequest('1');
+    return waitResponse(request);
+  }
+
+  void setUp() {
+    serverChannel = new MockServerChannel();
+    server = createAnalysisServer();
+    server.pluginManager = new TestPluginManager();
+    // listen for notifications
+    Stream<Notification> notificationStream =
+        serverChannel.notificationController.stream;
+    notificationStream.listen((Notification notification) {
+      processNotification(notification);
+    });
+  }
+
+  void tearDown() {
+    server.done();
+    server = null;
+    serverChannel = null;
+  }
+
+  /// Returns a [Future] that completes when the server's analysis is complete.
+  Future waitForTasksFinished() {
+    return server.onAnalysisComplete;
+  }
+
+  /// Completes with a successful [Response] for the given [request].
+  Future<Response> waitResponse(Request request,
+      {bool throwOnError = true}) async {
+    return serverChannel.sendRequest(request, throwOnError: throwOnError);
+  }
+}
+
+class MigrationTest extends MigrationBase {
+  Future<void> run(String packageRoot, String outputDir, int port) async {
+    List<String> packageRoots = [packageRoot];
+    await sendAnalysisSetAnalysisRoots(packageRoots);
+    await sendEditDartfix(packageRoots, outputDir, port);
+  }
+}
+
+class TestInfo {
+  static const Set<String> thirdPartyPackages = {
+    'charcode',
+    'collection',
+    'logging',
+    'meta',
+    'pedantic',
+    'typed_data'
+  };
+
+  static const Set<String> builtInPackages = {'meta', 'path'};
+
+  final Map<String, Object> testInfoJson;
+
+  TestInfo(this.testInfoJson);
+
+  Map<String, String> get externalPackages =>
+      ((testInfoJson['external_packages'] ?? {}) as Map).cast<String, String>();
+
+  String get outputRoot => testInfoJson['output_root'];
+
+  int get port => testInfoJson['port'];
+
+  String get sdkRoot => testInfoJson['sdk_root'];
+
+  String packageRoot(String packageName) {
+    if (thirdPartyPackages.contains(packageName)) {
+      return path.join(sdkRoot, 'third_party', 'pkg', packageName);
+    } else if (builtInPackages.contains(packageName)) {
+      return path.join(sdkRoot, 'pkg', packageName);
+    } else if (externalPackages.containsKey(packageName)) {
+      return externalPackages[packageName];
+    } else {
+      throw StateError('Unrecognized package $packageName');
+    }
+  }
+}
diff --git a/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java b/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java
index e2df2d3..c887243 100644
--- a/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java
+++ b/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java
@@ -439,6 +439,8 @@
    *         the client is interested in receiving completion suggestions. If one configured path is
    *         beneath another, the descendent will override the ancestors' configured libraries of
    *         interest.
+   *
+   * @deprecated
    */
   public void completion_registerLibraryPaths(List<LibraryPathSet> paths);
 
@@ -842,7 +844,9 @@
    * @param value The new value to set for the property. If absent, indicates that the property
    *         should be removed. If the property corresponds to an optional parameter, the
    *         corresponding named argument is removed. If the property isRequired is true,
-   *         FLUTTER_SET_WIDGET_PROPERTY_VALUE_IS_REQUIRED error is generated.
+   *         FLUTTER_SET_WIDGET_PROPERTY_VALUE_IS_REQUIRED error is generated. If the expression is
+   *         not a syntactically valid Dart code, then
+   *         FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_EXPRESSION is reported.
    */
   public void flutter_setWidgetPropertyValue(int id, FlutterWidgetPropertyValue value, SetWidgetPropertyValueConsumer consumer);
 
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 6abbf6e..c968830 100644
--- a/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java
+++ b/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java
@@ -38,6 +38,11 @@
   public static final String FLUTTER_GET_WIDGET_DESCRIPTION_NO_WIDGET = "FLUTTER_GET_WIDGET_DESCRIPTION_NO_WIDGET";
 
   /**
+   * The given property expression is invalid, e.g. has a syntax error.
+   */
+  public static final String FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_EXPRESSION = "FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_EXPRESSION";
+
+  /**
    * The given property identifier is not valid. It might have never been valid, or a change to code
    * invalidated it, or its TTL was exceeded.
    */
diff --git a/pkg/analysis_server/tool/spec/spec_input.html b/pkg/analysis_server/tool/spec/spec_input.html
index 5c210a87..360bab1 100644
--- a/pkg/analysis_server/tool/spec/spec_input.html
+++ b/pkg/analysis_server/tool/spec/spec_input.html
@@ -1437,7 +1437,7 @@
       </field>
     </params>
   </request>
-  <request method="registerLibraryPaths">
+  <request method="registerLibraryPaths" deprecated="true">
     <p>
       The client can make this request to express interest in certain
       libraries to receive completion suggestions from based on the client path.
@@ -3245,6 +3245,11 @@
           true, <tt>FLUTTER_SET_WIDGET_PROPERTY_VALUE_IS_REQUIRED</tt> error
           is generated.
         </p>
+        <p>
+          If the <tt>expression</tt> is not a syntactically valid Dart code,
+          then <tt>FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_EXPRESSION</tt>
+          is reported.
+        </p>
       </field>
     </params>
     <result>
@@ -4901,6 +4906,12 @@
         </p>
       </value>
       <value>
+        <code>FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_EXPRESSION</code>
+        <p>
+          The given property expression is invalid, e.g. has a syntax error.
+        </p>
+      </value>
+      <value>
         <code>FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_ID</code>
         <p>
           The given property identifier is not valid. It might have never been
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 6431008..f04a782 100644
--- a/pkg/analysis_server_client/lib/src/protocol/protocol_generated.dart
+++ b/pkg/analysis_server_client/lib/src/protocol/protocol_generated.dart
@@ -15780,6 +15780,9 @@
    * corresponds to an optional parameter, the corresponding named argument is
    * removed. If the property isRequired is true,
    * FLUTTER_SET_WIDGET_PROPERTY_VALUE_IS_REQUIRED error is generated.
+   *
+   * If the expression is not a syntactically valid Dart code, then
+   * FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_EXPRESSION is reported.
    */
   FlutterWidgetPropertyValue get value => _value;
 
@@ -15790,6 +15793,9 @@
    * corresponds to an optional parameter, the corresponding named argument is
    * removed. If the property isRequired is true,
    * FLUTTER_SET_WIDGET_PROPERTY_VALUE_IS_REQUIRED error is generated.
+   *
+   * If the expression is not a syntactically valid Dart code, then
+   * FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_EXPRESSION is reported.
    */
   void set value(FlutterWidgetPropertyValue value) {
     this._value = value;
@@ -19717,6 +19723,7 @@
  *   DEBUG_PORT_COULD_NOT_BE_OPENED
  *   FILE_NOT_ANALYZED
  *   FLUTTER_GET_WIDGET_DESCRIPTION_NO_WIDGET
+ *   FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_EXPRESSION
  *   FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_ID
  *   FLUTTER_SET_WIDGET_PROPERTY_VALUE_IS_REQUIRED
  *   FORMAT_INVALID_FILE
@@ -19778,6 +19785,14 @@
       const RequestErrorCode._("FLUTTER_GET_WIDGET_DESCRIPTION_NO_WIDGET");
 
   /**
+   * The given property expression is invalid, e.g. has a syntax error.
+   */
+  static const RequestErrorCode
+      FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_EXPRESSION =
+      const RequestErrorCode._(
+          "FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_EXPRESSION");
+
+  /**
    * The given property identifier is not valid. It might have never been
    * valid, or a change to code invalidated it, or its TTL was exceeded.
    */
@@ -19985,6 +20000,7 @@
     DEBUG_PORT_COULD_NOT_BE_OPENED,
     FILE_NOT_ANALYZED,
     FLUTTER_GET_WIDGET_DESCRIPTION_NO_WIDGET,
+    FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_EXPRESSION,
     FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_ID,
     FLUTTER_SET_WIDGET_PROPERTY_VALUE_IS_REQUIRED,
     FORMAT_INVALID_FILE,
@@ -20030,6 +20046,8 @@
         return FILE_NOT_ANALYZED;
       case "FLUTTER_GET_WIDGET_DESCRIPTION_NO_WIDGET":
         return FLUTTER_GET_WIDGET_DESCRIPTION_NO_WIDGET;
+      case "FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_EXPRESSION":
+        return FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_EXPRESSION;
       case "FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_ID":
         return FLUTTER_SET_WIDGET_PROPERTY_VALUE_INVALID_ID;
       case "FLUTTER_SET_WIDGET_PROPERTY_VALUE_IS_REQUIRED":
diff --git a/pkg/analyzer/README.md b/pkg/analyzer/README.md
index 201fcca..fb43fa4 100644
--- a/pkg/analyzer/README.md
+++ b/pkg/analyzer/README.md
@@ -100,7 +100,7 @@
 [dartanalyzer]: https://github.com/dart-lang/sdk/tree/master/pkg/analyzer_cli#dartanalyzer
 [list]: https://groups.google.com/a/dartlang.org/forum/#!forum/analyzer-discuss
 [lintrules]: https://dart-lang.github.io/linter/lints/
-[glob]: https://pub.dartlang.org/packages/glob
+[glob]: https://pub.dev/packages/glob
 [LICENSE]: https://github.com/dart-lang/sdk/blob/master/pkg/analyzer/LICENSE
 [dartfmt]: https://github.com/dart-lang/dart_style
 [dartdoc]: https://github.com/dart-lang/dartdoc
diff --git a/pkg/analyzer/lib/dart/analysis/utilities.dart b/pkg/analyzer/lib/dart/analysis/utilities.dart
index ac920d1..bddafbd 100644
--- a/pkg/analyzer/lib/dart/analysis/utilities.dart
+++ b/pkg/analyzer/lib/dart/analysis/utilities.dart
@@ -99,8 +99,13 @@
 ///
 /// If [throwIfDiagnostics] is `true` (the default), then if any diagnostics are
 /// produced because of syntactic errors in the [content] an `ArgumentError`
-/// will be thrown. If the parameter is `false`, then the caller can check the
-/// result to see whether there are any `errors`.
+/// will be thrown.  This behavior is not intended as a way for the client to
+/// find out about errors--it is intended to avoid causing problems for naive
+/// clients that might not be thinking about the possibility of parse errors
+/// (and might therefore make assumptions about the returned AST that don't hold
+/// in the presence of parse errors).  Clients interested in details about parse
+/// errors should pass `false` and check `result.errors` to determine what parse
+/// errors, if any, have occurred.
 ParseStringResult parseString(
     {@required String content,
     FeatureSet featureSet,
diff --git a/pkg/analyzer/lib/dart/element/element.dart b/pkg/analyzer/lib/dart/element/element.dart
index 29038c6..059219c 100644
--- a/pkg/analyzer/lib/dart/element/element.dart
+++ b/pkg/analyzer/lib/dart/element/element.dart
@@ -38,11 +38,13 @@
 import 'package:analyzer/dart/constant/value.dart';
 import 'package:analyzer/dart/element/nullability_suffix.dart';
 import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/dart/element/type_system.dart';
 import 'package:analyzer/error/error.dart';
 import 'package:analyzer/src/dart/constant/evaluation.dart';
 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
 import 'package:analyzer/src/generated/java_engine.dart';
-import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/resolver.dart'
+    show Namespace, TypeProvider;
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
 import 'package:analyzer/src/task/api/model.dart' show AnalysisTarget;
@@ -1312,6 +1314,12 @@
   /// elements, but does not include imports, exports, or synthetic elements.
   Iterable<Element> get topLevelElements;
 
+  /// Return the [TypeProvider] that is used in this library.
+  TypeProvider get typeProvider;
+
+  /// Return the [TypeSystem] that is used in this library.
+  TypeSystem get typeSystem;
+
   /// Return a list containing all of the compilation units this library
   /// consists of. This includes the defining compilation unit and units
   /// included using the `part` directive.
@@ -1571,7 +1579,10 @@
 /// A top-level variable.
 ///
 /// Clients may not extend, implement or mix-in this class.
-abstract class TopLevelVariableElement implements PropertyInducingElement {}
+abstract class TopLevelVariableElement implements PropertyInducingElement {
+  @override
+  TopLevelVariableElement get declaration;
+}
 
 /// An element that defines a type.
 ///
diff --git a/pkg/analyzer/lib/dart/element/type.dart b/pkg/analyzer/lib/dart/element/type.dart
index 6462cde..d80c7b4 100644
--- a/pkg/analyzer/lib/dart/element/type.dart
+++ b/pkg/analyzer/lib/dart/element/type.dart
@@ -20,6 +20,7 @@
 /// type parameters. But if we declare a variable as `Pair<String, int> pair;`
 /// the references to `String` and `int` are type arguments.
 import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/nullability_suffix.dart';
 import 'package:analyzer/src/dart/element/type.dart' show InterfaceTypeImpl;
 
 /// The type associated with elements in the element model.
@@ -111,6 +112,9 @@
   /// such as when the type represents the type of an unnamed function.
   String get name;
 
+  /// Return the nullability suffix of this type.
+  NullabilitySuffix get nullabilitySuffix;
+
   /// If this type is a [TypeParameterType], returns its bound if it has one, or
   /// [objectType] otherwise.
   ///
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index 7313b18..8e471b0 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -302,6 +302,7 @@
   CompileTimeErrorCode.SUPER_IN_REDIRECTING_CONSTRUCTOR,
   CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF,
   CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS,
+  // ignore: deprecated_member_use_from_same_package
   CompileTimeErrorCode.TYPE_PARAMETER_ON_CONSTRUCTOR,
   CompileTimeErrorCode.UNDEFINED_ANNOTATION,
   CompileTimeErrorCode.UNDEFINED_CLASS,
@@ -320,6 +321,8 @@
   CompileTimeErrorCode.WRONG_NUMBER_OF_PARAMETERS_FOR_OPERATOR_MINUS,
   CompileTimeErrorCode.WRONG_NUMBER_OF_PARAMETERS_FOR_SETTER,
   CompileTimeErrorCode.WRONG_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE,
+  CompileTimeErrorCode.WRONG_TYPE_PARAMETER_VARIANCE_POSITION,
+  CompileTimeErrorCode.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE,
   CompileTimeErrorCode.YIELD_EACH_IN_NON_GENERATOR,
   CompileTimeErrorCode.YIELD_IN_NON_GENERATOR,
   FfiCode.ANNOTATION_ON_POINTER_FIELD,
@@ -627,6 +630,7 @@
   ParserErrorCode.TYPEDEF_IN_CLASS,
   ParserErrorCode.TYPE_ARGUMENTS_ON_TYPE_VARIABLE,
   ParserErrorCode.TYPE_BEFORE_FACTORY,
+  ParserErrorCode.TYPE_PARAMETER_ON_CONSTRUCTOR,
   ParserErrorCode.UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP,
   ParserErrorCode.UNEXPECTED_TOKEN,
   ParserErrorCode.VAR_AND_TYPE,
@@ -669,8 +673,11 @@
   StaticTypeWarningCode.NON_BOOL_NEGATION_EXPRESSION,
   StaticTypeWarningCode.NON_BOOL_OPERAND,
   StaticTypeWarningCode.NON_TYPE_AS_TYPE_ARGUMENT,
+  // ignore: deprecated_member_use_from_same_package
   StaticTypeWarningCode.RETURN_OF_INVALID_TYPE,
   StaticTypeWarningCode.RETURN_OF_INVALID_TYPE_FROM_CLOSURE,
+  StaticTypeWarningCode.RETURN_OF_INVALID_TYPE_FROM_FUNCTION,
+  StaticTypeWarningCode.RETURN_OF_INVALID_TYPE_FROM_METHOD,
   StaticTypeWarningCode.TYPE_PARAMETER_SUPERTYPE_OF_ITS_BOUND,
   StaticTypeWarningCode.UNDEFINED_ENUM_CONSTANT,
   StaticTypeWarningCode.UNDEFINED_FUNCTION,
diff --git a/pkg/analyzer/lib/error/listener.dart b/pkg/analyzer/lib/error/listener.dart
index 124d667..19235f8 100644
--- a/pkg/analyzer/lib/error/listener.dart
+++ b/pkg/analyzer/lib/error/listener.dart
@@ -202,7 +202,7 @@
         if (name != null && name.isNotEmpty) {
           StringBuffer buffer = new StringBuffer();
           buffer.write(name);
-          (type as TypeImpl).appendTo(buffer, new Set.identity());
+          (type as TypeImpl).appendTo(buffer);
           return buffer.toString();
         }
       }
diff --git a/pkg/analyzer/lib/exception/exception.dart b/pkg/analyzer/lib/exception/exception.dart
index e5f6335..779f27a 100644
--- a/pkg/analyzer/lib/exception/exception.dart
+++ b/pkg/analyzer/lib/exception/exception.dart
@@ -68,6 +68,19 @@
   CaughtException.withMessage(this.message, this.exception, stackTrace)
       : this.stackTrace = stackTrace ?? StackTrace.current;
 
+  /**
+   * Recursively unwrap this [CaughtException] if it itself contains a
+   * [CaughtException].
+   *
+   * If it does not contain a [CaughtException], simply return this instance.
+   */
+  CaughtException get rootCaughtException {
+    if (exception is CaughtException) {
+      return (exception as CaughtException).rootCaughtException;
+    }
+    return this;
+  }
+
   @override
   String toString() {
     StringBuffer buffer = new StringBuffer();
diff --git a/pkg/analyzer/lib/file_system/physical_file_system.dart b/pkg/analyzer/lib/file_system/physical_file_system.dart
index 83a34de..fa9ce48 100644
--- a/pkg/analyzer/lib/file_system/physical_file_system.dart
+++ b/pkg/analyzer/lib/file_system/physical_file_system.dart
@@ -262,7 +262,12 @@
   @override
   Stream<WatchEvent> get changes =>
       new DirectoryWatcher(_entry.path).events.handleError((error) {},
-          test: (error) => error is io.FileSystemException);
+          test: (error) =>
+              error is io.FileSystemException &&
+              // Don't suppress "Directory watcher closed," so the outer
+              // listener can see the interruption & act on it.
+              !error.message
+                  .startsWith("Directory watcher closed unexpectedly"));
 
   /**
    * Return the underlying file being represented by this wrapper.
diff --git a/pkg/analyzer/lib/source/line_info.dart b/pkg/analyzer/lib/source/line_info.dart
index 631029f..457f38e 100644
--- a/pkg/analyzer/lib/source/line_info.dart
+++ b/pkg/analyzer/lib/source/line_info.dart
@@ -86,7 +86,7 @@
       }
     }
 
-    // Binary search to fine the line containing this offset.
+    // Binary search to find the line containing this offset.
     while (min < max) {
       var midpoint = (max - min + 1) ~/ 2 + min;
 
diff --git a/pkg/analyzer/lib/src/context/builder.dart b/pkg/analyzer/lib/src/context/builder.dart
index eb36757..bb0b380 100644
--- a/pkg/analyzer/lib/src/context/builder.dart
+++ b/pkg/analyzer/lib/src/context/builder.dart
@@ -15,7 +15,6 @@
         applyAnalysisOptionFlags,
         bazelAnalysisOptionsPath,
         flutterAnalysisOptionsPath;
-import 'package:analyzer/src/context/context.dart';
 import 'package:analyzer/src/context/context_root.dart';
 import 'package:analyzer/src/dart/analysis/byte_store.dart';
 import 'package:analyzer/src/dart/analysis/context_root.dart' as api;
@@ -151,23 +150,6 @@
       : builderOptions = options ?? new ContextBuilderOptions();
 
   /**
-   * Return an analysis context that is configured correctly to analyze code in
-   * the directory with the given [path].
-   *
-   * *Note:* This method is not yet fully implemented and should not be used.
-   */
-  AnalysisContext buildContext(String path) {
-    InternalAnalysisContext context =
-        AnalysisEngine.instance.createAnalysisContext();
-    AnalysisOptionsImpl options = getAnalysisOptions(path);
-    context.sourceFactory = createSourceFactory(path, options);
-    context.analysisOptions = options;
-    //_processAnalysisOptions(context, optionMap);
-    declareVariables(context);
-    return context;
-  }
-
-  /**
    * Return an analysis driver that is configured correctly to analyze code in
    * the directory with the given [path].
    */
@@ -292,17 +274,6 @@
 
   /**
    * Add any [declaredVariables] to the list of declared variables used by the
-   * given [context].
-   */
-  void declareVariables(AnalysisContextImpl context) {
-    Map<String, String> variables = builderOptions.declaredVariables;
-    if (variables != null && variables.isNotEmpty) {
-      context.declaredVariables = new DeclaredVariables.fromMap(variables);
-    }
-  }
-
-  /**
-   * Add any [declaredVariables] to the list of declared variables used by the
    * given analysis [driver].
    */
   void declareVariablesInDriver(AnalysisDriver driver) {
@@ -647,23 +618,6 @@
     return null;
   }
 
-  /**
-   * Return `true` if either the directory at [rootPath] or a parent of that
-   * directory contains a `.packages` file.
-   */
-  static bool _hasPackageFileInPath(
-      ResourceProvider resourceProvider, String rootPath) {
-    Folder folder = resourceProvider.getFolder(rootPath);
-    while (folder != null) {
-      File file = folder.getChildAssumingFile('.packages');
-      if (file.exists) {
-        return true;
-      }
-      folder = folder.parent;
-    }
-    return false;
-  }
-
   static Workspace createWorkspace(ResourceProvider resourceProvider,
       String rootPath, ContextBuilder contextBuilder) {
     if (_hasPackageFileInPath(resourceProvider, rootPath)) {
@@ -683,6 +637,23 @@
     return workspace ??
         BasicWorkspace.find(resourceProvider, rootPath, contextBuilder);
   }
+
+  /**
+   * Return `true` if either the directory at [rootPath] or a parent of that
+   * directory contains a `.packages` file.
+   */
+  static bool _hasPackageFileInPath(
+      ResourceProvider resourceProvider, String rootPath) {
+    Folder folder = resourceProvider.getFolder(rootPath);
+    while (folder != null) {
+      File file = folder.getChildAssumingFile('.packages');
+      if (file.exists) {
+        return true;
+      }
+      folder = folder.parent;
+    }
+    return false;
+  }
 }
 
 /**
diff --git a/pkg/analyzer/lib/src/context/context.dart b/pkg/analyzer/lib/src/context/context.dart
index e1cdfc4..405869e 100644
--- a/pkg/analyzer/lib/src/context/context.dart
+++ b/pkg/analyzer/lib/src/context/context.dart
@@ -2,88 +2,85 @@
 // 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/dart/analysis/session.dart';
+import 'package:analyzer/src/dart/element/type_provider.dart';
 import 'package:analyzer/src/generated/constant.dart';
 import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
 import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/type_system.dart' show TypeSystemImpl;
+import 'package:meta/meta.dart';
 
 /**
  * An [AnalysisContext] in which analysis can be performed.
  */
 class AnalysisContextImpl implements InternalAnalysisContext {
-  /**
-   * The set of analysis options controlling the behavior of this context.
-   */
-  AnalysisOptionsImpl _options = new AnalysisOptionsImpl();
-
-  /**
-   * The source factory used to create the sources that can be analyzed in this
-   * context.
-   */
-  SourceFactory _sourceFactory;
-
-  /**
-   * The set of declared variables used when computing constant values.
-   */
-  DeclaredVariables _declaredVariables = new DeclaredVariables();
-
-  /**
-   * The [TypeProvider] for this context, `null` if not yet created.
-   */
-  TypeProvider _typeProvider;
-
-  /**
-   * The [TypeSystem] for this context, `null` if not yet created.
-   */
-  TypeSystem _typeSystem;
-
-  /**
-   * Initialize a newly created analysis context.
-   */
-  AnalysisContextImpl();
+  final SynchronousSession _synchronousSession;
 
   @override
-  AnalysisOptions get analysisOptions => _options;
+  final SourceFactory sourceFactory;
+
+  AnalysisContextImpl(this._synchronousSession, this.sourceFactory);
+
+  @override
+  AnalysisOptionsImpl get analysisOptions {
+    return _synchronousSession.analysisOptions;
+  }
 
   @override
   void set analysisOptions(AnalysisOptions options) {
-    this._options = options;
+    throw StateError('Cannot be changed.');
   }
 
   @override
-  DeclaredVariables get declaredVariables => _declaredVariables;
-
-  /**
-   * Set the declared variables to the give collection of declared [variables].
-   */
-  void set declaredVariables(DeclaredVariables variables) {
-    _declaredVariables = variables;
+  DeclaredVariables get declaredVariables {
+    return _synchronousSession.declaredVariables;
   }
 
   @override
-  SourceFactory get sourceFactory => _sourceFactory;
-
-  @override
   void set sourceFactory(SourceFactory factory) {
-    _sourceFactory = factory;
+    throw StateError('Cannot be changed.');
   }
 
   @override
   TypeProvider get typeProvider {
-    return _typeProvider;
+    return _synchronousSession.typeProvider;
   }
 
-  /**
-   * Sets the [TypeProvider] for this context.
-   */
-  @override
-  void set typeProvider(TypeProvider typeProvider) {
-    _typeProvider = typeProvider;
+  TypeProviderImpl get typeProviderLegacy {
+    return _synchronousSession.typeProviderLegacy;
+  }
+
+  TypeProviderImpl get typeProviderNonNullableByDefault {
+    return _synchronousSession.typeProviderNonNullableByDefault;
   }
 
   @override
-  TypeSystem get typeSystem {
-    return _typeSystem ??= Dart2TypeSystem(typeProvider);
+  TypeSystemImpl get typeSystem {
+    return _synchronousSession.typeSystem;
+  }
+
+  TypeSystemImpl get typeSystemLegacy {
+    return _synchronousSession.typeSystemLegacy;
+  }
+
+  TypeSystemImpl get typeSystemNonNullableByDefault {
+    return _synchronousSession.typeSystemNonNullableByDefault;
+  }
+
+  void clearTypeProvider() {
+    _synchronousSession.clearTypeProvider();
+  }
+
+  @override
+  void setTypeProviders({
+    @required TypeProvider legacy,
+    @required TypeProvider nonNullableByDefault,
+  }) {
+    _synchronousSession.setTypeProviders(
+      legacy: legacy,
+      nonNullableByDefault: nonNullableByDefault,
+    );
   }
 }
 
@@ -96,14 +93,6 @@
    * Analysis options cannot be changed afterwards.  If the given [options] are
    * `null`, then default options are used.
    */
-  SdkAnalysisContext(AnalysisOptions options) {
-    if (options != null) {
-      super.analysisOptions = options;
-    }
-  }
-
-  @override
-  void set analysisOptions(AnalysisOptions options) {
-    throw new StateError('AnalysisOptions of SDK context cannot be changed.');
-  }
+  SdkAnalysisContext(AnalysisOptions options, SourceFactory sourceFactory)
+      : super(SynchronousSession(options, DeclaredVariables()), sourceFactory);
 }
diff --git a/pkg/analyzer/lib/src/dart/analysis/ddc.dart b/pkg/analyzer/lib/src/dart/analysis/ddc.dart
index c86790c..03670cb 100644
--- a/pkg/analyzer/lib/src/dart/analysis/ddc.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/ddc.dart
@@ -6,10 +6,9 @@
 
 import 'package:analyzer/dart/analysis/declared_variables.dart';
 import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/src/context/context.dart';
 import 'package:analyzer/src/dart/analysis/file_state.dart';
-import 'package:analyzer/src/dart/analysis/restricted_analysis_context.dart';
 import 'package:analyzer/src/dart/analysis/session.dart';
-import 'package:analyzer/src/dart/element/type_provider.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
@@ -38,7 +37,7 @@
   final PackageBundleAssembler _assembler;
   List<int> summaryBytes;
 
-  RestrictedAnalysisContext context;
+  AnalysisContextImpl context;
   summary2.LinkedElementFactory elementFactory;
 
   DevCompilerResynthesizerBuilder({
@@ -80,7 +79,7 @@
       _analysisOptions,
       _declaredVariables,
     );
-    context = RestrictedAnalysisContext(synchronousSession, _sourceFactory);
+    context = AnalysisContextImpl(synchronousSession, _sourceFactory);
 
     _createElementFactory(bundle);
   }
@@ -157,7 +156,7 @@
       );
     }
 
-    var analysisContext = RestrictedAnalysisContext(
+    var analysisContext = AnalysisContextImpl(
       SynchronousSession(_analysisOptions, _declaredVariables),
       _sourceFactory,
     );
@@ -203,11 +202,7 @@
 
     var dartCore = elementFactory.libraryOfUri('dart:core');
     var dartAsync = elementFactory.libraryOfUri('dart:async');
-    var typeProvider = TypeProviderImpl(dartCore, dartAsync);
-    context.typeProvider = typeProvider;
-
-    dartCore.createLoadLibraryFunction(typeProvider);
-    dartAsync.createLoadLibraryFunction(typeProvider);
+    elementFactory.createTypeProviders(dartCore, dartAsync);
   }
 }
 
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index bdbcc87..709e2acf 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -89,7 +89,7 @@
 /// TODO(scheglov) Clean up the list of implicitly analyzed files.
 class AnalysisDriver implements AnalysisDriverGeneric {
   /// The version of data format, should be incremented on every format change.
-  static const int DATA_VERSION = 89;
+  static const int DATA_VERSION = 90;
 
   /// The number of exception contexts allowed to write. Once this field is
   /// zero, we stop writing any new exception contexts in this process.
@@ -946,6 +946,7 @@
         _requestedFiles.remove(path).forEach((completer) {
           completer.completeError(exception, stackTrace);
         });
+        _clearLibraryContextAfterException();
       }
       return;
     }
@@ -962,6 +963,7 @@
         _requestedLibraries.remove(path).forEach((completer) {
           completer.completeError(exception, stackTrace);
         });
+        _clearLibraryContextAfterException();
       }
       return;
     }
@@ -1052,6 +1054,7 @@
             }
           } catch (exception, stackTrace) {
             _reportException(path, exception, stackTrace);
+            _clearLibraryContextAfterException();
           } finally {
             _fileTracker.fileWasAnalyzed(path);
           }
@@ -1077,6 +1080,7 @@
         }
       } catch (exception, stackTrace) {
         _reportException(path, exception, stackTrace);
+        _clearLibraryContextAfterException();
       } finally {
         _fileTracker.fileWasAnalyzed(path);
       }
@@ -1101,6 +1105,7 @@
         _requestedParts.remove(path).forEach((completer) {
           completer.completeError(exception, stackTrace);
         });
+        _clearLibraryContextAfterException();
       }
       return;
     }
@@ -1116,6 +1121,7 @@
         _resultController.add(result);
       } catch (exception, stackTrace) {
         _reportException(path, exception, stackTrace);
+        _clearLibraryContextAfterException();
       }
       return;
     }
@@ -1182,6 +1188,14 @@
     _scheduler.notify(this);
   }
 
+  /// There was an exception during a file analysis, we don't know why.
+  /// But it might have been caused by an inconsistency of files state, and
+  /// the library context state. Reset the library context, and hope that
+  /// we will solve the inconsistency while loading / building summaries.
+  void _clearLibraryContextAfterException() {
+    _libraryContext = null;
+  }
+
   /// Return the cached or newly computed analysis result of the file with the
   /// given [path].
   ///
@@ -2008,7 +2022,7 @@
   TypeProvider get typeProvider => unit.declaredElement.context.typeProvider;
 
   @override
-  TypeSystem get typeSystem => unit.declaredElement.context.typeSystem;
+  TypeSystemImpl get typeSystem => unit.declaredElement.context.typeSystem;
 }
 
 class DriverPerformance {
diff --git a/pkg/analyzer/lib/src/dart/analysis/experiments.g.dart b/pkg/analyzer/lib/src/dart/analysis/experiments.g.dart
index d4c2171..714dc6b 100644
--- a/pkg/analyzer/lib/src/dart/analysis/experiments.g.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/experiments.g.dart
@@ -13,6 +13,8 @@
       ExperimentalFeatures.control_flow_collections,
   EnableString.extension_methods: ExperimentalFeatures.extension_methods,
   EnableString.non_nullable: ExperimentalFeatures.non_nullable,
+  EnableString.nonfunction_type_aliases:
+      ExperimentalFeatures.nonfunction_type_aliases,
   EnableString.set_literals: ExperimentalFeatures.set_literals,
   EnableString.spread_collections: ExperimentalFeatures.spread_collections,
   EnableString.triple_shift: ExperimentalFeatures.triple_shift,
@@ -29,6 +31,7 @@
       true, // control-flow-collections
       true, // extension-methods
       IsEnabledByDefault.non_nullable,
+      IsEnabledByDefault.nonfunction_type_aliases,
       true, // set-literals
       true, // spread-collections
       IsEnabledByDefault.triple_shift,
@@ -52,6 +55,9 @@
   /// String to enable the experiment "non-nullable"
   static const String non_nullable = 'non-nullable';
 
+  /// String to enable the experiment "nonfunction-type-aliases"
+  static const String nonfunction_type_aliases = 'nonfunction-type-aliases';
+
   /// String to enable the experiment "set-literals"
   static const String set_literals = 'set-literals';
 
@@ -105,8 +111,15 @@
       IsExpired.non_nullable,
       'Non Nullable by default');
 
-  static const set_literals = const ExperimentalFeature(
+  static const nonfunction_type_aliases = const ExperimentalFeature(
       4,
+      EnableString.nonfunction_type_aliases,
+      IsEnabledByDefault.nonfunction_type_aliases,
+      IsExpired.nonfunction_type_aliases,
+      'Type aliases define a <type>, not just a <functionType>.');
+
+  static const set_literals = const ExperimentalFeature(
+      5,
       EnableString.set_literals,
       IsEnabledByDefault.set_literals,
       IsExpired.set_literals,
@@ -114,7 +127,7 @@
       firstSupportedVersion: '2.2.0');
 
   static const spread_collections = const ExperimentalFeature(
-      5,
+      6,
       EnableString.spread_collections,
       IsEnabledByDefault.spread_collections,
       IsExpired.spread_collections,
@@ -122,18 +135,18 @@
       firstSupportedVersion: '2.2.2');
 
   static const triple_shift = const ExperimentalFeature(
-      6,
+      7,
       EnableString.triple_shift,
       IsEnabledByDefault.triple_shift,
       IsExpired.triple_shift,
       'Triple-shift operator');
 
-  static const variance = const ExperimentalFeature(7, EnableString.variance,
+  static const variance = const ExperimentalFeature(8, EnableString.variance,
       IsEnabledByDefault.variance, IsExpired.variance, 'Sound variance.');
 
   @deprecated
   static const bogus_disabled = const ExperimentalFeature(
-      8,
+      9,
       // ignore: deprecated_member_use_from_same_package
       EnableString.bogus_disabled,
       IsEnabledByDefault.bogus_disabled,
@@ -142,7 +155,7 @@
 
   @deprecated
   static const bogus_enabled = const ExperimentalFeature(
-      9,
+      10,
       // ignore: deprecated_member_use_from_same_package
       EnableString.bogus_enabled,
       IsEnabledByDefault.bogus_enabled,
@@ -166,6 +179,9 @@
   /// Default state of the experiment "non-nullable"
   static const bool non_nullable = false;
 
+  /// Default state of the experiment "nonfunction-type-aliases"
+  static const bool nonfunction_type_aliases = false;
+
   /// Default state of the experiment "set-literals"
   static const bool set_literals = true;
 
@@ -203,6 +219,9 @@
   /// Expiration status of the experiment "non-nullable"
   static const bool non_nullable = false;
 
+  /// Expiration status of the experiment "nonfunction-type-aliases"
+  static const bool nonfunction_type_aliases = false;
+
   /// Expiration status of the experiment "set-literals"
   static const bool set_literals = true;
 
@@ -246,6 +265,10 @@
   /// Current state for the flag "non-nullable"
   bool get non_nullable => isEnabled(ExperimentalFeatures.non_nullable);
 
+  /// Current state for the flag "nonfunction-type-aliases"
+  bool get nonfunction_type_aliases =>
+      isEnabled(ExperimentalFeatures.nonfunction_type_aliases);
+
   /// Current state for the flag "set-literals"
   bool get set_literals => isEnabled(ExperimentalFeatures.set_literals);
 
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
index 527a5a2..10b10fb 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
@@ -7,7 +7,6 @@
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/dart/element/nullability_suffix.dart';
 import 'package:analyzer/error/error.dart';
 import 'package:analyzer/error/listener.dart';
 import 'package:analyzer/file_system/file_system.dart';
@@ -72,7 +71,7 @@
   final LinkedElementFactory _elementFactory;
   TypeProviderImpl _typeProvider;
 
-  final TypeSystem _typeSystem;
+  final TypeSystemImpl _typeSystem;
   LibraryElement _libraryElement;
 
   LibraryScope _libraryScope;
@@ -135,9 +134,9 @@
     FeatureSet featureSet = units[_library].featureSet;
     _typeProvider = _context.typeProvider;
     if (featureSet.isEnabled(Feature.non_nullable)) {
-      _typeProvider = _typeProvider.withNullability(NullabilitySuffix.none);
+      _typeProvider = _typeProvider.asNonNullableByDefault;
     } else {
-      _typeProvider = _typeProvider.withNullability(NullabilitySuffix.star);
+      _typeProvider = _typeProvider.asLegacy;
     }
     units.forEach((file, unit) {
       _validateFeatureSet(unit, featureSet);
@@ -295,8 +294,8 @@
     {
       UsedLocalElements usedElements =
           new UsedLocalElements.merge(_usedLocalElementsList);
-      UnusedLocalElementsVerifier visitor =
-          new UnusedLocalElementsVerifier(errorListener, usedElements);
+      UnusedLocalElementsVerifier visitor = new UnusedLocalElementsVerifier(
+          errorListener, usedElements, _inheritance, _libraryElement);
       unit.accept(visitor);
     }
 
@@ -430,8 +429,17 @@
 
     bool isIgnored(AnalysisError error) {
       int errorLine = lineInfo.getLocation(error.offset).lineNumber;
-      String errorCode = error.errorCode.name.toLowerCase();
-      return ignoreInfo.ignoredAt(errorCode, errorLine);
+      String name = error.errorCode.name.toLowerCase();
+      if (ignoreInfo.ignoredAt(name, errorLine)) {
+        return true;
+      }
+      String uniqueName = error.errorCode.uniqueName;
+      int period = uniqueName.indexOf('.');
+      if (period >= 0) {
+        uniqueName = uniqueName.substring(period + 1);
+      }
+      return uniqueName != name &&
+          ignoreInfo.ignoredAt(uniqueName.toLowerCase(), errorLine);
     }
 
     return errors.where((AnalysisError e) => !isIgnored(e)).toList();
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_context.dart b/pkg/analyzer/lib/src/dart/analysis/library_context.dart
index 6998356..4bb8489 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_context.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_context.dart
@@ -6,15 +6,14 @@
 import 'package:analyzer/dart/analysis/session.dart';
 import 'package:analyzer/dart/element/element.dart'
     show CompilationUnitElement, LibraryElement;
+import 'package:analyzer/src/context/context.dart';
 import 'package:analyzer/src/dart/analysis/byte_store.dart';
 import 'package:analyzer/src/dart/analysis/driver.dart';
 import 'package:analyzer/src/dart/analysis/file_state.dart';
 import 'package:analyzer/src/dart/analysis/library_graph.dart';
 import 'package:analyzer/src/dart/analysis/performance_logger.dart';
-import 'package:analyzer/src/dart/analysis/restricted_analysis_context.dart';
 import 'package:analyzer/src/dart/analysis/session.dart';
 import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
-import 'package:analyzer/src/dart/element/type_provider.dart';
 import 'package:analyzer/src/generated/engine.dart'
     show AnalysisContext, AnalysisOptions;
 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
@@ -54,7 +53,7 @@
   /// We use it as an approximation for the heap size of elements.
   int _linkedDataInBytes = 0;
 
-  RestrictedAnalysisContext analysisContext;
+  AnalysisContextImpl analysisContext;
   LinkedElementFactory elementFactory;
   InheritanceManager3 inheritanceManager;
 
@@ -75,15 +74,12 @@
         this.analysisSession = session {
     var synchronousSession =
         SynchronousSession(analysisOptions, declaredVariables);
-    analysisContext = new RestrictedAnalysisContext(
-      synchronousSession,
-      sourceFactory,
-    );
+    analysisContext = AnalysisContextImpl(synchronousSession, sourceFactory);
 
     _createElementFactory();
     load2(targetLibrary);
 
-    inheritanceManager = new InheritanceManager3(analysisContext.typeSystem);
+    inheritanceManager = new InheritanceManager3();
   }
 
   /**
@@ -281,10 +277,6 @@
 
     var dartCore = elementFactory.libraryOfUri('dart:core');
     var dartAsync = elementFactory.libraryOfUri('dart:async');
-    var typeProvider = TypeProviderImpl(dartCore, dartAsync);
-    analysisContext.typeProvider = typeProvider;
-
-    dartCore.createLoadLibraryFunction(typeProvider);
-    dartAsync.createLoadLibraryFunction(typeProvider);
+    elementFactory.createTypeProviders(dartCore, dartAsync);
   }
 }
diff --git a/pkg/analyzer/lib/src/dart/analysis/restricted_analysis_context.dart b/pkg/analyzer/lib/src/dart/analysis/restricted_analysis_context.dart
deleted file mode 100644
index 60b7db7..0000000
--- a/pkg/analyzer/lib/src/dart/analysis/restricted_analysis_context.dart
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright (c) 2018, 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/analysis/declared_variables.dart';
-import 'package:analyzer/src/context/context.dart';
-import 'package:analyzer/src/dart/analysis/session.dart';
-import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/resolver.dart';
-import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/generated/type_system.dart';
-
-/// This class is a temporary step toward migrating Analyzer clients to the
-/// new API.  It guards against attempts to use any [AnalysisContext]
-/// functionality (which is task based), except what we intend to expose
-/// through the new API.
-class RestrictedAnalysisContext implements AnalysisContextImpl {
-  final SynchronousSession synchronousSession;
-
-  @override
-  final SourceFactory sourceFactory;
-
-  RestrictedAnalysisContext(this.synchronousSession, this.sourceFactory);
-
-  @override
-  AnalysisOptionsImpl get analysisOptions => synchronousSession.analysisOptions;
-
-  @override
-  DeclaredVariables get declaredVariables =>
-      synchronousSession.declaredVariables;
-
-  @override
-  TypeProvider get typeProvider => synchronousSession.typeProvider;
-
-  @override
-  set typeProvider(TypeProvider typeProvider) {
-    synchronousSession.typeProvider = typeProvider;
-  }
-
-  @override
-  TypeSystem get typeSystem => synchronousSession.typeSystem;
-
-  noSuchMethod(Invocation invocation) {
-    return super.noSuchMethod(invocation);
-  }
-
-  void clearTypeProvider() {
-    synchronousSession.clearTypeProvider();
-  }
-}
diff --git a/pkg/analyzer/lib/src/dart/analysis/results.dart b/pkg/analyzer/lib/src/dart/analysis/results.dart
index da2e4d0..0011291 100644
--- a/pkg/analyzer/lib/src/dart/analysis/results.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/results.dart
@@ -235,7 +235,7 @@
   TypeProvider get typeProvider => unit.declaredElement.context.typeProvider;
 
   @override
-  TypeSystem get typeSystem => unit.declaredElement.context.typeSystem;
+  TypeSystemImpl get typeSystem => unit.declaredElement.context.typeSystem;
 }
 
 class UnitElementResultImpl extends AnalysisResultImpl
diff --git a/pkg/analyzer/lib/src/dart/analysis/session.dart b/pkg/analyzer/lib/src/dart/analysis/session.dart
index f090722..f4139fe 100644
--- a/pkg/analyzer/lib/src/dart/analysis/session.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/session.dart
@@ -17,6 +17,7 @@
 import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl;
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/generated/source.dart';
+import 'package:meta/meta.dart';
 
 /// A concrete implementation of an analysis session.
 class AnalysisSessionImpl implements AnalysisSession {
@@ -27,7 +28,7 @@
   TypeProvider _typeProvider;
 
   /// The type system being used by the analysis driver.
-  TypeSystem _typeSystem;
+  TypeSystemImpl _typeSystem;
 
   /// The URI converter used to convert between URI's and file paths.
   UriConverter _uriConverter;
@@ -58,18 +59,28 @@
     if (_typeProvider == null) {
       LibraryElement coreLibrary = await _driver.getLibraryByUri('dart:core');
       LibraryElement asyncLibrary = await _driver.getLibraryByUri('dart:async');
-      _typeProvider = new TypeProviderImpl(coreLibrary, asyncLibrary);
+      _typeProvider = new TypeProviderImpl(
+        coreLibrary: coreLibrary,
+        asyncLibrary: asyncLibrary,
+        isNonNullableByDefault: false,
+      );
     }
     return _typeProvider;
   }
 
   @override
-  Future<TypeSystem> get typeSystem async {
+  Future<TypeSystemImpl> get typeSystem async {
     // TODO(brianwilkerson) Determine whether this await is necessary.
     await null;
     _checkConsistency();
     if (_typeSystem == null) {
-      _typeSystem = new Dart2TypeSystem(await typeProvider);
+      var typeProvider = await this.typeProvider;
+      _typeSystem = TypeSystemImpl(
+        implicitCasts: true,
+        isNonNullableByDefault: false,
+        strictInference: false,
+        typeProvider: typeProvider,
+      );
     }
     return _typeSystem;
   }
@@ -200,31 +211,68 @@
 
   final DeclaredVariables declaredVariables;
 
-  TypeProvider _typeProvider;
+  TypeProvider _typeProviderLegacy;
+  TypeProvider _typeProviderNonNullableByDefault;
 
-  TypeSystem _typeSystem;
+  TypeSystemImpl _typeSystemLegacy;
+  TypeSystemImpl _typeSystemNonNullableByDefault;
 
   SynchronousSession(this.analysisOptions, this.declaredVariables);
 
-  TypeProvider get typeProvider => _typeProvider;
+  TypeProvider get typeProvider => _typeProviderLegacy;
 
-  set typeProvider(TypeProvider typeProvider) {
-    if (_typeProvider != null) {
-      throw StateError('TypeProvider can be set only once.');
-    }
-    _typeProvider = typeProvider;
+  TypeProvider get typeProviderLegacy {
+    return _typeProviderLegacy;
   }
 
-  TypeSystem get typeSystem {
-    return _typeSystem ??= Dart2TypeSystem(
-      typeProvider,
-      implicitCasts: analysisOptions.implicitCasts,
-      strictInference: analysisOptions.strictInference,
-    );
+  TypeProvider get typeProviderNonNullableByDefault {
+    return _typeProviderNonNullableByDefault;
+  }
+
+  TypeSystemImpl get typeSystem {
+    return typeSystemLegacy;
+  }
+
+  TypeSystemImpl get typeSystemLegacy {
+    return _typeSystemLegacy;
+  }
+
+  TypeSystemImpl get typeSystemNonNullableByDefault {
+    return _typeSystemNonNullableByDefault;
   }
 
   void clearTypeProvider() {
-    _typeProvider = null;
-    _typeSystem = null;
+    _typeProviderLegacy = null;
+    _typeProviderNonNullableByDefault = null;
+
+    _typeSystemLegacy = null;
+    _typeSystemNonNullableByDefault = null;
+  }
+
+  void setTypeProviders({
+    @required TypeProvider legacy,
+    @required TypeProvider nonNullableByDefault,
+  }) {
+    if (_typeProviderLegacy != null ||
+        _typeProviderNonNullableByDefault != null) {
+      throw StateError('TypeProvider(s) can be set only once.');
+    }
+
+    _typeProviderLegacy = legacy;
+    _typeProviderNonNullableByDefault = nonNullableByDefault;
+
+    _typeSystemLegacy = TypeSystemImpl(
+      implicitCasts: analysisOptions.implicitCasts,
+      isNonNullableByDefault: false,
+      strictInference: analysisOptions.strictInference,
+      typeProvider: _typeProviderLegacy,
+    );
+
+    _typeSystemNonNullableByDefault = TypeSystemImpl(
+      implicitCasts: analysisOptions.implicitCasts,
+      isNonNullableByDefault: true,
+      strictInference: analysisOptions.strictInference,
+      typeProvider: _typeProviderNonNullableByDefault,
+    );
   }
 }
diff --git a/pkg/analyzer/lib/src/dart/ast/ast_factory.dart b/pkg/analyzer/lib/src/dart/ast/ast_factory.dart
index 9b2cc48..a4aba0d 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast_factory.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast_factory.dart
@@ -1030,6 +1030,16 @@
           SimpleIdentifier name, Token extendsKeyword, TypeAnnotation bound) =>
       new TypeParameterImpl(comment, metadata, name, extendsKeyword, bound);
 
+  TypeParameter typeParameter2(
+          {Comment comment,
+          List<Annotation> metadata,
+          SimpleIdentifier name,
+          Token extendsKeyword,
+          TypeAnnotation bound,
+          Token varianceKeyword}) =>
+      new TypeParameterImpl(comment, metadata, name, extendsKeyword, bound)
+        ..varianceKeyword = varianceKeyword;
+
   @override
   TypeParameterList typeParameterList(Token leftBracket,
           List<TypeParameter> typeParameters, Token rightBracket) =>
diff --git a/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart b/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart
index 7cd5a86..1f5145f 100644
--- a/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart
@@ -4,6 +4,7 @@
 
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/src/dart/ast/ast.dart';
 import 'package:meta/meta.dart';
 
 /**
@@ -1127,6 +1128,11 @@
   @override
   void visitTypeParameter(TypeParameter node) {
     safelyVisitNodeListWithSeparatorAndSuffix(node.metadata, " ", " ");
+    // TODO (kallentu) : Clean up TypeParameterImpl casting once variance is
+    // added to the interface.
+    if ((node as TypeParameterImpl).varianceKeyword != null) {
+      sink.write((node as TypeParameterImpl).varianceKeyword.lexeme + ' ');
+    }
     safelyVisitNode(node.name);
     safelyVisitNodeWithPrefix(" extends ", node.bound);
   }
diff --git a/pkg/analyzer/lib/src/dart/ast/utilities.dart b/pkg/analyzer/lib/src/dart/ast/utilities.dart
index 95d8752..284ccb1 100644
--- a/pkg/analyzer/lib/src/dart/ast/utilities.dart
+++ b/pkg/analyzer/lib/src/dart/ast/utilities.dart
@@ -10,6 +10,7 @@
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/exception/exception.dart';
 import 'package:analyzer/src/dart/ast/ast.dart';
+import 'package:analyzer/src/dart/ast/ast_factory.dart';
 import 'package:analyzer/src/dart/ast/to_source_visitor.dart';
 import 'package:analyzer/src/dart/ast/token.dart';
 import 'package:analyzer/src/generated/engine.dart' show AnalysisEngine;
@@ -1019,12 +1020,16 @@
 
   @override
   TypeParameter visitTypeParameter(TypeParameter node) =>
-      astFactory.typeParameter(
-          cloneNode(node.documentationComment),
-          cloneNodeList(node.metadata),
-          cloneNode(node.name),
-          cloneToken(node.extendsKeyword),
-          cloneNode(node.bound));
+      // TODO (kallentu) : Clean up TypeParameterImpl and AstFactoryImpl casting
+      // once variance is added to the interface.
+      (astFactory as AstFactoryImpl).typeParameter2(
+          comment: cloneNode(node.documentationComment),
+          metadata: cloneNodeList(node.metadata),
+          name: cloneNode(node.name),
+          extendsKeyword: cloneToken(node.extendsKeyword),
+          bound: cloneNode(node.bound),
+          varianceKeyword:
+              cloneToken((node as TypeParameterImpl).varianceKeyword));
 
   @override
   TypeParameterList visitTypeParameterList(TypeParameterList node) =>
@@ -2269,10 +2274,14 @@
   @override
   bool visitTypeParameter(TypeParameter node) {
     TypeParameter other = _other as TypeParameter;
+    // TODO (kallentu) : Clean up TypeParameterImpl casting once variance is
+    // added to the interface.
     return isEqualNodes(
             node.documentationComment, other.documentationComment) &&
         _isEqualNodeLists(node.metadata, other.metadata) &&
         isEqualNodes(node.name, other.name) &&
+        isEqualTokens((node as TypeParameterImpl).varianceKeyword,
+            (other as TypeParameterImpl).varianceKeyword) &&
         isEqualTokens(node.extendsKeyword, other.extendsKeyword) &&
         isEqualNodes(node.bound, other.bound);
   }
@@ -5413,10 +5422,14 @@
   @override
   bool visitTypeParameter(TypeParameter node) {
     TypeParameter toNode = this._toNode as TypeParameter;
+    // TODO (kallentu) : Clean up TypeParameterImpl casting once variance is
+    // added to the interface.
     return _and(
         _isEqualNodes(node.documentationComment, toNode.documentationComment),
         _isEqualNodeLists(node.metadata, toNode.metadata),
         _isEqualNodes(node.name, toNode.name),
+        _isEqualTokens((node as TypeParameterImpl).varianceKeyword,
+            (toNode as TypeParameterImpl).varianceKeyword),
         _isEqualTokens(node.extendsKeyword, toNode.extendsKeyword),
         _isEqualNodes(node.bound, toNode.bound));
   }
diff --git a/pkg/analyzer/lib/src/dart/constant/compute.dart b/pkg/analyzer/lib/src/dart/constant/compute.dart
index 3fc6ca9..cfef338 100644
--- a/pkg/analyzer/lib/src/dart/constant/compute.dart
+++ b/pkg/analyzer/lib/src/dart/constant/compute.dart
@@ -6,15 +6,15 @@
 import 'package:analyzer/src/dart/analysis/experiments.dart';
 import 'package:analyzer/src/dart/constant/evaluation.dart';
 import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/generated/resolver.dart'
-    show TypeProvider, TypeSystem;
+import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
+import 'package:analyzer/src/generated/type_system.dart' show TypeSystemImpl;
 import 'package:analyzer/src/summary/link.dart' as graph
     show DependencyWalker, Node;
 
 /// Compute values of the given [constants] with correct ordering.
 void computeConstants(
     TypeProvider typeProvider,
-    TypeSystem typeSystem,
+    TypeSystemImpl typeSystem,
     DeclaredVariables declaredVariables,
     List<ConstantEvaluationTarget> constants,
     ExperimentStatus experimentStatus) {
diff --git a/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart b/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart
index 0d81332..7b91b96 100644
--- a/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart
+++ b/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart
@@ -10,6 +10,7 @@
 import 'package:analyzer/dart/constant/value.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/dart/element/type_system.dart';
 import 'package:analyzer/error/error.dart';
 import 'package:analyzer/error/listener.dart';
 import 'package:analyzer/src/dart/ast/utilities.dart';
@@ -20,7 +21,7 @@
 import 'package:analyzer/src/diagnostic/diagnostic_factory.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
 
 /// Instances of the class `ConstantVerifier` traverse an AST structure looking
 /// for additional errors and warnings not covered by the parser and resolver.
diff --git a/pkg/analyzer/lib/src/dart/constant/evaluation.dart b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
index dda42f3..ffae190 100644
--- a/pkg/analyzer/lib/src/dart/constant/evaluation.dart
+++ b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
@@ -13,6 +13,7 @@
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/nullability_suffix.dart';
 import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/dart/element/type_system.dart';
 import 'package:analyzer/error/error.dart';
 import 'package:analyzer/error/listener.dart';
 import 'package:analyzer/src/dart/analysis/experiments.dart';
@@ -26,8 +27,7 @@
 import 'package:analyzer/src/generated/engine.dart'
     show AnalysisEngine, RecordingErrorListener;
 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
-import 'package:analyzer/src/generated/type_system.dart'
-    show Dart2TypeSystem, TypeSystem;
+import 'package:analyzer/src/generated/type_system.dart' show TypeSystemImpl;
 import 'package:analyzer/src/task/api/model.dart';
 
 /// Helper class encapsulating the methods for evaluating constants and
@@ -90,7 +90,13 @@
       : typeProvider = typeProvider,
         validator =
             validator ?? new ConstantEvaluationValidator_ForProduction(),
-        typeSystem = typeSystem ?? new Dart2TypeSystem(typeProvider),
+        typeSystem = typeSystem ??
+            TypeSystemImpl(
+              implicitCasts: true,
+              isNonNullableByDefault: false,
+              strictInference: false,
+              typeProvider: typeProvider,
+            ),
         experimentStatus = experimentStatus ?? new ExperimentStatus();
 
   /// Check that the arguments to a call to fromEnvironment() are correct. The
@@ -1127,7 +1133,7 @@
     ParameterizedType thenType = thenResult.type;
     ParameterizedType elseType = elseResult.type;
     return new DartObjectImpl.validWithUnknownValue(
-        typeSystem.getLeastUpperBound(thenType, elseType) as ParameterizedType);
+        typeSystem.leastUpperBound(thenType, elseType) as ParameterizedType);
   }
 
   @override
@@ -1260,14 +1266,16 @@
     SimpleIdentifier prefixNode = node.prefix;
     Element prefixElement = prefixNode.staticElement;
     // String.length
-    if (prefixElement is! PrefixElement && prefixElement is! ClassElement) {
+    if (prefixElement is! PrefixElement &&
+        prefixElement is! ClassElement &&
+        prefixElement is! ExtensionElement) {
       DartObjectImpl prefixResult = prefixNode.accept(this);
       if (_isStringLength(prefixResult, node.identifier)) {
         return prefixResult.stringLength(_typeProvider);
       }
     }
     // importPrefix.CONST
-    if (prefixElement is! PrefixElement) {
+    if (prefixElement is! PrefixElement && prefixElement is! ExtensionElement) {
       DartObjectImpl prefixResult = prefixNode.accept(this);
       if (prefixResult == null) {
         // The error has already been reported.
diff --git a/pkg/analyzer/lib/src/dart/constant/value.dart b/pkg/analyzer/lib/src/dart/constant/value.dart
index 6658568..c3bbde2 100644
--- a/pkg/analyzer/lib/src/dart/constant/value.dart
+++ b/pkg/analyzer/lib/src/dart/constant/value.dart
@@ -8,10 +8,10 @@
 import 'package:analyzer/dart/constant/value.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/dart/element/type_system.dart';
 import 'package:analyzer/error/error.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
-import 'package:analyzer/src/generated/type_system.dart';
 import 'package:analyzer/src/generated/utilities_general.dart';
 
 /// The state of an object representing a boolean value.
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index da91d96..3de7141 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -17,6 +17,7 @@
 import 'package:analyzer/src/dart/constant/value.dart';
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/type_algebra.dart';
+import 'package:analyzer/src/dart/element/type_provider.dart';
 import 'package:analyzer/src/dart/resolver/variance.dart';
 import 'package:analyzer/src/generated/constant.dart' show EvaluationResultImpl;
 import 'package:analyzer/src/generated/engine.dart'
@@ -58,9 +59,6 @@
       ElementImpl enclosing, Reference reference, AstNode linkedNode)
       : super.forLinkedNode(enclosing, reference, linkedNode);
 
-  /// Initialize a newly created class element to have the given [name].
-  AbstractClassElementImpl.forNode(Identifier name) : super.forNode(name);
-
   /// Initialize using the given serialized information.
   AbstractClassElementImpl.forSerialized(
       CompilationUnitElementImpl enclosingUnit)
@@ -456,9 +454,6 @@
       Reference reference, AstNode linkedNode)
       : super.forLinkedNode(enclosing, reference, linkedNode);
 
-  /// Initialize a newly created class element to have the given [name].
-  ClassElementImpl.forNode(Identifier name) : super.forNode(name);
-
   @override
   List<PropertyAccessorElement> get accessors {
     if (_accessors != null) return _accessors;
@@ -1787,9 +1782,6 @@
   ConstFieldElementImpl.forLinkedNode(
       ElementImpl enclosing, Reference reference, AstNode linkedNode)
       : super.forLinkedNode(enclosing, reference, linkedNode);
-
-  /// Initialize a newly created field element to have the given [name].
-  ConstFieldElementImpl.forNode(Identifier name) : super.forNode(name);
 }
 
 /// A field element representing an enum constant.
@@ -1937,10 +1929,6 @@
   /// Initialize a newly created local variable element to have the given [name]
   /// and [offset].
   ConstLocalVariableElementImpl(String name, int offset) : super(name, offset);
-
-  /// Initialize a newly created local variable element to have the given
-  /// [name].
-  ConstLocalVariableElementImpl.forNode(Identifier name) : super.forNode(name);
 }
 
 /// A concrete implementation of a [ConstructorElement].
@@ -1976,9 +1964,6 @@
       Reference reference, ConstructorDeclaration linkedNode)
       : super.forLinkedNode(enclosingClass, reference, linkedNode);
 
-  /// Initialize a newly created constructor element to have the given [name].
-  ConstructorElementImpl.forNode(Identifier name) : super.forNode(name);
-
   /// Return the constant initializers for this element, which will be empty if
   /// there are no initializers, or `null` if there was an error in the source.
   List<ConstructorInitializer> get constantInitializers {
@@ -2223,11 +2208,6 @@
   ConstTopLevelVariableElementImpl.forLinkedNode(
       ElementImpl enclosing, Reference reference, AstNode linkedNode)
       : super.forLinkedNode(enclosing, reference, linkedNode);
-
-  /// Initialize a newly created top-level variable element to have the given
-  /// [name].
-  ConstTopLevelVariableElementImpl.forNode(Identifier name)
-      : super.forNode(name);
 }
 
 /// Mixin used by elements that represent constant variables and have
@@ -2300,10 +2280,6 @@
   DefaultFieldFormalParameterElementImpl.forLinkedNode(
       ElementImpl enclosing, Reference reference, AstNode linkedNode)
       : super.forLinkedNode(enclosing, reference, linkedNode);
-
-  /// Initialize a newly created parameter element to have the given [name].
-  DefaultFieldFormalParameterElementImpl.forNode(Identifier name)
-      : super.forNode(name);
 }
 
 /// A [ParameterElement] for parameters that have an initializer.
@@ -2317,9 +2293,6 @@
   DefaultParameterElementImpl.forLinkedNode(
       ElementImpl enclosing, Reference reference, AstNode linkedNode)
       : super.forLinkedNode(enclosing, reference, linkedNode);
-
-  /// Initialize a newly created parameter element to have the given [name].
-  DefaultParameterElementImpl.forNode(Identifier name) : super.forNode(name);
 }
 
 /// The synthetic element representing the declaration of the type `dynamic`.
@@ -2666,10 +2639,6 @@
     reference?.element ??= this;
   }
 
-  /// Initialize a newly created element to have the given [name].
-  ElementImpl.forNode(Identifier name)
-      : this(name == null ? "" : name.name, name == null ? -1 : name.offset);
-
   /// Initialize from serialized information.
   ElementImpl.forSerialized(this._enclosingElement)
       : reference = null,
@@ -3317,9 +3286,6 @@
       Reference reference, EnumDeclaration linkedNode)
       : super.forLinkedNode(enclosing, reference, linkedNode);
 
-  /// Initialize a newly created class element to have the given [name].
-  EnumElementImpl.forNode(Identifier name) : super.forNode(name);
-
   @override
   List<PropertyAccessorElement> get accessors {
     if (_accessors == null) {
@@ -3567,9 +3533,6 @@
       ElementImpl enclosing, Reference reference, AstNode linkedNode)
       : super.forLinkedNode(enclosing, reference, linkedNode);
 
-  /// Initialize a newly created executable element to have the given [name].
-  ExecutableElementImpl.forNode(Identifier name) : super.forNode(name);
-
   /// Set whether this executable element's body is asynchronous.
   void set asynchronous(bool isAsynchronous) {
     setModifier(Modifier.ASYNCHRONOUS, isAsynchronous);
@@ -3980,9 +3943,6 @@
       Reference reference, AstNode linkedNode)
       : super.forLinkedNode(enclosing, reference, linkedNode);
 
-  /// Initialize a newly created extension element to have the given [name].
-  ExtensionElementImpl.forNode(Identifier name) : super.forNode(name);
-
   @override
   List<PropertyAccessorElement> get accessors {
     if (_accessors != null) {
@@ -4333,9 +4293,6 @@
     return FieldElementImpl.forLinkedNode(enclosing, reference, linkedNode);
   }
 
-  /// Initialize a newly created field element to have the given [name].
-  FieldElementImpl.forNode(Identifier name) : super.forNode(name);
-
   @override
   FieldElement get declaration => this;
 
@@ -4395,10 +4352,6 @@
       ElementImpl enclosing, Reference reference, AstNode linkedNode)
       : super.forLinkedNode(enclosing, reference, linkedNode);
 
-  /// Initialize a newly created parameter element to have the given [name].
-  FieldFormalParameterElementImpl.forNode(Identifier name)
-      : super.forNode(name);
-
   @override
   FieldElement get field {
     if (_field == null) {
@@ -4450,9 +4403,6 @@
       FunctionDeclaration linkedNode)
       : super.forLinkedNode(enclosing, reference, linkedNode);
 
-  /// Initialize a newly created function element to have the given [name].
-  FunctionElementImpl.forNode(Identifier name) : super.forNode(name);
-
   /// Initialize a newly created function element to have no name and the given
   /// [nameOffset]. This is used for function expressions, that have no name.
   FunctionElementImpl.forOffset(int nameOffset) : super("", nameOffset);
@@ -4639,7 +4589,7 @@
   void appendTo(StringBuffer buffer) {
     DartType type = returnType;
     if (type is TypeImpl) {
-      type.appendTo(buffer, new HashSet<TypeImpl>());
+      type.appendTo(buffer);
       buffer.write(' Function');
     } else {
       buffer.write('Function');
@@ -4698,9 +4648,6 @@
       AstNode linkedNode)
       : super.forLinkedNode(enclosingUnit, reference, linkedNode);
 
-  /// Initialize a newly created type alias element to have the given [name].
-  GenericTypeAliasElementImpl.forNode(Identifier name) : super.forNode(name);
-
   @override
   int get codeLength {
     if (linkedNode != null) {
@@ -5197,14 +5144,6 @@
       this._onSwitchMember)
       : super(name, nameOffset);
 
-  /// Initialize a newly created label element to have the given [name].
-  /// [_onSwitchStatement] should be `true` if this label is associated with a
-  /// `switch` statement and [_onSwitchMember] should be `true` if this label is
-  /// associated with a `switch` member.
-  LabelElementImpl.forNode(
-      Identifier name, this._onSwitchStatement, this._onSwitchMember)
-      : super.forNode(name);
-
   @override
   String get displayName => name;
 
@@ -5234,6 +5173,12 @@
   @override
   final AnalysisSession session;
 
+  @override
+  TypeProviderImpl typeProvider;
+
+  @override
+  TypeSystemImpl typeSystem;
+
   /// The context of the defining unit.
   final LinkedUnitContext linkedContext;
 
@@ -5307,14 +5252,6 @@
         LibraryResolutionCapability.constantExpressions, true);
   }
 
-  /// Initialize a newly created library element in the given [context] to have
-  /// the given [name].
-  LibraryElementImpl.forNode(this.context, this.session, LibraryIdentifier name,
-      this.isNonNullableByDefault)
-      : nameLength = name != null ? name.length : 0,
-        linkedContext = null,
-        super.forNode(name);
-
   @override
   int get codeLength {
     CompilationUnitElement unit = _definingCompilationUnit;
@@ -5810,10 +5747,6 @@
   /// [offset].
   LocalVariableElementImpl(String name, int offset) : super(name, offset);
 
-  /// Initialize a newly created local variable element to have the given
-  /// [name].
-  LocalVariableElementImpl.forNode(Identifier name) : super.forNode(name);
-
   @override
   String get identifier {
     return '$name$nameOffset';
@@ -5854,9 +5787,6 @@
       Reference reference, MethodDeclaration linkedNode)
       : super.forLinkedNode(enclosingClass, reference, linkedNode);
 
-  /// Initialize a newly created method element to have the given [name].
-  MethodElementImpl.forNode(Identifier name) : super.forNode(name);
-
   @override
   MethodElement get declaration => this;
 
@@ -5956,9 +5886,6 @@
       Reference reference, MixinDeclaration linkedNode)
       : super.forLinkedNode(enclosing, reference, linkedNode);
 
-  /// Initialize a newly created class element to have the given [name].
-  MixinElementImpl.forNode(Identifier name) : super.forNode(name);
-
   @override
   bool get isAbstract => true;
 
@@ -6399,10 +6326,6 @@
       ElementImpl enclosing, Reference reference, AstNode linkedNode)
       : super.forLinkedNode(enclosing, reference, linkedNode);
 
-  /// Initialize a newly created variable element to have the given [name].
-  NonParameterVariableElementImpl.forNode(Identifier name)
-      : super.forNode(name);
-
   @override
   int get codeLength {
     if (linkedNode != null) {
@@ -6544,9 +6467,6 @@
     }
   }
 
-  /// Initialize a newly created parameter element to have the given [name].
-  ParameterElementImpl.forNode(Identifier name) : super.forNode(name);
-
   /// Creates a synthetic parameter with [name], [type] and [kind].
   factory ParameterElementImpl.synthetic(
       String name, DartType type, ParameterKind kind) {
@@ -7002,9 +6922,6 @@
       ElementImpl enclosing, Reference reference, SimpleIdentifier linkedNode)
       : super.forLinkedNode(enclosing, reference, linkedNode);
 
-  /// Initialize a newly created prefix element to have the given [name].
-  PrefixElementImpl.forNode(Identifier name) : super.forNode(name);
-
   @override
   String get displayName => name;
 
@@ -7055,10 +6972,6 @@
       ElementImpl enclosing, Reference reference, AstNode linkedNode)
       : super.forLinkedNode(enclosing, reference, linkedNode);
 
-  /// Initialize a newly created property accessor element to have the given
-  /// [name].
-  PropertyAccessorElementImpl.forNode(Identifier name) : super.forNode(name);
-
   /// Initialize a newly created synthetic property accessor element to be
   /// associated with the given [variable].
   PropertyAccessorElementImpl.forVariable(PropertyInducingElementImpl variable,
@@ -7306,9 +7219,6 @@
       ElementImpl enclosing, Reference reference, AstNode linkedNode)
       : super.forLinkedNode(enclosing, reference, linkedNode);
 
-  /// Initialize a newly created element to have the given [name].
-  PropertyInducingElementImpl.forNode(Identifier name) : super.forNode(name);
-
   @override
   bool get isConstantEvaluated => true;
 
@@ -7461,9 +7371,8 @@
     );
   }
 
-  /// Initialize a newly created top-level variable element to have the given
-  /// [name].
-  TopLevelVariableElementImpl.forNode(Identifier name) : super.forNode(name);
+  @override
+  TopLevelVariableElement get declaration => this;
 
   @override
   bool get isStatic => true;
@@ -7503,10 +7412,6 @@
       ElementImpl enclosing, Reference reference, TypeParameter linkedNode)
       : super.forLinkedNode(enclosing, reference, linkedNode);
 
-  /// Initialize a newly created type parameter element to have the given
-  /// [name].
-  TypeParameterElementImpl.forNode(Identifier name) : super.forNode(name);
-
   /// Initialize a newly created synthetic type parameter element to have the
   /// given [name], and with [synthetic] set to true.
   TypeParameterElementImpl.synthetic(String name) : super(name, -1) {
@@ -7566,6 +7471,13 @@
   @override
   String get displayName => name;
 
+  bool get isLegacyCovariant {
+    if (linkedNode != null) {
+      return linkedContext.getTypeParameterVariance(linkedNode) == null;
+    }
+    return _variance == null;
+  }
+
   @override
   ElementKind get kind => ElementKind.TYPE_PARAMETER;
 
@@ -7601,12 +7513,21 @@
     _type = type;
   }
 
-  Variance get variance => _variance ?? Variance.covariant;
+  Variance get variance {
+    if (_variance != null) return _variance;
+
+    if (linkedNode != null) {
+      var varianceKeyword = linkedContext.getTypeParameterVariance(linkedNode);
+      if (varianceKeyword != null) {
+        _variance = Variance.fromKeywordString(varianceKeyword.lexeme);
+      }
+    }
+
+    return _variance ?? Variance.covariant;
+  }
 
   void set variance(Variance newVariance) => _variance = newVariance;
 
-  bool get isLegacyCovariant => _variance == null;
-
   @override
   bool operator ==(Object other) {
     if (identical(other, this)) {
@@ -7627,6 +7548,9 @@
 
   @override
   void appendTo(StringBuffer buffer) {
+    if (!isLegacyCovariant) {
+      buffer.write(variance.toKeywordString() + " ");
+    }
     buffer.write(displayName);
     if (bound != null) {
       buffer.write(" extends ");
@@ -7748,9 +7672,6 @@
       ElementImpl enclosing, Reference reference, AstNode linkedNode)
       : super.forLinkedNode(enclosing, reference, linkedNode);
 
-  /// Initialize a newly created variable element to have the given [name].
-  VariableElementImpl.forNode(Identifier name) : super.forNode(name);
-
   /// Initialize using the given serialized information.
   VariableElementImpl.forSerialized(ElementImpl enclosingElement)
       : super.forSerialized(enclosingElement);
diff --git a/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart b/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart
index 8f3af4e..c80aa0f 100644
--- a/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart
+++ b/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart
@@ -4,7 +4,8 @@
 
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
-import 'package:analyzer/src/generated/type_system.dart';
+import 'package:analyzer/dart/element/type_system.dart';
+import 'package:analyzer/src/generated/type_system.dart' show TypeSystemImpl;
 import 'package:analyzer/src/generated/utilities_general.dart';
 
 /// Description of a failure to find a valid override from superinterfaces.
@@ -32,8 +33,6 @@
 class InheritanceManager3 {
   static final _noSuchMethodName = Name(null, 'noSuchMethod');
 
-  final TypeSystem _typeSystem;
-
   /// Cached instance interfaces for [InterfaceType].
   final Map<InterfaceType, Interface> _interfaces = {};
 
@@ -41,7 +40,7 @@
   /// self-referencing cycles.
   final Set<ClassElement> _processingClasses = new Set<ClassElement>();
 
-  InheritanceManager3(this._typeSystem);
+  InheritanceManager3([@deprecated TypeSystem typeSystem]);
 
   /// Return the most specific signature of the member with the given [name]
   /// that the [type] inherits from the mixins, superclasses, or interfaces;
@@ -69,6 +68,7 @@
     if (interface._inheritedMap == null) {
       interface._inheritedMap = {};
       _findMostSpecificFromNamedCandidates(
+        type.element.library.typeSystem,
         interface._inheritedMap,
         interface._overridden,
       );
@@ -94,6 +94,8 @@
       return Interface._empty;
     }
 
+    var typeSystem = classElement.library.typeSystem;
+
     Map<Name, List<ExecutableElement>> namedCandidates = {};
     List<Map<Name, ExecutableElement>> superImplemented = [];
     Map<Name, ExecutableElement> declared;
@@ -123,7 +125,11 @@
         // `mixin M on S1, S2 {}` can call using `super` any instance member
         // from its superclass constraints, whether it is abstract or concrete.
         var superClass = <Name, ExecutableElement>{};
-        _findMostSpecificFromNamedCandidates(superClass, superClassCandidates);
+        _findMostSpecificFromNamedCandidates(
+          typeSystem,
+          superClass,
+          superClassCandidates,
+        );
         superImplemented.add(superClass);
       } else {
         if (type.superclass != null) {
@@ -172,6 +178,7 @@
     // signature becomes the signature of the class's interface.
     Map<Name, ExecutableElement> map = new Map.of(declared);
     List<Conflict> conflicts = _findMostSpecificFromNamedCandidates(
+      typeSystem,
       map,
       namedCandidates,
     );
@@ -340,6 +347,7 @@
   /// such single most specific signature (i.e. no valid override), then add a
   /// new conflict description.
   List<Conflict> _findMostSpecificFromNamedCandidates(
+      TypeSystemImpl typeSystem,
       Map<Name, ExecutableElement> map,
       Map<Name, List<ExecutableElement>> namedCandidates) {
     List<Conflict> conflicts;
@@ -374,7 +382,7 @@
         validOverride = candidates[i];
         for (var j = 0; j < candidates.length; j++) {
           var candidate = candidates[j];
-          if (!_typeSystem.isOverrideSubtypeOf(
+          if (!typeSystem.isOverrideSubtypeOf(
               validOverride.type, candidate.type)) {
             validOverride = null;
             break;
diff --git a/pkg/analyzer/lib/src/dart/element/member.dart b/pkg/analyzer/lib/src/dart/element/member.dart
index e349274..a086001 100644
--- a/pkg/analyzer/lib/src/dart/element/member.dart
+++ b/pkg/analyzer/lib/src/dart/element/member.dart
@@ -8,6 +8,7 @@
 import 'package:analyzer/dart/element/nullability_suffix.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/nullability_eliminator.dart';
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/type_algebra.dart';
 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
@@ -28,7 +29,8 @@
   ConstructorMember(
     ConstructorElement declaration,
     MapSubstitution substitution,
-  ) : super(declaration, substitution);
+    bool isLegacy,
+  ) : super(declaration, substitution, isLegacy);
 
   @deprecated
   @override
@@ -81,7 +83,7 @@
       substitution = _substitution;
     }
 
-    return ConstructorMember(declaration, substitution);
+    return ConstructorMember(declaration, substitution, false);
   }
 
   @override
@@ -137,6 +139,7 @@
     return ConstructorMember(
       constructor,
       Substitution.fromInterfaceType(definingType),
+      false,
     );
   }
 }
@@ -156,7 +159,8 @@
   ExecutableMember(
     ExecutableElement declaration,
     MapSubstitution substitution,
-  ) : super(declaration, substitution);
+    bool isLegacy,
+  ) : super(declaration, substitution, isLegacy);
 
   @deprecated
   @override
@@ -196,9 +200,9 @@
   List<ParameterElement> get parameters {
     return declaration.parameters.map((p) {
       if (p is FieldFormalParameterElement) {
-        return FieldFormalParameterMember(p, _substitution);
+        return FieldFormalParameterMember(p, _substitution, isLegacy);
       }
-      return ParameterMember(p, _substitution);
+      return ParameterMember(p, _substitution, isLegacy);
     }).toList();
   }
 
@@ -209,7 +213,9 @@
   FunctionType get type {
     if (_type != null) return _type;
 
-    return _type = _substitution.substituteType(declaration.type);
+    _type = _substitution.substituteType(declaration.type);
+    _type = _toLegacyType(_type);
+    return _type;
   }
 
   @override
@@ -232,6 +238,10 @@
     ExecutableElement element,
     MapSubstitution substitution,
   ) {
+    if (element == null) {
+      return null;
+    }
+
     var combined = substitution;
     if (element is ExecutableMember) {
       ExecutableMember member = element;
@@ -247,11 +257,11 @@
     }
 
     if (element is ConstructorElement) {
-      return ConstructorMember(element, combined);
+      return ConstructorMember(element, combined, false);
     } else if (element is MethodElement) {
-      return MethodMember(element, combined);
+      return MethodMember(element, combined, false);
     } else if (element is PropertyAccessorElement) {
-      return PropertyAccessorMember(element, combined);
+      return PropertyAccessorMember(element, combined, false);
     } else {
       throw UnimplementedError('(${element.runtimeType}) $element');
     }
@@ -271,7 +281,8 @@
   FieldFormalParameterMember(
     FieldFormalParameterElement declaration,
     MapSubstitution substitution,
-  ) : super(declaration, substitution);
+    bool isLegacy,
+  ) : super(declaration, substitution, isLegacy);
 
   @override
   FieldElement get field {
@@ -280,7 +291,7 @@
       return null;
     }
 
-    return FieldMember(field, _substitution);
+    return FieldMember(field, _substitution, isLegacy);
   }
 
   @override
@@ -303,7 +314,8 @@
   FieldMember(
     FieldElement declaration,
     MapSubstitution substitution,
-  ) : super(declaration, substitution);
+    bool isLegacy,
+  ) : super(declaration, substitution, isLegacy);
 
   @deprecated
   @override
@@ -321,7 +333,7 @@
     if (baseGetter == null) {
       return null;
     }
-    return PropertyAccessorMember(baseGetter, _substitution);
+    return PropertyAccessorMember(baseGetter, _substitution, isLegacy);
   }
 
   @override
@@ -336,7 +348,7 @@
     if (baseSetter == null) {
       return null;
     }
-    return PropertyAccessorMember(baseSetter, _substitution);
+    return PropertyAccessorMember(baseSetter, _substitution, isLegacy);
   }
 
   @override
@@ -359,6 +371,7 @@
     return FieldMember(
       field,
       Substitution.fromInterfaceType(definingType),
+      false,
     );
   }
 
@@ -369,7 +382,26 @@
     if (substitution.map.isEmpty) {
       return element;
     }
-    return FieldMember(element, substitution);
+    return FieldMember(element, substitution, false);
+  }
+}
+
+class FunctionMember extends ExecutableMember implements FunctionElement {
+  FunctionMember(
+    ExecutableElement declaration,
+    MapSubstitution substitution,
+    bool isLegacy,
+  ) : super(declaration, substitution, isLegacy);
+
+  @override
+  FunctionElement get declaration => super.declaration;
+
+  @override
+  bool get isEntryPoint => declaration.isEntryPoint;
+
+  @override
+  T accept<T>(ElementVisitor<T> visitor) {
+    return visitor.visitFunctionElement(this);
   }
 }
 
@@ -389,10 +421,15 @@
   final MapSubstitution _substitution;
 
   /**
+   * If `true`, then this is a legacy view on a NNBD element.
+   */
+  final bool isLegacy;
+
+  /**
    * Initialize a newly created element to represent a member, based on the
    * [declaration], and applied [_substitution].
    */
-  Member(this._declaration, this._substitution) {
+  Member(this._declaration, this._substitution, this.isLegacy) {
     if (_declaration is Member) {
       throw StateError('Members must be created from a declarations.');
     }
@@ -417,6 +454,9 @@
   String get documentationComment => _declaration.documentationComment;
 
   @override
+  Element get enclosingElement => _declaration.enclosingElement;
+
+  @override
   bool get hasAlwaysThrows => _declaration.hasAlwaysThrows;
 
   @override
@@ -539,6 +579,78 @@
   void visitChildren(ElementVisitor visitor) {
     // There are no children to visit
   }
+
+  /// If this member is a legacy view, erase nullability from the [type].
+  /// Otherwise, return the type unchanged.
+  DartType _toLegacyType(DartType type) {
+    if (isLegacy) {
+      return NullabilityEliminator.perform(type);
+    } else {
+      return type;
+    }
+  }
+
+  /// Return the legacy view of them [element], so that all its types, and
+  /// types of any elements that are returned from it, are legacy types.
+  ///
+  /// If the [element] is declared in a legacy library, return it unchanged.
+  static Element legacy(Element element) {
+    if (element is ConstructorElement) {
+      if (!element.library.isNonNullableByDefault) {
+        return element;
+      } else if (element is Member) {
+        var member = element as Member;
+        return ConstructorMember(
+          member._declaration,
+          member._substitution,
+          true,
+        );
+      } else {
+        return ConstructorMember(element, Substitution.empty, true);
+      }
+    } else if (element is FunctionElement) {
+      if (!element.library.isNonNullableByDefault) {
+        return element;
+      } else if (element is Member) {
+        var member = element as Member;
+        return FunctionMember(
+          member._declaration,
+          member._substitution,
+          true,
+        );
+      } else {
+        return FunctionMember(element, Substitution.empty, true);
+      }
+    } else if (element is MethodElement) {
+      if (!element.library.isNonNullableByDefault) {
+        return element;
+      } else if (element is Member) {
+        var member = element as Member;
+        return MethodMember(
+          member._declaration,
+          member._substitution,
+          true,
+        );
+      } else {
+        return MethodMember(element, Substitution.empty, true);
+      }
+    } else if (element is PropertyAccessorElement) {
+      if (!element.library.isNonNullableByDefault) {
+        return element;
+      } else if (element is Member) {
+        var member = element as Member;
+        return PropertyAccessorMember(
+          member._declaration,
+          member._substitution,
+          true,
+        );
+      } else {
+        return PropertyAccessorMember(element, Substitution.empty, true);
+      }
+    } else {
+      return element;
+    }
+  }
 }
 
 /**
@@ -553,7 +665,8 @@
   MethodMember(
     MethodElement declaration,
     MapSubstitution substitution,
-  ) : super(declaration, substitution);
+    bool isLegacy,
+  ) : super(declaration, substitution, isLegacy);
 
   @deprecated
   @override
@@ -648,6 +761,7 @@
     return MethodMember(
       method,
       Substitution.fromInterfaceType(definingType),
+      false,
     );
   }
 
@@ -658,7 +772,7 @@
     if (substitution.map.isEmpty) {
       return element;
     }
-    return MethodMember(element, substitution);
+    return MethodMember(element, substitution, false);
   }
 }
 
@@ -676,7 +790,8 @@
   ParameterMember(
     ParameterElement declaration,
     MapSubstitution substitution,
-  ) : super(declaration, substitution);
+    bool isLegacy,
+  ) : super(declaration, substitution, isLegacy);
 
   @deprecated
   @override
@@ -771,7 +886,8 @@
   PropertyAccessorMember(
     PropertyAccessorElement declaration,
     MapSubstitution substitution,
-  ) : super(declaration, substitution);
+    bool isLegacy,
+  ) : super(declaration, substitution, isLegacy);
 
   @deprecated
   @override
@@ -782,6 +898,7 @@
     return PropertyAccessorMember(
       declaration.correspondingGetter,
       _substitution,
+      isLegacy,
     );
   }
 
@@ -790,6 +907,7 @@
     return PropertyAccessorMember(
       declaration.correspondingSetter,
       _substitution,
+      isLegacy,
     );
   }
 
@@ -808,9 +926,12 @@
 
   @override
   PropertyInducingElement get variable {
+    // TODO
     PropertyInducingElement variable = declaration.variable;
     if (variable is FieldElement) {
-      return FieldMember(variable, _substitution);
+      return FieldMember(variable, _substitution, isLegacy);
+    } else if (variable is TopLevelVariableElement) {
+      return TopLevelVariableMember(variable, _substitution, isLegacy);
     }
     return variable;
   }
@@ -866,10 +987,46 @@
     return PropertyAccessorMember(
       accessor,
       Substitution.fromInterfaceType(definingType),
+      false,
     );
   }
 }
 
+class TopLevelVariableMember extends VariableMember
+    implements TopLevelVariableElement {
+  TopLevelVariableMember(
+    VariableElement declaration,
+    MapSubstitution substitution,
+    bool isLegacy,
+  ) : super(declaration, substitution, isLegacy);
+
+  @override
+  TopLevelVariableElement get declaration => _declaration;
+
+  @override
+  PropertyAccessorElement get getter {
+    var baseGetter = declaration.getter;
+    if (baseGetter == null) {
+      return null;
+    }
+    return PropertyAccessorMember(baseGetter, _substitution, isLegacy);
+  }
+
+  @override
+  PropertyAccessorElement get setter {
+    var baseSetter = declaration.setter;
+    if (baseSetter == null) {
+      return null;
+    }
+    return PropertyAccessorMember(baseSetter, _substitution, isLegacy);
+  }
+
+  @override
+  T accept<T>(ElementVisitor<T> visitor) {
+    return visitor.visitTopLevelVariableElement(this);
+  }
+}
+
 /**
  * A type parameter defined inside of another parameterized type, where the
  * values of the enclosing type parameters are known.
@@ -891,7 +1048,7 @@
 
   TypeParameterMember(TypeParameterElement declaration,
       MapSubstitution substitution, this._bound)
-      : super(declaration, substitution) {
+      : super(declaration, substitution, false) {
     _type = TypeParameterTypeImpl(this);
   }
 
@@ -993,8 +1150,11 @@
    * Initialize a newly created element to represent a variable, based on the
    * [declaration], with applied [substitution].
    */
-  VariableMember(VariableElement declaration, MapSubstitution substitution)
-      : super(declaration, substitution);
+  VariableMember(
+    VariableElement declaration,
+    MapSubstitution substitution,
+    bool isLegacy,
+  ) : super(declaration, substitution, isLegacy);
 
   @deprecated
   @override
@@ -1038,7 +1198,9 @@
   DartType get type {
     if (_type != null) return _type;
 
-    return _type = _substitution.substituteType(declaration.type);
+    _type = _substitution.substituteType(declaration.type);
+    _type = _toLegacyType(_type);
+    return _type;
   }
 
   @override
diff --git a/pkg/analyzer/lib/src/dart/element/nullability_eliminator.dart b/pkg/analyzer/lib/src/dart/element/nullability_eliminator.dart
index c1485e2..fa1dc26 100644
--- a/pkg/analyzer/lib/src/dart/element/nullability_eliminator.dart
+++ b/pkg/analyzer/lib/src/dart/element/nullability_eliminator.dart
@@ -9,6 +9,7 @@
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/type_algebra.dart';
 import 'package:analyzer/src/dart/element/type_visitor.dart';
+import 'package:analyzer/src/generated/type_system.dart';
 
 class NullabilityEliminator extends DartTypeVisitor<DartType> {
   int _counter = 0;
@@ -96,6 +97,11 @@
   }
 
   @override
+  DartType visitUnknownInferredType(UnknownInferredType type) {
+    return type;
+  }
+
+  @override
   DartType visitVoidType(VoidType type) {
     return type;
   }
@@ -126,8 +132,13 @@
 
     var freshElements = List<TypeParameterElement>(elements.length);
     for (var i = 0; i < elements.length; i++) {
-      var element = elements[i];
+      // TODO (kallentu) : Clean up TypeParameterElementImpl casting once
+      // variance is added to the interface.
+      var element = elements[i] as TypeParameterElementImpl;
       var freshElement = TypeParameterElementImpl(element.name, -1);
+      if (!element.isLegacyCovariant) {
+        freshElement.variance = element.variance;
+      }
       freshElement.bound = freshBounds[i];
       freshElements[i] = freshElement;
     }
@@ -152,6 +163,10 @@
   /// return a new type with legacy nullability suffixes. Otherwise return the
   /// original instance.
   static T perform<T extends DartType>(T type) {
+    if (type == null) {
+      return type;
+    }
+
     return NullabilityEliminator().visit(type);
   }
 
diff --git a/pkg/analyzer/lib/src/dart/element/type.dart b/pkg/analyzer/lib/src/dart/element/type.dart
index 920a511..14581cc 100644
--- a/pkg/analyzer/lib/src/dart/element/type.dart
+++ b/pkg/analyzer/lib/src/dart/element/type.dart
@@ -13,7 +13,7 @@
 import 'package:analyzer/src/dart/element/type_algebra.dart';
 import 'package:analyzer/src/generated/engine.dart'
     show AnalysisContext, AnalysisEngine;
-import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
 import 'package:analyzer/src/generated/type_system.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
 import 'package:meta/meta.dart';
@@ -149,7 +149,7 @@
       // Function types have an empty name when they are defined implicitly by
       // either a closure or as part of a parameter declaration.
       StringBuffer buffer = new StringBuffer();
-      appendTo(buffer, new Set.identity());
+      appendTo(buffer);
       if (nullabilitySuffix == NullabilitySuffix.question) {
         buffer.write('?');
       }
@@ -295,71 +295,68 @@
   }
 
   @override
-  void appendTo(StringBuffer buffer, Set<TypeImpl> visitedTypes,
-      {bool withNullability = false}) {
+  void appendTo(StringBuffer buffer, {bool withNullability = false}) {
     // TODO(paulberry): eliminate code duplication with
     // _ElementWriter.writeType.  See issue #35818.
-    if (visitedTypes.add(this)) {
-      if (typeFormals.isNotEmpty) {
-        StringBuffer typeParametersBuffer = StringBuffer();
-        // To print a type with type variables, first make sure we have unique
-        // variable names to print.
-        var freeVariables = <TypeParameterElement>{};
-        _freeVariablesInFunctionType(this, freeVariables);
+    if (typeFormals.isNotEmpty) {
+      StringBuffer typeParametersBuffer = StringBuffer();
+      // To print a type with type variables, first make sure we have unique
+      // variable names to print.
+      var freeVariables = <TypeParameterElement>{};
+      _freeVariablesInFunctionType(this, freeVariables);
 
-        var namesToAvoid = <String>{};
-        for (TypeParameterElement arg in freeVariables) {
-          namesToAvoid.add(arg.displayName);
-        }
-
-        List<DartType> instantiateTypeArgs = <DartType>[];
-        List<TypeParameterElement> variables = <TypeParameterElement>[];
-        typeParametersBuffer.write('<');
-        for (TypeParameterElement e in typeFormals) {
-          if (e != typeFormals[0]) {
-            typeParametersBuffer.write(', ');
-          }
-          String name = e.name;
-          int counter = 0;
-          while (!namesToAvoid.add(name)) {
-            // Unicode subscript-zero is U+2080, zero is U+0030. Other digits
-            // are sequential from there. Thus +0x2050 will get us the subscript.
-            String subscript = new String.fromCharCodes(
-                counter.toString().codeUnits.map((n) => n + 0x2050));
-
-            name = e.name + subscript;
-            counter++;
-          }
-          TypeParameterTypeImpl t = new TypeParameterTypeImpl(
-              new TypeParameterElementImpl(name, -1),
-              nullabilitySuffix: NullabilitySuffix.none);
-          t.appendTo(typeParametersBuffer, visitedTypes,
-              withNullability: withNullability);
-          instantiateTypeArgs.add(t);
-          variables.add(e);
-          if (e.bound != null) {
-            typeParametersBuffer.write(' extends ');
-            TypeImpl renamed =
-                Substitution.fromPairs(variables, instantiateTypeArgs)
-                    .substituteType(e.bound);
-            renamed.appendTo(typeParametersBuffer, visitedTypes,
-                withNullability: withNullability);
-          }
-        }
-        typeParametersBuffer.write('>');
-
-        // Instantiate it and print the resulting type.
-        this.instantiate(instantiateTypeArgs)._appendToWithTypeParameters(
-            buffer,
-            visitedTypes,
-            withNullability,
-            typeParametersBuffer.toString());
-      } else {
-        _appendToWithTypeParameters(buffer, visitedTypes, withNullability, '');
+      var namesToAvoid = <String>{};
+      for (TypeParameterElement arg in freeVariables) {
+        namesToAvoid.add(arg.displayName);
       }
-      visitedTypes.remove(this);
+
+      List<DartType> instantiateTypeArgs = <DartType>[];
+      List<TypeParameterElement> variables = <TypeParameterElement>[];
+      typeParametersBuffer.write('<');
+      // TODO (kallentu) : Clean up TypeParameterElementImpl casting once
+      // variance is added to the interface.
+      for (TypeParameterElementImpl e in typeFormals) {
+        if (e != typeFormals[0]) {
+          typeParametersBuffer.write(', ');
+        }
+
+        if (!e.isLegacyCovariant) {
+          typeParametersBuffer.write(e.variance.toKeywordString() + ' ');
+        }
+
+        String name = e.name;
+        int counter = 0;
+        while (!namesToAvoid.add(name)) {
+          // Unicode subscript-zero is U+2080, zero is U+0030. Other digits
+          // are sequential from there. Thus +0x2050 will get us the subscript.
+          String subscript = new String.fromCharCodes(
+              counter.toString().codeUnits.map((n) => n + 0x2050));
+
+          name = e.name + subscript;
+          counter++;
+        }
+        TypeParameterTypeImpl t = new TypeParameterTypeImpl(
+            new TypeParameterElementImpl(name, -1),
+            nullabilitySuffix: NullabilitySuffix.none);
+        t.appendTo(typeParametersBuffer, withNullability: withNullability);
+        instantiateTypeArgs.add(t);
+        variables.add(e);
+        if (e.bound != null) {
+          typeParametersBuffer.write(' extends ');
+          TypeImpl renamed =
+              Substitution.fromPairs(variables, instantiateTypeArgs)
+                  .substituteType(e.bound);
+          renamed.appendTo(typeParametersBuffer,
+              withNullability: withNullability);
+        }
+      }
+      typeParametersBuffer.write('>');
+
+      // Instantiate it and print the resulting type.
+      this.instantiate(instantiateTypeArgs)._appendToWithTypeParameters(
+          buffer, withNullability, typeParametersBuffer.toString());
     } else {
-      buffer.write('<recursive>');
+      _appendToWithTypeParameters(buffer, withNullability, '');
     }
   }
 
@@ -461,8 +458,8 @@
     );
   }
 
-  void _appendToWithTypeParameters(StringBuffer buffer,
-      Set<TypeImpl> visitedTypes, bool withNullability, String typeParameters) {
+  void _appendToWithTypeParameters(
+      StringBuffer buffer, bool withNullability, String typeParameters) {
     List<DartType> normalParameterTypes = this.normalParameterTypes;
     List<DartType> optionalParameterTypes = this.optionalParameterTypes;
     DartType returnType = this.returnType;
@@ -471,7 +468,7 @@
       buffer.write('null');
     } else {
       (returnType as TypeImpl)
-          .appendTo(buffer, visitedTypes, withNullability: withNullability);
+          .appendTo(buffer, withNullability: withNullability);
     }
     buffer.write(' Function');
     buffer.write(typeParameters);
@@ -496,8 +493,7 @@
     if (normalParameterTypes.isNotEmpty) {
       for (DartType type in normalParameterTypes) {
         writeSeparator();
-        (type as TypeImpl)
-            .appendTo(buffer, visitedTypes, withNullability: withNullability);
+        (type as TypeImpl).appendTo(buffer, withNullability: withNullability);
       }
     }
     if (optionalParameterTypes.isNotEmpty) {
@@ -505,8 +501,7 @@
       buffer.write('[');
       for (DartType type in optionalParameterTypes) {
         writeSeparator();
-        (type as TypeImpl)
-            .appendTo(buffer, visitedTypes, withNullability: withNullability);
+        (type as TypeImpl).appendTo(buffer, withNullability: withNullability);
       }
       buffer.write(']');
       needsComma = true;
@@ -524,7 +519,7 @@
         buffer.write(parameter.name);
         buffer.write(': ');
         (parameter.type as TypeImpl)
-            .appendTo(buffer, visitedTypes, withNullability: withNullability);
+            .appendTo(buffer, withNullability: withNullability);
       }
       buffer.write('}');
       needsComma = true;
@@ -779,7 +774,9 @@
       TypeParameterElementImpl pFresh =
           new TypeParameterElementImpl.synthetic(p2.name);
 
-      DartType variableFresh = new TypeParameterTypeImpl(pFresh);
+      DartType variableFresh = pFresh.instantiate(
+        nullabilitySuffix: NullabilitySuffix.none,
+      );
 
       variables1.add(p1);
       variables2.add(p2);
@@ -1179,28 +1176,22 @@
   }
 
   @override
-  void appendTo(StringBuffer buffer, Set<TypeImpl> visitedTypes,
-      {bool withNullability = false}) {
-    if (visitedTypes.add(this)) {
-      buffer.write(name);
-      int argumentCount = typeArguments.length;
-      if (argumentCount > 0) {
-        buffer.write("<");
-        for (int i = 0; i < argumentCount; i++) {
-          if (i > 0) {
-            buffer.write(", ");
-          }
-          (typeArguments[i] as TypeImpl)
-              .appendTo(buffer, visitedTypes, withNullability: withNullability);
+  void appendTo(StringBuffer buffer, {bool withNullability = false}) {
+    buffer.write(name);
+    int argumentCount = typeArguments.length;
+    if (argumentCount > 0) {
+      buffer.write("<");
+      for (int i = 0; i < argumentCount; i++) {
+        if (i > 0) {
+          buffer.write(", ");
         }
-        buffer.write(">");
+        (typeArguments[i] as TypeImpl)
+            .appendTo(buffer, withNullability: withNullability);
       }
-      if (withNullability) {
-        _appendNullability(buffer);
-      }
-      visitedTypes.remove(this);
-    } else {
-      buffer.write('<recursive>');
+      buffer.write(">");
+    }
+    if (withNullability) {
+      _appendNullability(buffer);
     }
   }
 
@@ -1663,7 +1654,7 @@
    * types in [types], return it.  Otherwise return `null`.
    */
   static DartType findMostSpecificType(
-      List<DartType> types, TypeSystem typeSystem) {
+      List<DartType> types, TypeSystemImpl typeSystem) {
     // The << relation ("more specific than") is a partial ordering on types,
     // so to find the most specific type of a set, we keep a bucket of the most
     // specific types seen so far such that no type in the bucket is more
@@ -2032,26 +2023,17 @@
   @override
   bool get isVoid => false;
 
-  /**
-   * Return the nullability suffix of this type.
-   */
+  @override
   NullabilitySuffix get nullabilitySuffix;
 
   /**
-   * Append a textual representation of this type to the given [buffer]. The set
-   * of [visitedTypes] is used to prevent infinite recursion.
+   * Append a textual representation of this type to the given [buffer].
    */
-  void appendTo(StringBuffer buffer, Set<TypeImpl> visitedTypes,
-      {bool withNullability = false}) {
-    if (visitedTypes.add(this)) {
-      if (name == null) {
-        buffer.write("<unnamed type>");
-      } else {
-        buffer.write(name);
-      }
-      visitedTypes.remove(this);
+  void appendTo(StringBuffer buffer, {bool withNullability = false}) {
+    if (name == null) {
+      buffer.write("<unnamed type>");
     } else {
-      buffer.write('<recursive>');
+      buffer.write(name);
     }
     if (withNullability) {
       _appendNullability(buffer);
@@ -2081,7 +2063,7 @@
   @override
   String toString({bool withNullability = false}) {
     StringBuffer buffer = new StringBuffer();
-    appendTo(buffer, new Set.identity(), withNullability: withNullability);
+    appendTo(buffer, withNullability: withNullability);
     return buffer.toString();
   }
 
@@ -2095,7 +2077,7 @@
    * so it is what you want if you are constructing a fresh type and want it to
    * have the correct nullability suffix, but it is generally *not* what you
    * want if you're manipulating existing types.  For manipulating existing
-   * types, please use the methods in [TypeSystem].
+   * types, please use the methods in [TypeSystemImpl].
    */
   TypeImpl withNullability(NullabilitySuffix nullabilitySuffix);
 
diff --git a/pkg/analyzer/lib/src/dart/element/type_algebra.dart b/pkg/analyzer/lib/src/dart/element/type_algebra.dart
index c74ce935..2cab0ed 100644
--- a/pkg/analyzer/lib/src/dart/element/type_algebra.dart
+++ b/pkg/analyzer/lib/src/dart/element/type_algebra.dart
@@ -36,7 +36,14 @@
   var substitution = Substitution.fromMap(map);
 
   for (int i = 0; i < typeParameters.length; ++i) {
-    var bound = typeParameters[i].bound;
+    // TODO (kallentu) : Clean up TypeParameterElementImpl casting once
+    // variance is added to the interface.
+    var typeParameter = typeParameters[i] as TypeParameterElementImpl;
+    if (!typeParameter.isLegacyCovariant) {
+      freshParameters[i].variance = typeParameter.variance;
+    }
+
+    var bound = typeParameter.bound;
     if (bound != null) {
       var newBound = substitution.substituteType(bound);
       freshParameters[i].bound = newBound;
@@ -242,7 +249,9 @@
 
     var freshElements = List<TypeParameterElement>(elements.length);
     for (var i = 0; i < elements.length; i++) {
-      var element = elements[i];
+      // TODO (kallentu) : Clean up TypeParameterElementImpl casting once
+      // variance is added to the interface.
+      var element = elements[i] as TypeParameterElementImpl;
       var freshElement = TypeParameterElementImpl(element.name, -1);
       freshElements[i] = freshElement;
       var freshType = freshElement.instantiate(
@@ -250,6 +259,10 @@
       );
       freshElement.type = freshType;
       substitution[element] = freshType;
+
+      if (!element.isLegacyCovariant) {
+        freshElement.variance = element.variance;
+      }
     }
 
     for (var i = 0; i < freshElements.length; i++) {
diff --git a/pkg/analyzer/lib/src/dart/element/type_provider.dart b/pkg/analyzer/lib/src/dart/element/type_provider.dart
index 07a7fe8..8884f1b 100644
--- a/pkg/analyzer/lib/src/dart/element/type_provider.dart
+++ b/pkg/analyzer/lib/src/dart/element/type_provider.dart
@@ -8,6 +8,7 @@
 import 'package:analyzer/src/dart/constant/value.dart';
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/generated/resolver.dart';
+import 'package:meta/meta.dart';
 
 /// Provide common functionality shared by the various TypeProvider
 /// implementations.
@@ -41,10 +42,13 @@
 }
 
 class TypeProviderImpl extends TypeProviderBase {
-  final NullabilitySuffix _nullabilitySuffix;
   final LibraryElement _coreLibrary;
   final LibraryElement _asyncLibrary;
 
+  /// If `true`, then NNBD types are returned.
+  /// If `false`, then legacy types are returned.
+  final bool _isNonNullableByDefault;
+
   ClassElement _boolElement;
   ClassElement _doubleElement;
   ClassElement _futureElement;
@@ -96,13 +100,37 @@
 
   /// Initialize a newly created type provider to provide the types defined in
   /// the given [coreLibrary] and [asyncLibrary].
-  TypeProviderImpl(
-    LibraryElement coreLibrary,
-    LibraryElement asyncLibrary, {
-    NullabilitySuffix nullabilitySuffix = NullabilitySuffix.star,
-  })  : _nullabilitySuffix = nullabilitySuffix,
-        _coreLibrary = coreLibrary,
-        _asyncLibrary = asyncLibrary;
+  TypeProviderImpl({
+    @required LibraryElement coreLibrary,
+    @required LibraryElement asyncLibrary,
+    @required bool isNonNullableByDefault,
+  })  : _coreLibrary = coreLibrary,
+        _asyncLibrary = asyncLibrary,
+        _isNonNullableByDefault = isNonNullableByDefault;
+
+  TypeProviderImpl get asLegacy {
+    if (_isNonNullableByDefault) {
+      return TypeProviderImpl(
+        coreLibrary: _coreLibrary,
+        asyncLibrary: _asyncLibrary,
+        isNonNullableByDefault: false,
+      );
+    } else {
+      return this;
+    }
+  }
+
+  TypeProviderImpl get asNonNullableByDefault {
+    if (_isNonNullableByDefault) {
+      return this;
+    } else {
+      return TypeProviderImpl(
+        coreLibrary: _coreLibrary,
+        asyncLibrary: _asyncLibrary,
+        isNonNullableByDefault: true,
+      );
+    }
+  }
 
   @override
   ClassElement get boolElement {
@@ -117,7 +145,7 @@
 
   @override
   DartType get bottomType {
-    if (_nullabilitySuffix == NullabilitySuffix.none) {
+    if (_isNonNullableByDefault) {
       return NeverTypeImpl.instance;
     }
     return NeverTypeImpl.instanceLegacy;
@@ -434,8 +462,16 @@
   @override
   VoidType get voidType => VoidTypeImpl.instance;
 
+  NullabilitySuffix get _nullabilitySuffix {
+    if (_isNonNullableByDefault) {
+      return NullabilitySuffix.none;
+    } else {
+      return NullabilitySuffix.star;
+    }
+  }
+
   NullabilitySuffix get _questionOrStarSuffix {
-    return _nullabilitySuffix == NullabilitySuffix.none
+    return _isNonNullableByDefault
         ? NullabilitySuffix.question
         : NullabilitySuffix.star;
   }
@@ -496,14 +532,6 @@
     );
   }
 
-  TypeProviderImpl withNullability(NullabilitySuffix nullabilitySuffix) {
-    if (_nullabilitySuffix == nullabilitySuffix) {
-      return this;
-    }
-    return TypeProviderImpl(_coreLibrary, _asyncLibrary,
-        nullabilitySuffix: nullabilitySuffix);
-  }
-
   /// Return the class with the given [name] from the given [library], or
   /// throw a [StateError] if there is no class with the given name.
   ClassElement _getClassElement(LibraryElement library, String name) {
diff --git a/pkg/analyzer/lib/src/dart/error/hint_codes.dart b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
index 291e8b08..75008d4 100644
--- a/pkg/analyzer/lib/src/dart/error/hint_codes.dart
+++ b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
@@ -22,7 +22,56 @@
   /**
    * Dead code is code that is never reached, this can happen for instance if a
    * statement follows a return statement.
+   *
+   * No parameters.
    */
+  // #### Description
+  //
+  // The analyzer produces this diagnostic when code is found that won't be
+  // executed because execution will never reach the code.
+  //
+  // #### Example
+  //
+  // The following code produces this diagnostic because the invocation of
+  // `print` occurs after the function has returned:
+  //
+  // ```dart
+  // void f() {
+  //   return;
+  //   [!print('here');!]
+  // }
+  // ```
+  //
+  // #### Common fixes
+  //
+  // If the code isn't needed, then remove it:
+  //
+  // ```dart
+  // void f() {
+  //   return;
+  // }
+  // ```
+  //
+  // If the code needs to be executed, then either move the code to a place
+  // where it will be executed:
+  //
+  // ```dart
+  // void f() {
+  //   print('here');
+  //   return;
+  // }
+  // ```
+  //
+  // Or, rewrite the code before it, so that it can be reached:
+  //
+  // ```dart
+  // void f({bool skipPrinting = true}) {
+  //   if (skipPrinting) {
+  //     return;
+  //   }
+  //   print('here');
+  // }
+  // ```
   static const HintCode DEAD_CODE = const HintCode('DEAD_CODE', "Dead code.",
       correction: "Try removing the code, or "
           "fixing the code before it so that it can be reached.");
@@ -30,11 +79,57 @@
   /**
    * Dead code is code that is never reached. This case covers cases where the
    * user has catch clauses after `catch (e)` or `on Object catch (e)`.
+   *
+   * No parameters.
    */
+  // #### Description
+  //
+  // The analyzer produces this diagnostic when a catch clause is found that
+  // can't be executed because it’s after a catch clause of the form `catch (e)`
+  // or `on Object catch (e)`. The first catch clause that matches the thrown
+  // object is selected, and both of those forms will match any object, so no
+  // catch clauses that follow them will be selected.
+  //
+  // #### Example
+  //
+  // The following code produces this diagnostic:
+  //
+  // ```dart
+  // void f() {
+  //   try {
+  //   } catch (e) {
+  //   } [!on String {
+  //   }!]
+  // }
+  // ```
+  //
+  // #### Common fixes
+  //
+  // If the clause should be selectable, then move the clause before the general
+  // clause:
+  //
+  // ```dart
+  // void f() {
+  //   try {
+  //   } on String {
+  //   } catch (e) {
+  //   }
+  // }
+  // ```
+  //
+  // If the clause doesn't need to be selectable, then remove it:
+  //
+  // ```dart
+  // void f() {
+  //   try {
+  //   } catch (e) {
+  //   }
+  // }
+  // ```
   static const HintCode DEAD_CODE_CATCH_FOLLOWING_CATCH = const HintCode(
       'DEAD_CODE_CATCH_FOLLOWING_CATCH',
-      "Dead code: catch clauses after a 'catch (e)' or "
-          "an 'on Object catch (e)' are never reached.",
+      "Dead code: Catch clauses after a 'catch (e)' or an "
+          "'on Object catch (e)' are never reached.",
       correction:
           "Try reordering the catch clauses so that they can be reached, or "
           "removing the unreachable catch clauses.");
@@ -48,10 +143,55 @@
    * 0: name of the subtype
    * 1: name of the supertype
    */
+  // #### Description
+  //
+  // The analyzer produces this diagnostic when a catch clause is found that
+  // can't be executed because it is after a catch clause that catches either
+  // the same type or a supertype of the clause's type. The first catch clause
+  // that matches the thrown object is selected, and the earlier clause l always
+  // matches anything matchable by the highlighted clause, so the highlighted
+  // clause will never be selected.
+  //
+  // #### Example
+  //
+  // The following code produces this diagnostic:
+  //
+  // ```dart
+  // void f() {
+  //   try {
+  //   } on num {
+  //   } [!on int {
+  //   }!]
+  // }
+  // ```
+  //
+  // #### Common fixes
+  //
+  // If the clause should be selectable, then move the clause before the general
+  // clause:
+  //
+  // ```dart
+  // void f() {
+  //   try {
+  //   } on int {
+  //   } on num {
+  //   }
+  // }
+  // ```
+  //
+  // If the clause doesn't need to be selectable, then remove it:
+  //
+  // ```dart
+  // void f() {
+  //   try {
+  //   } on num {
+  //   }
+  // }
+  // ```
   static const HintCode DEAD_CODE_ON_CATCH_SUBTYPE = const HintCode(
       'DEAD_CODE_ON_CATCH_SUBTYPE',
-      "Dead code: this on-catch block will never be executed because '{0}' is "
-          "a subtype of '{1}' and hence will have been caught above.",
+      "Dead code: This on-catch block won’t be executed because '{0}' is a "
+          "subtype of '{1}' and hence will have been caught already.",
       correction:
           "Try reordering the catch clauses so that this block can be reached, "
           "or removing the unreachable catch clause.");
@@ -112,7 +252,7 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because `x` is deprecated:
   //
   // ```dart
   // @deprecated
@@ -177,7 +317,35 @@
 
   /**
    * Duplicate imports.
+   *
+   * No parameters.
    */
+  // #### Description
+  //
+  // The analyzer produces this diagnostic when an import directive is found
+  // that is the same as an import before it in the file. The second import
+  // doesn’t add value and should be removed.
+  //
+  // #### Example
+  //
+  // The following code produces this diagnostic:
+  //
+  // ```dart
+  // import 'package:meta/meta.dart';
+  // import [!'package:meta/meta.dart'!];
+  //
+  // @sealed class C {}
+  // ```
+  //
+  // #### Common fixes
+  //
+  // Remove the unnecessary import:
+  //
+  // ```dart
+  // import 'package:meta/meta.dart';
+  //
+  // @sealed class C {}
+  // ```
   static const HintCode DUPLICATE_IMPORT = const HintCode(
       'DUPLICATE_IMPORT', "Duplicate import.",
       correction: "Try removing all but one import of the library.");
@@ -330,12 +498,25 @@
    */
   // #### Description
   //
-  // The meaning of the `@literal` annotation is only defined when it's applied
-  // to a const constructor.
+  // The analyzer produces this diagnostic when the `@literal` annotation is
+  // applied to anything other than a const constructor.
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because the constructor is not
+  // a `const` constructor:
+  //
+  // ```dart
+  // import 'package:meta/meta.dart';
+  //
+  // class C {
+  //   [!@literal!]
+  //   C();
+  // }
+  // ```
+  //
+  // The following code produces this diagnostic because `x` isn't a
+  // constructor:
   //
   // ```dart
   // import 'package:meta/meta.dart';
@@ -346,7 +527,23 @@
   //
   // #### Common fixes
   //
-  // Remove the annotation:
+  // If the annotation is on a constructor and the constructor should always be
+  // invoked with `const`, when possible, then mark the constructor with the
+  // `const` keyword:
+  //
+  // ```dart
+  // import 'package:meta/meta.dart';
+  //
+  // class C {
+  //   @literal
+  //   const C();
+  // }
+  // ```
+  //
+  // If the constructor can't be marked as `const`, then remove the annotation.
+  //
+  // If the annotation is on anything other than a constructor, then remove the
+  // annotation:
   //
   // ```dart
   // var x;
@@ -467,34 +664,79 @@
       "The member '{0}' can only be used within instance members of subclasses "
           "of '{1}'.");
 
-  /// This hint is generated anywhere where a member annotated with
-  /// `@visibleForTemplate` is used outside of a "template" Dart file.
-  ///
-  /// Parameters:
-  /// 0: the name of the member
-  /// 1: the name of the defining class
+  /**
+   * This hint is generated anywhere where a member annotated with
+   * `@visibleForTemplate` is used outside of a "template" Dart file.
+   *
+   * Parameters:
+   * 0: the name of the member
+   * 1: the name of the defining class
+   */
   static const HintCode INVALID_USE_OF_VISIBLE_FOR_TEMPLATE_MEMBER =
       const HintCode(
           'INVALID_USE_OF_VISIBLE_FOR_TEMPLATE_MEMBER',
           "The member '{0}' can only be used within '{1}' or a template "
               "library.");
 
-  /// This hint is generated anywhere where a member annotated with
-  /// `@visibleForTesting` is used outside the defining library, or a test.
-  ///
-  /// Parameters:
-  /// 0: the name of the member
-  /// 1: the name of the defining class
+  /**
+   * This hint is generated anywhere where a member annotated with
+   * `@visibleForTesting` is used outside the defining library, or a test.
+   *
+   * Parameters:
+   * 0: the name of the member
+   * 1: the name of the defining class
+   */
   static const HintCode INVALID_USE_OF_VISIBLE_FOR_TESTING_MEMBER =
       const HintCode('INVALID_USE_OF_VISIBLE_FOR_TESTING_MEMBER',
           "The member '{0}' can only be used within '{1}' or a test.");
 
-  /// This hint is generated anywhere where a private declaration is annotated
-  /// with `@visibleForTemplate` or `@visibleForTesting`.
-  ///
-  /// Parameters:
-  /// 0: the name of the member
-  /// 1: the name of the annotation
+  /**
+   * This hint is generated anywhere where a private declaration is annotated
+   * with `@visibleForTemplate` or `@visibleForTesting`.
+   *
+   * Parameters:
+   * 0: the name of the member
+   * 1: the name of the annotation
+   */
+  // #### Description
+  //
+  // The analyzer produces this diagnostic when either the `@visibleForTemplate`
+  // or `@visibleForTesting` annotation is applied to a non-public declaration.
+  //
+  // #### Example
+  //
+  // The following code produces this diagnostic:
+  //
+  // ```dart
+  // import 'package:meta/meta.dart';
+  //
+  // [!@visibleForTesting!]
+  // void _someFunction() {}
+  //
+  // void f() => _someFunction();
+  // ```
+  //
+  // #### Common fixes
+  //
+  // If the declaration doesn't need to be used by test code, then remove the
+  // annotation:
+  //
+  // ```dart
+  // void _someFunction() {}
+  //
+  // void f() => _someFunction();
+  // ```
+  //
+  // If it does, then make it public:
+  //
+  // ```dart
+  // import 'package:meta/meta.dart';
+  //
+  // @visibleForTesting
+  // void someFunction() {}
+  //
+  // void f() => someFunction();
+  // ```
   static const HintCode INVALID_VISIBILITY_ANNOTATION = const HintCode(
       'INVALID_VISIBILITY_ANNOTATION',
       "The member '{0}' is annotated with '{1}', but this annotation is only "
@@ -557,6 +799,40 @@
    * Parameters:
    * 0: the name of the parameter
    */
+  // #### Description
+  //
+  // The analyzer produces this diagnostic when a method or function with a
+  // named parameter that is annotated as being required is invoked without
+  // providing a value for the parameter.
+  //
+  // #### Example
+  //
+  // The following code produces this diagnostic because the named parameter `x`
+  // is required:
+  //
+  // ```dart
+  // import 'package:meta/meta.dart';
+  //
+  // void f({@required int x}) {}
+  //
+  // void g() {
+  //   [!f!]();
+  // }
+  // ```
+  //
+  // #### Common fixes
+  //
+  // Provide the required value:
+  //
+  // ```dart
+  // import 'package:meta/meta.dart';
+  //
+  // void f({@required int x}) {}
+  //
+  // void g() {
+  //   f(x: 2);
+  // }
+  // ```
   static const HintCode MISSING_REQUIRED_PARAM = const HintCode(
       'MISSING_REQUIRED_PARAM', "The parameter '{0}' is required.");
 
@@ -568,9 +844,11 @@
    * 0: the name of the parameter
    * 1: message details
    */
-  static const HintCode MISSING_REQUIRED_PARAM_WITH_DETAILS = const HintCode(
-      'MISSING_REQUIRED_PARAM_WITH_DETAILS',
-      "The parameter '{0}' is required. {1}.");
+  static const HintCode MISSING_REQUIRED_PARAM_WITH_DETAILS =
+      const HintCodeWithUniqueName(
+          'MISSING_REQUIRED_PARAM',
+          'HintCode.MISSING_REQUIRED_PARAM_WITH_DETAILS',
+          "The parameter '{0}' is required. {1}.");
 
   /**
    * Parameters:
@@ -584,7 +862,8 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because `f` doesn't end with a
+  // return:
   //
   // ```dart
   // int [!f!](int x) {
@@ -609,11 +888,47 @@
   /**
    * This hint is generated anywhere where a `@sealed` class is used as a
    * a superclass constraint of a mixin.
+   *
+   * Parameters:
+   * 0: the name of the sealed class
    */
+  // #### Description
+  //
+  // The analyzer produces this diagnostic when the superclass constraint of a
+  // mixin is a class from a different package that was marked as `@sealed`.
+  // Classes that are sealed can't be extended, implemented, mixed in, or used
+  // as a superclass constraint.
+  //
+  // #### Example
+  //
+  // If the package 'p' defines a sealed class:
+  //
+  // ```dart
+  // %uri="package:p/p.dart"
+  // import 'package:meta/meta.dart';
+  //
+  // @sealed
+  // class C {}
+  // ```
+  //
+  // Then, the following code, when in a package other than 'p', produces this
+  // diagnostic:
+  //
+  // ```dart
+  // import 'package:p/p.dart';
+  //
+  // [!mixin M on C {}!]
+  // ```
+  //
+  // #### Common fixes
+  //
+  // If the classes that use the mixin don't need to be subclasses of the sealed
+  // class, then consider adding a field and delegating to the wrapped instance
+  // of the sealed class.
   static const HintCode MIXIN_ON_SEALED_CLASS = const HintCode(
       'MIXIN_ON_SEALED_CLASS',
       "The class '{0}' shouldn't be used as a mixin constraint because it is "
-          "sealed, and any class mixing in this mixin has '{0}' as a "
+          "sealed, and any class mixing in this mixin must have '{0}' as a "
           "superclass.",
       correction:
           "Try composing with this class, or refer to its documentation for "
@@ -644,7 +959,47 @@
   /**
    * Generate a hint for non-const instance creation using a constructor
    * annotated with `@literal`.
+   *
+   * Parameters:
+   * 0: the name of the class defining the annotated constructor
    */
+  // #### Description
+  //
+  // The analyzer produces this diagnostic when a constructor that has the
+  // `@literal` annotation is invoked without using the `const` keyword, but all
+  // of the arguments to the constructor are constants. The annotation indicates
+  // that the constructor should be used to create a constant value whenever
+  // possible.
+  //
+  // #### Example
+  //
+  // The following code produces this diagnostic:
+  //
+  // ```dart
+  // import 'package:meta/meta.dart';
+  //
+  // class C {
+  //   @literal
+  //   const C();
+  // }
+  //
+  // C f() => [!C()!];
+  // ```
+  //
+  // #### Common fixes
+  //
+  // Add the keyword `const` before the constructor invocation:
+  //
+  // ```dart
+  // import 'package:meta/meta.dart';
+  //
+  // class C {
+  //   @literal
+  //   const C();
+  // }
+  //
+  // void f() => const C();
+  // ```
   static const HintCode NON_CONST_CALL_TO_LITERAL_CONSTRUCTOR = const HintCode(
       'NON_CONST_CALL_TO_LITERAL_CONSTRUCTOR',
       "This instance creation must be 'const', because the {0} constructor is "
@@ -654,10 +1009,14 @@
   /**
    * Generate a hint for non-const instance creation (with the `new` keyword)
    * using a constructor annotated with `@literal`.
+   *
+   * Parameters:
+   * 0: the name of the class defining the annotated constructor
    */
   static const HintCode NON_CONST_CALL_TO_LITERAL_CONSTRUCTOR_USING_NEW =
-      const HintCode(
-          'NON_CONST_CALL_TO_LITERAL_CONSTRUCTOR_USING_NEW',
+      const HintCodeWithUniqueName(
+          'NON_CONST_CALL_TO_LITERAL_CONSTRUCTOR',
+          'HintCode.NON_CONST_CALL_TO_LITERAL_CONSTRUCTOR_USING_NEW',
           "This instance creation must be 'const', because the {0} constructor "
               "is marked as '@literal'.",
           correction: "Try replacing the 'new' keyword with 'const'.");
@@ -706,39 +1065,89 @@
 
   /**
    * A getter with the override annotation does not override an existing getter.
+   *
+   * No parameters.
    */
-  static const HintCode OVERRIDE_ON_NON_OVERRIDING_GETTER = const HintCode(
-      'OVERRIDE_ON_NON_OVERRIDING_GETTER',
-      "Getter doesn't override an inherited getter.",
-      correction: "Try updating this class to match the superclass, or "
-          "removing the override annotation.");
+  static const HintCode OVERRIDE_ON_NON_OVERRIDING_GETTER =
+      const HintCodeWithUniqueName(
+          'OVERRIDE_ON_NON_OVERRIDING_MEMBER',
+          'HintCode.OVERRIDE_ON_NON_OVERRIDING_GETTER',
+          "The getter doesn't override an inherited getter.",
+          correction: "Try updating this class to match the superclass, or "
+              "removing the override annotation.");
 
   /**
    * A field with the override annotation does not override a getter or setter.
+   *
+   * No parameters.
    */
-  static const HintCode OVERRIDE_ON_NON_OVERRIDING_FIELD = const HintCode(
-      'OVERRIDE_ON_NON_OVERRIDING_FIELD',
-      "Field doesn't override an inherited getter or setter.",
-      correction: "Try updating this class to match the superclass, or "
-          "removing the override annotation.");
+  static const HintCode OVERRIDE_ON_NON_OVERRIDING_FIELD =
+      const HintCodeWithUniqueName(
+          'OVERRIDE_ON_NON_OVERRIDING_MEMBER',
+          'HintCode.OVERRIDE_ON_NON_OVERRIDING_FIELD',
+          "The field doesn't override an inherited getter or setter.",
+          correction: "Try updating this class to match the superclass, or "
+              "removing the override annotation.");
 
   /**
    * A method with the override annotation does not override an existing method.
+   *
+   * No parameters.
    */
-  static const HintCode OVERRIDE_ON_NON_OVERRIDING_METHOD = const HintCode(
-      'OVERRIDE_ON_NON_OVERRIDING_METHOD',
-      "Method doesn't override an inherited method.",
-      correction: "Try updating this class to match the superclass, or "
-          "removing the override annotation.");
+  // #### Description
+  //
+  // The analyzer produces this diagnostic when a class member is annotated with
+  // the `@override` annotation, but the member isn’t declared in any of the
+  // supertypes of the class.
+  //
+  // #### Example
+  //
+  // The following code produces this diagnostic because `m` isn't declared in
+  // any of the supertypes of `C`:
+  //
+  // ```dart
+  // class C {
+  //   @override
+  //   String [!m!]() => '';
+  // }
+  // ```
+  //
+  // #### Common fixes
+  //
+  // If the member is intended to override a member with a different name, then
+  // update the member to have the same name:
+  //
+  // ```dart
+  // class C {
+  //   @override
+  //   String toString() => '';
+  // }
+  // ```
+  //
+  // If the member is intended to override a member that was removed from the
+  // superclass, then consider removing the member from the subclass.
+  //
+  // If the member can't be removed, then remove the annotation.
+  static const HintCode OVERRIDE_ON_NON_OVERRIDING_METHOD =
+      const HintCodeWithUniqueName(
+          'OVERRIDE_ON_NON_OVERRIDING_MEMBER',
+          'HintCode.OVERRIDE_ON_NON_OVERRIDING_METHOD',
+          "The method doesn't override an inherited method.",
+          correction: "Try updating this class to match the superclass, or "
+              "removing the override annotation.");
 
   /**
    * A setter with the override annotation does not override an existing setter.
+   *
+   * No parameters.
    */
-  static const HintCode OVERRIDE_ON_NON_OVERRIDING_SETTER = const HintCode(
-      'OVERRIDE_ON_NON_OVERRIDING_SETTER',
-      "Setter doesn't override an inherited setter.",
-      correction: "Try updating this class to match the superclass, or "
-          "removing the override annotation.");
+  static const HintCode OVERRIDE_ON_NON_OVERRIDING_SETTER =
+      const HintCodeWithUniqueName(
+          'OVERRIDE_ON_NON_OVERRIDING_MEMBER',
+          'HintCode.OVERRIDE_ON_NON_OVERRIDING_SETTER',
+          "The setter doesn't override an inherited setter.",
+          correction: "Try updating this class to match the superclass, or "
+              "removing the override annotation.");
 
   /**
    * It is a bad practice for a package import to reference anything outside the
@@ -1527,7 +1936,8 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because `_x` isn't referenced
+  // anywhere in the library:
   //
   // ```dart
   // class Point {
@@ -1557,7 +1967,8 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because nothing defined in
+  // `dart:async` is referenced in the library:
   //
   // ```dart
   // import [!'dart:async'!];
@@ -1595,7 +2006,8 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because the value of `count` is
+  // never read:
   //
   // ```dart
   // void main() {
diff --git a/pkg/analyzer/lib/src/dart/error/syntactic_errors.dart b/pkg/analyzer/lib/src/dart/error/syntactic_errors.dart
index 5f1bace..442e549 100644
--- a/pkg/analyzer/lib/src/dart/error/syntactic_errors.dart
+++ b/pkg/analyzer/lib/src/dart/error/syntactic_errors.dart
@@ -218,7 +218,8 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because the method `a` doesn't
+  // have a body:
   //
   // ```dart
   // extension E on String {
@@ -244,7 +245,8 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because there is a constructor
+  // declaration in `E`:
   //
   // ```dart
   // extension E on String {
@@ -269,7 +271,8 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because `s` is an instance
+  // field:
   //
   // ```dart
   // extension E on String {
@@ -494,7 +497,8 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because `i` is marked as being
+  // covariant:
   //
   // ```dart
   // extension E on String {
@@ -826,6 +830,9 @@
 
   static const ParserErrorCode TYPEDEF_IN_CLASS = _TYPEDEF_IN_CLASS;
 
+  static const ParserErrorCode TYPE_PARAMETER_ON_CONSTRUCTOR =
+      _TYPE_PARAMETER_ON_CONSTRUCTOR;
+
   /**
    * Parameters:
    * 0: the starting character that was missing
diff --git a/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart b/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart
index f5eff9d..7aad143 100644
--- a/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart
+++ b/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart
@@ -106,6 +106,7 @@
   _NULL_AWARE_CASCADE_OUT_OF_ORDER,
   _MULTIPLE_VARIANCE_MODIFIERS,
   _INVALID_USE_OF_COVARIANT_IN_EXTENSION,
+  _TYPE_PARAMETER_ON_CONSTRUCTOR,
 ];
 
 const ParserErrorCode _ABSTRACT_CLASS_MEMBER = const ParserErrorCode(
@@ -563,6 +564,11 @@
     'TYPE_BEFORE_FACTORY', r"Factory constructors cannot have a return type.",
     correction: "Try removing the type appearing before 'factory'.");
 
+const ParserErrorCode _TYPE_PARAMETER_ON_CONSTRUCTOR = const ParserErrorCode(
+    'TYPE_PARAMETER_ON_CONSTRUCTOR',
+    r"Constructors can't have type parameters.",
+    correction: "Try removing the type parameters.");
+
 const ParserErrorCode _VAR_AND_TYPE = const ParserErrorCode('VAR_AND_TYPE',
     r"Variables can't be declared using both 'var' and a type name.",
     correction: "Try removing 'var.'");
diff --git a/pkg/analyzer/lib/src/dart/resolver/extension_member_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/extension_member_resolver.dart
index 4c3462b..cd96592 100644
--- a/pkg/analyzer/lib/src/dart/resolver/extension_member_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/extension_member_resolver.dart
@@ -28,7 +28,7 @@
 
   TypeProvider get _typeProvider => _resolver.typeProvider;
 
-  TypeSystem get _typeSystem => _resolver.typeSystem;
+  TypeSystemImpl get _typeSystem => _resolver.typeSystem;
 
   /// Return the most specific extension in the current scope for this [type],
   /// that defines the member with the given [name].
@@ -95,10 +95,11 @@
       node.typeArgumentTypes,
     );
 
-    var getterMember =
-        getter != null ? ExecutableMember.from2(getter, substitution) : null;
-    var setterMember =
-        setter != null ? ExecutableMember.from2(setter, substitution) : null;
+    var getterMember = ExecutableMember.from2(getter, substitution);
+    var setterMember = ExecutableMember.from2(setter, substitution);
+
+    getterMember = _resolver.toLegacyElement(getterMember);
+    setterMember = _resolver.toLegacyElement(setterMember);
 
     return ResolutionResult(getter: getterMember, setter: setterMember);
   }
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 15de2d3..6916281 100644
--- a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
@@ -10,7 +10,7 @@
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/dart/element/type_system.dart';
 import 'package:analyzer/src/dart/element/type.dart';
-import 'package:analyzer/src/generated/type_system.dart' show Dart2TypeSystem;
+import 'package:analyzer/src/generated/type_system.dart' show TypeSystemImpl;
 import 'package:analyzer/src/generated/variable_type_provider.dart';
 
 /// Data gathered by flow analysis, retained for testing purposes.
@@ -283,7 +283,7 @@
 
 class TypeSystemTypeOperations
     implements TypeOperations<PromotableElement, DartType> {
-  final Dart2TypeSystem typeSystem;
+  final TypeSystemImpl typeSystem;
 
   TypeSystemTypeOperations(this.typeSystem);
 
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 dfff9aa..6ac99e7 100644
--- a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
@@ -362,7 +362,7 @@
       return result;
     }
 
-    ExecutableElement member = result.getter;
+    var member = _resolver.toLegacyElement(result.getter);
     nameNode.staticElement = member;
 
     if (member.isStatic) {
@@ -387,6 +387,7 @@
       ExtensionElement extension, SimpleIdentifier nameNode, String name) {
     var getter = extension.getGetter(name);
     if (getter != null) {
+      getter = _resolver.toLegacyElement(getter);
       nameNode.staticElement = getter;
       _reportStaticAccessToInstanceMember(getter, nameNode);
       _rewriteAsFunctionExpressionInvocation(node, getter.returnType);
@@ -395,6 +396,7 @@
 
     var method = extension.getMethod(name);
     if (method != null) {
+      method = _resolver.toLegacyElement(method);
       nameNode.staticElement = method;
       _reportStaticAccessToInstanceMember(method, nameNode);
       _setResolution(node, method.type);
@@ -412,7 +414,7 @@
   void _resolveExtensionOverride(MethodInvocation node,
       ExtensionOverride override, SimpleIdentifier nameNode, String name) {
     var result = _extensionResolver.getOverrideMember(override, name);
-    var member = result.getter;
+    var member = _resolver.toLegacyElement(result.getter);
 
     if (member == null) {
       _setDynamicResolution(node);
@@ -464,7 +466,7 @@
     ResolutionResult result =
         _extensionResolver.findExtension(receiverType, name, nameNode);
     if (result.isSingle) {
-      var member = result.getter;
+      var member = _resolver.toLegacyElement(result.getter);
       nameNode.staticElement = member;
       if (member is PropertyAccessorElement) {
         return _rewriteAsFunctionExpressionInvocation(node, member.returnType);
@@ -473,6 +475,7 @@
     } else if (result.isAmbiguous) {
       return;
     }
+
     // We can invoke Object methods on Function.
     var member = _inheritance.getMember(
       _resolver.typeProvider.functionType,
@@ -500,6 +503,7 @@
 
     var target = _inheritance.getMember(receiverType, _currentName);
     if (target != null) {
+      target = _resolver.toLegacyElement(target);
       nameNode.staticElement = target;
       if (target is PropertyAccessorElement) {
         return _rewriteAsFunctionExpressionInvocation(node, target.returnType);
@@ -545,6 +549,7 @@
       MethodInvocation node, SimpleIdentifier nameNode, String name) {
     var element = nameScope.lookup(nameNode, _definingLibrary);
     if (element != null) {
+      element = _resolver.toLegacyElement(element);
       nameNode.staticElement = element;
       if (element is MultiplyDefinedElement) {
         MultiplyDefinedElement multiply = element;
@@ -590,6 +595,7 @@
     var target = _inheritance.getMember(receiverType, _currentName);
 
     if (target != null) {
+      target = _resolver.toLegacyElement(target);
       nameNode.staticElement = target;
       if (target is PropertyAccessorElement) {
         return _rewriteAsFunctionExpressionInvocation(node, target.returnType);
@@ -619,7 +625,7 @@
 
     var result = _extensionResolver.findExtension(receiverType, name, nameNode);
     if (result.isSingle) {
-      var target = result.getter;
+      var target = _resolver.toLegacyElement(result.getter);
       if (target != null) {
         nameNode.staticElement = target;
         _setResolution(node, target.type);
@@ -651,6 +657,7 @@
     // But maybe this is the only one solution.
     var prefixedName = new PrefixedIdentifierImpl.temp(receiver, nameNode);
     var element = nameScope.lookup(prefixedName, _definingLibrary);
+    element = _resolver.toLegacyElement(element);
     nameNode.staticElement = element;
 
     if (element is MultiplyDefinedElement) {
@@ -682,6 +689,7 @@
       _currentName,
       forSuper: true,
     );
+    target = _resolver.toLegacyElement(target);
 
     // If there is that concrete dispatch target, then we are done.
     if (target != null) {
@@ -723,6 +731,7 @@
     }
 
     var element = _resolveElement(receiver, nameNode);
+    element = _resolver.toLegacyElement(element);
     if (element != null) {
       if (element is ExecutableElement) {
         nameNode.staticElement = element;
@@ -804,6 +813,7 @@
           return;
         }
       }
+      call = _resolver.toLegacyElement(call);
       if (call != null && call.kind == ElementKind.METHOD) {
         invocation.staticElement = call;
         rawFunctionType = call.type;
diff --git a/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart b/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart
index 8df0142..bef6eac 100644
--- a/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart
@@ -15,7 +15,6 @@
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/dart/resolver/ast_rewrite.dart';
 import 'package:analyzer/src/dart/resolver/scope.dart';
-import 'package:analyzer/src/dart/resolver/variance.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/generated/declaration_resolver.dart';
 import 'package:analyzer/src/generated/resolver.dart';
@@ -61,6 +60,10 @@
   final AstRewriter _astRewriter;
   final TypeNameResolver _typeNameResolver;
 
+  /// This index is incremented every time we visit a [LibraryDirective].
+  /// There is just one [LibraryElement], so we can support only one node.
+  int _libraryDirectiveIndex = 0;
+
   /// The provider of pre-built children elements from the element being
   /// visited. For example when we visit a method, its element is resynthesized
   /// from the summary, and we get resynthesized elements for type parameters
@@ -161,7 +164,10 @@
     _withNameScope(() {
       var exceptionNode = node.exceptionParameter;
       if (exceptionNode != null) {
-        var element = LocalVariableElementImpl.forNode(exceptionNode);
+        var element = LocalVariableElementImpl(
+          exceptionNode.name,
+          exceptionNode.offset,
+        );
         _elementHolder.enclose(element);
         _nameScope.define(element);
 
@@ -181,7 +187,10 @@
 
       var stackTraceNode = node.stackTraceParameter;
       if (stackTraceNode != null) {
-        var element = LocalVariableElementImpl.forNode(stackTraceNode);
+        var element = LocalVariableElementImpl(
+          stackTraceNode.name,
+          stackTraceNode.offset,
+        );
         _elementHolder.enclose(element);
         _nameScope.define(element);
 
@@ -292,7 +301,7 @@
   @override
   void visitDeclaredIdentifier(DeclaredIdentifier node) {
     var nameNode = node.identifier;
-    var element = LocalVariableElementImpl.forNode(nameNode);
+    var element = LocalVariableElementImpl(nameNode.name, nameNode.offset);
     _elementHolder.enclose(element);
     nameNode.staticElement = element;
 
@@ -322,7 +331,11 @@
     if (_elementWalker != null) {
       element = _elementWalker.getParameter();
     } else {
-      element = DefaultParameterElementImpl.forNode(nameNode);
+      if (nameNode != null) {
+        element = DefaultParameterElementImpl(nameNode.name, nameNode.offset);
+      } else {
+        element = DefaultParameterElementImpl('', -1);
+      }
       _elementHolder.addParameter(element);
 
       _setCodeRange(element, node);
@@ -390,10 +403,12 @@
 
   @override
   void visitExportDirective(ExportDirective node) {
-    super.visitExportDirective(node);
-    if (node.element != null) {
-      _setElementAnnotations(node.metadata, node.element.metadata);
-    }
+    _withElementWalker(null, () {
+      super.visitExportDirective(node);
+      if (node.element != null) {
+        _setElementAnnotations(node.metadata, node.element.metadata);
+      }
+    });
   }
 
   @override
@@ -430,20 +445,26 @@
     FieldFormalParameterElementImpl element;
     if (node.parent is DefaultFormalParameter) {
       element = node.declaredElement;
-    } else if (_elementWalker != null) {
-      element = _elementWalker.getParameter();
     } else {
-      // Only for recovery, this should not happen in valid code.
-      element = FieldFormalParameterElementImpl.forNode(node.identifier);
-      _elementHolder.enclose(element);
-      element.isConst = node.isConst;
-      element.isExplicitlyCovariant = node.covariantKeyword != null;
-      element.isFinal = node.isFinal;
-      // ignore: deprecated_member_use_from_same_package
-      element.parameterKind = node.kind;
-      _setCodeRange(element, node);
+      var nameNode = node.identifier;
+      if (_elementWalker != null) {
+        element = _elementWalker.getParameter();
+      } else {
+        // Only for recovery, this should not happen in valid code.
+        element = FieldFormalParameterElementImpl(
+          nameNode.name,
+          nameNode.offset,
+        );
+        _elementHolder.enclose(element);
+        element.isConst = node.isConst;
+        element.isExplicitlyCovariant = node.covariantKeyword != null;
+        element.isFinal = node.isFinal;
+        // ignore: deprecated_member_use_from_same_package
+        element.parameterKind = node.kind;
+        _setCodeRange(element, node);
+      }
+      nameNode.staticElement = element;
     }
-    node.identifier.staticElement = element;
 
     node.metadata.accept(this);
     _setElementAnnotations(node.metadata, element.metadata);
@@ -602,7 +623,7 @@
       if (_elementWalker != null) {
         element = _elementWalker.getParameter();
       } else {
-        element = new ParameterElementImpl.forNode(nameNode);
+        element = new ParameterElementImpl(nameNode.name, nameNode.offset);
         _elementHolder.addParameter(element);
         element.isConst = node.isConst;
         element.isExplicitlyCovariant = node.covariantKeyword != null;
@@ -703,10 +724,12 @@
 
   @override
   void visitImportDirective(ImportDirective node) {
-    super.visitImportDirective(node);
-    if (node.element != null) {
-      _setElementAnnotations(node.metadata, node.element.metadata);
-    }
+    _withElementWalker(null, () {
+      super.visitImportDirective(node);
+      if (node.element != null) {
+        _setElementAnnotations(node.metadata, node.element.metadata);
+      }
+    });
   }
 
   @override
@@ -735,8 +758,13 @@
   @override
   void visitLibraryDirective(LibraryDirective node) {
     super.visitLibraryDirective(node);
-    if (node.element != null) {
+    ++_libraryDirectiveIndex;
+    if (node.element != null && _libraryDirectiveIndex == 1) {
       _setElementAnnotations(node.metadata, node.element.metadata);
+    } else {
+      for (var annotation in node.metadata) {
+        annotation.elementAnnotation = ElementAnnotationImpl(_unitElement);
+      }
     }
   }
 
@@ -803,10 +831,12 @@
 
   @override
   void visitPartDirective(PartDirective node) {
-    super.visitPartDirective(node);
-    if (node.element != null) {
-      _setElementAnnotations(node.metadata, node.element.metadata);
-    }
+    _withElementWalker(null, () {
+      super.visitPartDirective(node);
+      if (node.element != null) {
+        _setElementAnnotations(node.metadata, node.element.metadata);
+      }
+    });
   }
 
   @override
@@ -819,7 +849,11 @@
       if (_elementWalker != null) {
         element = _elementWalker.getParameter();
       } else {
-        element = ParameterElementImpl.forNode(nameNode);
+        if (nameNode != null) {
+          element = ParameterElementImpl(nameNode.name, nameNode.offset);
+        } else {
+          element = ParameterElementImpl('', -1);
+        }
         _elementHolder.addParameter(element);
 
         _setCodeRange(element, node);
@@ -893,13 +927,6 @@
   void visitTypeParameter(TypeParameter node) {
     TypeParameterElementImpl element = node.declaredElement;
 
-    // TODO (kallentu) : Clean up TypeParameterImpl checks and casting once
-    //  variance is added to the interface.
-    if (node is TypeParameterImpl && node.varianceKeyword != null) {
-      element.variance =
-          Variance.fromKeywordString(node.varianceKeyword.lexeme);
-    }
-
     node.metadata?.accept(this);
     _setElementAnnotations(node.metadata, element.metadata);
 
@@ -908,9 +935,6 @@
       boundNode.accept(this);
       if (_elementWalker == null) {
         element.bound = boundNode.type;
-
-        element.metadata = _createElementAnnotations(node.metadata);
-        _setCodeRange(element, node);
       }
     }
   }
@@ -987,8 +1011,12 @@
       List<Label> labels, bool onSwitchStatement, bool onSwitchMember) {
     for (Label label in labels) {
       var labelName = label.label;
-      var element = LabelElementImpl.forNode(
-          labelName, onSwitchStatement, onSwitchMember);
+      var element = LabelElementImpl(
+        labelName.name,
+        labelName.offset,
+        onSwitchStatement,
+        onSwitchMember,
+      );
       labelName.staticElement = element;
       _elementHolder.enclose(element);
     }
@@ -1006,8 +1034,9 @@
 
   void _buildLocalFunctionElement(FunctionDeclarationStatement statement) {
     var node = statement.functionDeclaration;
-    var element = FunctionElementImpl.forNode(node.name);
-    node.name.staticElement = element;
+    var nameNode = node.name;
+    var element = FunctionElementImpl(nameNode.name, nameNode.offset);
+    nameNode.staticElement = element;
     _nameScope.define(element);
     _elementHolder.enclose(element);
   }
@@ -1021,9 +1050,15 @@
 
       LocalVariableElementImpl element;
       if (isConst && variable.initializer != null) {
-        element = ConstLocalVariableElementImpl.forNode(variableName);
+        element = ConstLocalVariableElementImpl(
+          variableName.name,
+          variableName.offset,
+        );
       } else {
-        element = LocalVariableElementImpl.forNode(variableName);
+        element = LocalVariableElementImpl(
+          variableName.name,
+          variableName.offset,
+        );
       }
       variableName.staticElement = element;
       _elementHolder.enclose(element);
@@ -1048,8 +1083,11 @@
       if (_elementWalker != null) {
         element = _elementWalker.getTypeParameter();
       } else {
-        element = TypeParameterElementImpl.forNode(name);
+        element = TypeParameterElementImpl(name.name, name.offset);
         _elementHolder.addTypeParameter(element);
+
+        element.metadata = _createElementAnnotations(typeParameter.metadata);
+        _setCodeRange(element, typeParameter);
       }
       name.staticElement = element;
       _nameScope.define(element);
diff --git a/pkg/analyzer/lib/src/dart/resolver/variance.dart b/pkg/analyzer/lib/src/dart/resolver/variance.dart
index 3f69514..ccb7fa8 100644
--- a/pkg/analyzer/lib/src/dart/resolver/variance.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/variance.dart
@@ -4,6 +4,7 @@
 
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/element.dart';
 
 /// The variance of a type parameter `X` in a type `T`.
 class Variance {
@@ -33,10 +34,16 @@
       }
     } else if (type is InterfaceType) {
       var result = unrelated;
-      for (var argument in type.typeArguments) {
-        result = result.meet(
-          Variance(typeParameter, argument),
-        );
+      for (int i = 0; i < type.typeArguments.length; ++i) {
+        var argument = type.typeArguments[i];
+        var parameter = type.element.typeParameters[i];
+
+        // TODO (kallentu) : Clean up TypeParameterElementImpl casting once
+        // variance is added to the interface.
+        var parameterVariance =
+            (parameter as TypeParameterElementImpl).variance;
+        result = result
+            .meet(parameterVariance.combine(Variance(typeParameter, argument)));
       }
       return result;
     } else if (type is FunctionType) {
@@ -98,6 +105,23 @@
         'Invalid keyword string for variance: $varianceString');
   }
 
+  /// Returns the associated keyword lexeme.
+  String toKeywordString() {
+    switch (this) {
+      case contravariant:
+        return 'in';
+      case invariant:
+        return 'inout';
+      case covariant:
+        return 'out';
+      case unrelated:
+        return '';
+      default:
+        throw new ArgumentError(
+            'Missing keyword lexeme representation for variance: $this');
+    }
+  }
+
   /// Return `true` if this represents the case when `X` occurs free in `T`, and
   /// `U <: V` implies `[V/X]T <: [U/X]T`.
   bool get isContravariant => this == contravariant;
@@ -156,6 +180,29 @@
   /// [meet] calculates the meet of two elements of such lattice.  It can be
   /// used, for example, to calculate the variance of a typedef type parameter
   /// if it's encountered on the RHS of the typedef multiple times.
+  ///
+  ///       unrelated
+  /// covariant   contravariant
+  ///       invariant
   Variance meet(Variance other) =>
       Variance._fromEncoding(_encoding | other._encoding);
+
+  /// Returns true if this variance is greater than (above) or equal to the
+  /// [other] variance in the partial order induced by the variance lattice.
+  ///
+  ///       unrelated
+  /// covariant   contravariant
+  ///       invariant
+  bool greaterThanOrEqual(Variance other) {
+    if (isUnrelated) {
+      return true;
+    } else if (isCovariant) {
+      return other.isCovariant || other.isInvariant;
+    } else if (isContravariant) {
+      return other.isContravariant || other.isInvariant;
+    } else {
+      assert(isInvariant);
+      return other.isInvariant;
+    }
+  }
 }
diff --git a/pkg/analyzer/lib/src/dart/sdk/sdk.dart b/pkg/analyzer/lib/src/dart/sdk/sdk.dart
index 10e559f..2d46430 100644
--- a/pkg/analyzer/lib/src/dart/sdk/sdk.dart
+++ b/pkg/analyzer/lib/src/dart/sdk/sdk.dart
@@ -83,9 +83,8 @@
   @override
   AnalysisContext get context {
     if (_analysisContext == null) {
-      _analysisContext = new SdkAnalysisContext(_analysisOptions);
-      SourceFactory factory = new SourceFactory([new DartUriResolver(this)]);
-      _analysisContext.sourceFactory = factory;
+      var factory = SourceFactory([DartUriResolver(this)]);
+      _analysisContext = SdkAnalysisContext(_analysisOptions, factory);
     }
     return _analysisContext;
   }
diff --git a/pkg/analyzer/lib/src/error/codes.dart b/pkg/analyzer/lib/src/error/codes.dart
index 240ec8c..4e41047 100644
--- a/pkg/analyzer/lib/src/error/codes.dart
+++ b/pkg/analyzer/lib/src/error/codes.dart
@@ -118,7 +118,8 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because `B` doesn't inherit a
+  // concrete implementation of `a`:
   //
   // ```dart
   // abstract class A {
@@ -448,7 +449,8 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because `mixin` is a built-in
+  // identifier:
   //
   // ```dart
   // extension [!mixin!] on int {}
@@ -936,15 +938,32 @@
               "removing the keyword 'const' from the map.");
 
   /**
-   * 5 Variables: A constant variable must be initialized to a compile-time
-   * constant (12.1) or a compile-time error occurs.
-   *
    * Parameters:
    * 0: the name of the uninitialized final variable
    */
+  // #### Description
+  //
+  // The analyzer produces this diagnostic when a variable that is declared to
+  // be a constant doesn't have an initializer.
+  //
+  // #### Example
+  //
+  // The following code produces this diagnostic because `c` isn't initialized:
+  //
+  // ```dart
+  // const [!c!];
+  // ```
+  //
+  // #### Common fixes
+  //
+  // Add an initializer:
+  //
+  // ```dart
+  // const c = 'c';
+  // ```
   static const CompileTimeErrorCode CONST_NOT_INITIALIZED =
-      const CompileTimeErrorCode('CONST_NOT_INITIALIZED',
-          "The const variable '{0}' must be initialized.",
+      const CompileTimeErrorCode(
+          'CONST_NOT_INITIALIZED', "The constant '{0}' must be initialized.",
           correction: "Try adding an initialization to the declaration.");
 
   /**
@@ -970,7 +989,8 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because the value of `list1` is
+  // `null`, which is neither a list nor a set:
   //
   // ```dart
   // const List<int> list1 = null;
@@ -1001,7 +1021,8 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because the value of `map1` is
+  // `null`, which isn't a map:
   //
   // ```dart
   // const Map<String, int> map1 = null;
@@ -1065,7 +1086,7 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because `i` isn't a constant:
   //
   // ```dart
   // class C {
@@ -1271,7 +1292,8 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because the name `x` is
+  // declared twice:
   //
   // ```dart
   // int x = 0;
@@ -1331,7 +1353,8 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because the string `'a'` is
+  // specified twice:
   //
   // ```dart
   // const Set<String> set = {'a', [!'a'!]};
@@ -1365,7 +1388,8 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because the key `1` is used
+  // twice:
   //
   // ```dart
   // const map = <int, String>{1: 'a', 2: 'b', [!1!]: 'c', 4: 'd'};
@@ -1501,13 +1525,45 @@
               "removing the extends clause.");
 
   /**
-   * 7.9 Superclasses: It is a compile-time error if the extends clause of a
-   * class <i>C</i> includes a type expression that does not denote a class
-   * available in the lexical scope of <i>C</i>.
-   *
    * Parameters:
-   * 0: the name of the superclass that was not found
+   * 0: the name in the extends clause
    */
+  // #### Description
+  //
+  // The analyzer produces this diagnostic when an extends clause contains a
+  // name that is declared to be something other than a class.
+  //
+  // #### Example
+  //
+  // The following code produces this diagnostic because `f` is declared to be a
+  // function:
+  //
+  // ```dart
+  // void f() {}
+  //
+  // class C extends [!f!] {}
+  // ```
+  //
+  // #### Common fixes
+  //
+  // If you want the class to extend a class other than `Object`, then replace
+  // the name in the extends clause with the name of that class:
+  //
+  // ```dart
+  // void f() {}
+  //
+  // class C extends B {}
+  //
+  // class B {}
+  // ```
+  //
+  // If you want the class to extend `Object`, then remove the extends clause:
+  //
+  // ```dart
+  // void f() {}
+  //
+  // class C {}
+  // ```
   static const CompileTimeErrorCode EXTENDS_NON_CLASS =
       const CompileTimeErrorCode(
           'EXTENDS_NON_CLASS', "Classes can only extend other classes.",
@@ -1523,11 +1579,14 @@
   //
   // The analyzer produces this diagnostic when the name of an extension is used
   // in an expression other than in an extension override or to qualify an
-  // access to a static member of the extension.
+  // access to a static member of the extension. Because classes define a type,
+  // the name of a class can be used to refer to the instance of `Type`
+  // representing the type of the class. Extensions, on the other hand, don't
+  // define a type and can't be used as a type literal.
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because `E` is an extension:
   //
   // ```dart
   // extension E on int {
@@ -1570,7 +1629,8 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because the name `a` is being
+  // used for two different members:
   //
   // ```dart
   // extension E on Object {
@@ -1610,7 +1670,8 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because `toString` is defined
+  // by `Object`:
   //
   // ```dart
   // extension E on String {
@@ -1648,15 +1709,15 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because `m` is static:
   //
   // ```dart
   // extension E on String {
-  //   static void staticMethod() {}
+  //   static void m() {}
   // }
   //
   // void f() {
-  //   E('').[!staticMethod!]();
+  //   E('').[!m!]();
   // }
   // ```
   //
@@ -1666,11 +1727,11 @@
   //
   // ```dart
   // extension E on String {
-  //   static void staticMethod() {}
+  //   static void m() {}
   // }
   //
   // void f() {
-  //   E.staticMethod();
+  //   E.m();
   // }
   // ```
   static const CompileTimeErrorCode EXTENSION_OVERRIDE_ACCESS_TO_STATIC_MEMBER =
@@ -1693,7 +1754,7 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because `3` isn't a `String`:
   //
   // ```dart
   // extension E on String {
@@ -1736,11 +1797,14 @@
   // #### Description
   //
   // The analyzer produces this diagnostic when an extension override is used as
-  // the target of a cascade expression.
+  // the target of a cascade expression. The value of a cascade expression
+  // `e..m` is the value of the target `e`, but extension overrides are not
+  // expressions and don't have a value.
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because `E(3)` isn't an
+  // expression:
   //
   // ```dart
   // extension E on int {
@@ -1786,7 +1850,8 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because `E(i)` isn't an
+  // expression:
   //
   // ```dart
   // extension E on int {
@@ -1842,7 +1907,8 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because `f` defines 2
+  // parameters but is invoked with 3 arguments:
   //
   // ```dart
   // void f(int a, int b) {}
@@ -1880,7 +1946,9 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because `f` defines 2
+  // positional parameters but has a named parameter that could be used for the
+  // third argument:
   //
   // ```dart
   // void f(int a, int b, {int c}) {}
@@ -2084,7 +2152,8 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because `x` is a variable
+  // rather than a class or mixin:
   //
   // ```dart
   // var x;
@@ -2139,14 +2208,54 @@
           correction: "Try removing one of the occurrences.");
 
   /**
-   * 7.6.1 Generative Constructors: Note that <b>this</b> is not in scope on the
-   * right hand side of an initializer.
-   *
-   * 12.10 This: It is a compile-time error if this appears in a top-level
-   * function or variable initializer, in a factory constructor, or in a static
-   * method or variable initializer, or in the initializer of an instance
-   * variable.
+   * No parameters.
    */
+  // #### Description
+  //
+  // The analyzer produces this diagnostic when it finds a reference to an
+  // instance member in a constructor's initializer list.
+  //
+  // #### Example
+  //
+  // The following code produces this diagnostic because `defaultX` is an
+  // instance member:
+  //
+  // ```dart
+  // class C {
+  //   int x;
+  //
+  //   C() : x = [!defaultX!];
+  //
+  //   int get defaultX => 0;
+  // }
+  // ```
+  //
+  // #### Common fixes
+  //
+  // If the member can be made static, then do so:
+  //
+  // ```dart
+  // class C {
+  //   int x;
+  //
+  //   C() : x = defaultX;
+  //
+  //   static int get defaultX => 0;
+  // }
+  // ```
+  //
+  // If not, then replace the reference in the initializer with a different
+  // expression that doesn't use an instance member:
+  //
+  // ```dart
+  // class C {
+  //   int x;
+  //
+  //   C() : x = 0;
+  //
+  //   int get defaultX => 0;
+  // }
+  // ```
   static const CompileTimeErrorCode IMPLICIT_THIS_REFERENCE_IN_INITIALIZER =
       const CompileTimeErrorCode('IMPLICIT_THIS_REFERENCE_IN_INITIALIZER',
           "Only static members can be accessed in initializers.");
@@ -2264,17 +2373,74 @@
           correction: "Try removing the initialization.");
 
   /**
-   * 7.6.1 Generative Constructors: An initializing formal has the form
-   * <i>this.id</i>. It is a compile-time error if <i>id</i> is not the name of
-   * an instance variable of the immediately enclosing class.
-   *
    * Parameters:
    * 0: the name of the initializing formal that is not an instance variable in
    *    the immediately enclosing class
-   *
-   * See [INITIALIZING_FORMAL_FOR_STATIC_FIELD], and
-   * [INITIALIZER_FOR_NON_EXISTENT_FIELD].
    */
+  // #### Description
+  //
+  // The analyzer produces this diagnostic when a field formal parameter is
+  // found in a constructor in a class that doesn't declare the field being
+  // initialized.
+  //
+  // #### Example
+  //
+  // The following code produces this diagnostic because the field `x` isn't
+  // defined:
+  //
+  // ```dart
+  // class C {
+  //   int y;
+  //
+  //   C([!this.x!]);
+  // }
+  // ```
+  //
+  // #### Common fixes
+  //
+  // If the field name was wrong, then change it to the name of an existing
+  // field:
+  //
+  // ```dart
+  // class C {
+  //   int y;
+  //
+  //   C(this.y);
+  // }
+  // ```
+  //
+  // If the field name is correct but hasn't yet been defined, then declare the
+  // field:
+  //
+  // ```dart
+  // class C {
+  //   int x;
+  //   int y;
+  //
+  //   C(this.x);
+  // }
+  // ```
+  //
+  // If the parameter is needed but shouldn't initialize a field, then convert
+  // it to a normal parameter and use it:
+  //
+  // ```dart
+  // class C {
+  //   int y;
+  //
+  //   C(int x) : y = x * 2;
+  // }
+  // ```
+  //
+  // If the parameter isn't needed, then remove it:
+  //
+  // ```dart
+  // class C {
+  //   int y;
+  //
+  //   C();
+  // }
+  // ```
   static const CompileTimeErrorCode INITIALIZING_FORMAL_FOR_NON_EXISTENT_FIELD =
       const CompileTimeErrorCode('INITIALIZING_FORMAL_FOR_NON_EXISTENT_FIELD',
           "'{0}' isn't a field in the enclosing class.",
@@ -2518,14 +2684,6 @@
               "making this a required parameter.");
 
   /**
-   * If a class declaration has a member declaration, the signature of that
-   * member declaration becomes the signature in the interface. It's a
-   * compile-time error if that signature is not a valid override of all
-   * super-interface member signatures with the same name. (Not just the
-   * members of the immediate super-interfaces, but all of them. For
-   * non-covariant parameters, it's sufficient to check just the immediate
-   * super-interfaces).
-   *
    * Parameters:
    * 0: the name of the declared member that is not a valid override.
    * 1: the name of the interface that declares the member.
@@ -2533,6 +2691,62 @@
    * 3. the name of the interface with the overridden member.
    * 4. the type of the overridden member.
    */
+  // #### Description
+  //
+  // The analyzer produces this diagnostic when a member of a class is found
+  // that overrides a member from a supertype and the override isn't valid. An
+  // override is valid if all of these are true:
+  // * It allows all of the arguments allowed by the overridden member.
+  // * It doesn't require any arguments that aren't required by the overridden
+  //   member.
+  // * The type of every parameter of the overridden member is assignable to the
+  //   corresponding parameter of the override.
+  // * The return type of the override is assignable to the return type of the
+  //   overridden member.
+  //
+  // #### Example
+  //
+  // The following code produces this diagnostic because the type of the
+  // parameter `s` (`String`) isn't assignable to the type of the parameter `i`
+  // (`int`):
+  //
+  // ```dart
+  // class A {
+  //   void m(int i) {}
+  // }
+  //
+  // class B extends A {
+  //   void [!m!](String s) {}
+  // }
+  // ```
+  //
+  // #### Common fixes
+  //
+  // If the invalid method is intended to override the method from the
+  // superclass, then change it to conform:
+  //
+  // ```dart
+  // class A {
+  //   void m(int i) {}
+  // }
+  //
+  // class B extends A {
+  //   void m(int i) {}
+  // }
+  // ```
+  //
+  // If it isn't intended to override the method from the superclass, then
+  // rename it:
+  //
+  // ```dart
+  // class A {
+  //   void m(int i) {}
+  // }
+  //
+  // class B extends A {
+  //   void m2(String s) {}
+  // }
+  // ```
   static const CompileTimeErrorCode INVALID_OVERRIDE =
       const CompileTimeErrorCode('INVALID_OVERRIDE',
           "'{1}.{0}' ('{2}') isn't a valid override of '{3}.{0}' ('{4}').");
@@ -2621,10 +2835,47 @@
    * Parameters:
    * 0: the name of the extension
    */
+  // #### Description
+  //
+  // The analyzer produces this diagnostic when an extension override is used to
+  // invoke a function but the extension doesn't declare a `call` method.
+  //
+  // #### Example
+  //
+  // The following code produces this diagnostic because the extension `E`
+  // doesn't define a `call` method:
+  //
+  // ```dart
+  // extension E on String {}
+  //
+  // void f() {
+  //   [!E('')!]();
+  // }
+  // ```
+  //
+  // #### Common fixes
+  //
+  // If the extension is intended to define a `call` method, then declare it:
+  //
+  // ```dart
+  // extension E on String {
+  //   int call() => 0;
+  // }
+  //
+  // void f() {
+  //   E('')();
+  // }
+  // ```
+  //
+  // If the extended type defines a `call` method, then remove the extension
+  // override.
+  //
+  // If the `call` method isn't defined, then rewrite the code so that it
+  // doesn't invoke the `call` method.
   static const CompileTimeErrorCode INVOCATION_OF_EXTENSION_WITHOUT_CALL =
       const CompileTimeErrorCode(
           'INVOCATION_OF_EXTENSION_WITHOUT_CALL',
-          "The extension '{0}' does not define a 'call' method so the override "
+          "The extension '{0}' doesn't define a 'call' method so the override "
               "can't be used in an invocation.");
 
   /**
@@ -2671,7 +2922,8 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because the literal has a map
+  // entry even though it's a set literal:
   //
   // ```dart
   // const collection = <String>{[!'a' : 'b'!]};
@@ -2998,9 +3250,34 @@
           'MIXIN_SUPER_CLASS_CONSTRAINT_DISALLOWED_CLASS',
           "'{0}' can't be used as a super-class constraint.");
 
+  /**
+   * No parameters.
+   */
+  // #### Description
+  //
+  // The analyzer produces this diagnostic when a type following the `on`
+  // keyword in a mixin declaration is neither a class nor a mixin.
+  //
+  // #### Example
+  //
+  // The following code produces this diagnostic because `F` is neither a class
+  // nor a mixin:
+  //
+  // ```dart
+  // typedef F = void Function();
+  //
+  // mixin M on [!F!] {}
+  // ```
+  //
+  // #### Common fixes
+  //
+  // If the type was intended to be a class but was mistyped, then replace the
+  // name.
+  //
+  // Otherwise, remove the type from the on clause.
   static const CompileTimeErrorCode MIXIN_SUPER_CLASS_CONSTRAINT_NON_INTERFACE =
       const CompileTimeErrorCode('MIXIN_SUPER_CLASS_CONSTRAINT_NON_INTERFACE',
-          "Only classes and mixins can be used as super-class constraints.");
+          "Only classes and mixins can be used as superclass constraints.");
 
   /**
    * 9.1 Mixin Application: It is a compile-time error if <i>S</i> does not
@@ -3112,7 +3389,7 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because `j` isn't a constant:
   //
   // ```dart
   // void f(int i, int j) {
@@ -3166,12 +3443,47 @@
               "changing the import to not be deferred.");
 
   /**
-   * 6.2.2 Optional Formals: It is a compile-time error if the default value of
-   * an optional parameter is not a compile-time constant.
+   * No parameters.
    */
+  // #### Description
+  //
+  // The analyzer produces this diagnostic when an optional parameter, either
+  // named or positional, has a default value that isn't a compile-time
+  // constant.
+  //
+  // #### Example
+  //
+  // The following code produces this diagnostic:
+  //
+  // ```dart
+  // var defaultValue = 3;
+  //
+  // void f([int value = [!defaultValue!]]) {}
+  // ```
+  //
+  // #### Common fixes
+  //
+  // If the default value can be converted to be a constant, then convert it:
+  //
+  // ```dart
+  // const defaultValue = 3;
+  //
+  // void f([int value = defaultValue]) {}
+  // ```
+  //
+  // If the default value needs to change over time, then apply the default
+  // value inside the function:
+  //
+  // ```dart
+  // var defaultValue = 3;
+  //
+  // void f([int value]) {
+  //   value ??= defaultValue;
+  // }
+  // ```
   static const CompileTimeErrorCode NON_CONSTANT_DEFAULT_VALUE =
       const CompileTimeErrorCode('NON_CONSTANT_DEFAULT_VALUE',
-          "Default values of an optional parameter must be constant.");
+          "The default value of an optional parameter must be constant.");
 
   /**
    * 6.2.2 Optional Formals: It is a compile-time error if the default value of
@@ -3262,7 +3574,7 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic beause `a` isn't a constant:
   //
   // ```dart
   // var a = 'a';
@@ -3315,7 +3627,7 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because `a` isn't a constant:
   //
   // ```dart
   // var a = 'a';
@@ -3486,7 +3798,8 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because `f` declares two
+  // required parameters, but only one argument is provided:
   //
   // ```dart
   // void f(int a, int b) {}
@@ -3607,7 +3920,7 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because `l` isn't a `Map`:
   //
   // ```dart
   // var l =  <String>['a', 'b'];
@@ -4009,7 +4322,8 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because `i` is used before it
+  // is declared:
   //
   // ```dart
   // void f() {
@@ -4119,7 +4433,8 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because `super` can't be used
+  // in an extension:
   //
   // ```dart
   // extension E on Object {
@@ -4186,7 +4501,8 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because `String` isn't a
+  // subclass of `num`:
   //
   // ```dart
   // class A<E extends num> {}
@@ -4219,10 +4535,9 @@
           "Typedefs can't reference themselves directly or recursively via "
               "another typedef.");
 
-  static const CompileTimeErrorCode TYPE_PARAMETER_ON_CONSTRUCTOR =
-      const CompileTimeErrorCode('TYPE_PARAMETER_ON_CONSTRUCTOR',
-          "Constructors can't have type parameters.",
-          correction: "Try removing the type parameters.");
+  @Deprecated('Use ParserErrorCode.TYPE_PARAMETER_ON_CONSTRUCTOR')
+  static const ParserErrorCode TYPE_PARAMETER_ON_CONSTRUCTOR =
+      ParserErrorCode.TYPE_PARAMETER_ON_CONSTRUCTOR;
 
   /**
    * No parameters.
@@ -4234,7 +4549,8 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because the name `undefined`
+  // isn't defined:
   //
   // ```dart
   // [!@undefined!]
@@ -4281,7 +4597,7 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because `Piont` isn't defined:
   //
   // ```dart
   // class Point {}
@@ -4672,7 +4988,8 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because `m` doesn't declare a
+  // named parameter named `a`:
   //
   // ```dart
   // class C {
@@ -4747,7 +5064,8 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because `m` is a static member
+  // of the extended type `C`:
   //
   // ```dart
   // class C {
@@ -4889,23 +5207,43 @@
           'URI_WITH_INTERPOLATION', "URIs can't use string interpolation.");
 
   /**
-   * 7.1.1 Operators: It is a compile-time error if the arity of the
-   * user-declared operator []= is not 2. It is a compile time error if the
-   * arity of a user-declared operator with one of the names: &lt;, &gt;, &lt;=,
-   * &gt;=, ==, +, /, ~/, *, %, |, ^, &, &lt;&lt;, &gt;&gt;, [] is not 1. It is
-   * a compile time error if the arity of the user-declared operator - is not 0
-   * or 1. It is a compile time error if the arity of the user-declared operator
-   * ~ is not 0.
-   *
    * Parameters:
    * 0: the name of the declared operator
    * 1: the number of parameters expected
    * 2: the number of parameters found in the operator declaration
    */
+  // #### Description
+  //
+  // The analyzer produces this diagnostic when a declaration of an operator has
+  // the wrong number of parameters.
+  //
+  // #### Example
+  //
+  // The following code produces this diagnostic because the operator `+` must
+  // have a single parameter corresponding to the right operand:
+  //
+  // ```dart
+  // class C {
+  //   int operator [!+!](a, b) => 0;
+  // }
+  // ```
+  //
+  // #### Common fixes
+  //
+  // Add or remove parameters to match the required number:
+  //
+  // ```dart
+  // class C {
+  //   int operator +(a) => 0;
+  // }
+  // ```
+  // TODO(brianwilkerson) It would be good to add a link to the spec or some
+  //  other documentation that lists the number of parameters for each operator,
+  //  but I don't know what to link to.
   static const CompileTimeErrorCode WRONG_NUMBER_OF_PARAMETERS_FOR_OPERATOR =
       const CompileTimeErrorCode(
           'WRONG_NUMBER_OF_PARAMETERS_FOR_OPERATOR',
-          "Operator '{0}' should declare exactly {1} parameter(s), but {2} "
+          "Operator '{0}' should declare exactly {1} parameters, but {2} "
               "found.");
 
   /**
@@ -4940,7 +5278,61 @@
     'WRONG_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE',
     "'{0}' can't be used contravariantly or invariantly in '{1}'.",
     correction: "Try not using class type parameters in types of formal "
-        "parameters of function types.",
+        "parameters of function types, nor in explicitly contravariant or "
+        "invariant superinterfaces.",
+  );
+
+  /**
+   * Let `C` be a generic class that declares a formal type parameter `X`.
+   *
+   * If `X` is explicitly contravariant then it is a compile-time error for
+   * `X` to occur in a non-contravariant position in a member signature in the
+   * body of `C`, except when `X` is in a contravariant position in the type
+   * annotation of a covariant formal parameter.
+   *
+   * If `X` is explicitly covariant then it is a compile-time error for
+   * `X` to occur in a non-covariant position in a member signature in the
+   * body of `C`, except when `X` is in a covariant position in the type
+   * annotation of a covariant formal parameter.
+   *
+   * Parameters:
+   * 0: the variance modifier defined for {0}
+   * 1: the name of the type parameter
+   * 2: the variance position that the type parameter {1} is in
+   */
+  static const CompileTimeErrorCode WRONG_TYPE_PARAMETER_VARIANCE_POSITION =
+      const CompileTimeErrorCode(
+    'WRONG_TYPE_PARAMETER_VARIANCE_POSITION',
+    "The '{0}' type parameter '{1}' can't be used in an '{2}' position.",
+    correction: "Try removing the type parameter or change the explicit "
+        "variance modifier declaration for the type parameter to another one of"
+        " 'in', 'out', or 'inout'.",
+  );
+
+  /**
+   * Let `C` be a generic class that declares a formal type parameter `X`, and
+   * assume that `T` is a direct superinterface of `C`.
+   *
+   * It is a compile-time error if `X` is explicitly defined as a covariant or
+   * 'in' type parameter and `X` occurs in a non-covariant position in `T`.
+   * It is a compile-time error if `X` is explicitly defined as a contravariant
+   * or 'out' type parameter and `X` occurs in a non-contravariant position in
+   * `T`.
+   *
+   * Parameters:
+   * 0: the name of the type parameter
+   * 1: the variance modifier defined for {0}
+   * 2: the variance position of the type parameter {0} in the
+   *    superinterface {3}
+   * 3: the name of the superinterface
+   */
+  static const CompileTimeErrorCode
+      WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE =
+      const CompileTimeErrorCode(
+    'WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE',
+    "'{0}' is an '{1}' type parameter and can't be used in an '{2}' position in '{3}'.",
+    correction: "Try using 'in' type parameters in 'in' positions and 'out' "
+        "type parameters in 'out' positions in the superinterface.",
   );
 
   /**
@@ -5150,7 +5542,8 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because `Binary` is the name of
+  // a function type, not a function:
   //
   // ```dart
   // typedef Binary = int Function(int, int);
@@ -5189,18 +5582,37 @@
               "invoked.");
 
   /**
-   * 12.20 Conditional: It is a static type warning if the type of
-   * <i>e<sub>1</sub></i> may not be assigned to bool.
-   *
-   * 13.5 If: It is a static type warning if the type of the expression <i>b</i>
-   * may not be assigned to bool.
-   *
-   * 13.7 While: It is a static type warning if the type of <i>e</i> may not be
-   * assigned to bool.
-   *
-   * 13.8 Do: It is a static type warning if the type of <i>e</i> cannot be
-   * assigned to bool.
+   * No parameters.
    */
+  // #### Description
+  //
+  // The analyzer produces this diagnostic when a condition, such as an `if` or
+  // `while` loop, doesn't have the static type `bool`.
+  //
+  // #### Example
+  //
+  // The following code produces this diagnostic because `x` has the static type
+  // `int`:
+  //
+  // ```dart
+  // void f(int x) {
+  //   if ([!x!]) {
+  //     // ...
+  //   }
+  // }
+  // ```
+  //
+  // #### Common fixes
+  //
+  // Change the condition so that it produces a Boolean value:
+  //
+  // ```dart
+  // void f(int x) {
+  //   if (x == 0) {
+  //     // ...
+  //   }
+  // }
+  // ```
   static const StaticTypeWarningCode NON_BOOL_CONDITION =
       const StaticTypeWarningCode(
           'NON_BOOL_CONDITION', "Conditions must have a static type of 'bool'.",
@@ -5275,15 +5687,13 @@
           isUnresolvedIdentifier: true);
 
   /**
-   * 13.11 Return: It is a static type warning if the type of <i>e</i> may not
-   * be assigned to the declared return type of the immediately enclosing
-   * function.
-   *
    * Parameters:
    * 0: the return type as declared in the return statement
    * 1: the expected return type as defined by the method
    * 2: the name of the method
    */
+  @Deprecated('Use either RETURN_OF_INVALID_TYPE_FROM_FUNCTION or '
+      'RETURN_OF_INVALID_TYPE_FROM_METHOD')
   static const StaticTypeWarningCode RETURN_OF_INVALID_TYPE =
       const StaticTypeWarningCode(
           'RETURN_OF_INVALID_TYPE',
@@ -5306,6 +5716,60 @@
               "closure.");
 
   /**
+   * Parameters:
+   * 0: the return type as declared in the return statement
+   * 1: the expected return type as defined by the method
+   * 2: the name of the method
+   */
+  // #### Description
+  //
+  // The analyzer produces this diagnostic when a method or function returns a
+  // value whose type isn't assignable to the declared return type.
+  //
+  // #### Example
+  //
+  // The following code produces this diagnostic because `f` has a return type
+  // of `String` but is returning an `int`:
+  //
+  // ```dart
+  // String f() => [!3!];
+  // ```
+  //
+  // #### Common fixes
+  //
+  // If the return type is correct, then replace the value being returned with a
+  // value of the correct type, possibly by converting the existing value:
+  //
+  // ```dart
+  // String f() => 3.toString();
+  // ```
+  //
+  // If the value is correct, then change the return type to match:
+  //
+  // ```dart
+  // int f() => 3;
+  // ```
+  static const StaticTypeWarningCode RETURN_OF_INVALID_TYPE_FROM_FUNCTION =
+      const StaticTypeWarningCodeWithUniqueName(
+          'RETURN_OF_INVALID_TYPE',
+          'StaticTypeWarningCode.RETURN_OF_INVALID_TYPE_FROM_FUNCTION',
+          "A value of type '{0} can't be returned from function '{2}' because it "
+              "has a return type of '{1}'.");
+
+  /**
+   * Parameters:
+   * 0: the return type as declared in the return statement
+   * 1: the expected return type as defined by the method
+   * 2: the name of the method
+   */
+  static const StaticTypeWarningCode RETURN_OF_INVALID_TYPE_FROM_METHOD =
+      const StaticTypeWarningCodeWithUniqueName(
+          'RETURN_OF_INVALID_TYPE',
+          'StaticTypeWarningCode.RETURN_OF_INVALID_TYPE_FROM_METHOD',
+          "A value of type '{0} can't be returned from method '{2}' because it has "
+              "a return type of '{1}'.");
+
+  /**
    * 10 Generics: It is a static type warning if a type parameter is a supertype
    * of its upper bound.
    *
@@ -5348,7 +5812,8 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because the name `emty` isn't
+  // defined:
   //
   // ```dart
   // List<int> empty() => [];
@@ -5396,7 +5861,8 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because `String` has no member
+  // named `len`:
   //
   // ```dart
   // int f(String s) => s.[!len!];
@@ -5434,7 +5900,8 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because the identifier
+  // `removeMiddle` isn't defined:
   //
   // ```dart
   // int f(List<int> l) => l.[!removeMiddle!]();
@@ -5458,25 +5925,37 @@
           hasPublishedDocs: true);
 
   /**
-   * 12.18 Assignment: Evaluation of an assignment of the form
-   * <i>e<sub>1</sub></i>[<i>e<sub>2</sub></i>] = <i>e<sub>3</sub></i> is
-   * equivalent to the evaluation of the expression (a, i, e){a.[]=(i, e);
-   * return e;} (<i>e<sub>1</sub></i>, <i>e<sub>2</sub></i>,
-   * <i>e<sub>2</sub></i>).
-   *
-   * 12.29 Assignable Expressions: An assignable expression of the form
-   * <i>e<sub>1</sub></i>[<i>e<sub>2</sub></i>] is evaluated as a method
-   * invocation of the operator method [] on <i>e<sub>1</sub></i> with argument
-   * <i>e<sub>2</sub></i>.
-   *
-   * 12.15.1 Ordinary Invocation: Let <i>T</i> be the static type of <i>o</i>.
-   * It is a static type warning if <i>T</i> does not have an accessible
-   * instance member named <i>m</i>.
-   *
    * Parameters:
    * 0: the name of the operator
    * 1: the name of the enclosing type where the operator is being looked for
    */
+  // #### Description
+  //
+  // The analyzer produces this diagnostic when a user-definable operator is
+  // invoked on an object for which the operator isn't defined.
+  //
+  // #### Example
+  //
+  // The following code produces this diagnostic because the class `C` doesn't
+  // define the operator `+`:
+  //
+  // ```dart
+  // class C {}
+  //
+  // C f(C c) => c [!+!] 2;
+  // ```
+  //
+  // #### Common fixes
+  //
+  // If the operator should be defined for the class, then define it:
+  //
+  // ```dart
+  // class C {
+  //   C operator +(int i) => this;
+  // }
+  //
+  // C f(C c) => c + 2;
+  // ```
   static const StaticTypeWarningCode UNDEFINED_OPERATOR =
       const StaticTypeWarningCode('UNDEFINED_OPERATOR',
           "The operator '{0}' isn't defined for the class '{1}'.",
@@ -5493,7 +5972,8 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because `dart:core` doesn't
+  // define anything named `a`:
   //
   // ```dart
   // import 'dart:core' as p;
@@ -5533,7 +6013,8 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because there isn't a setter
+  // named `z`:
   //
   // ```dart
   // class C {
@@ -5594,7 +6075,8 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because `Object` doesn't define
+  // a member named `n`:
   //
   // ```dart
   // class C {
@@ -5683,17 +6165,38 @@
           correction: "Try adding '{0}.' before the name.");
 
   /**
-   * 15.8 Parameterized Types: It is a static type warning if <i>G</i> is not a
-   * generic type with exactly <i>n</i> type parameters.
-   *
    * Parameters:
    * 0: the name of the type being referenced (<i>G</i>)
    * 1: the number of type parameters that were declared
    * 2: the number of type arguments provided
-   *
-   * See [CompileTimeErrorCode.CONST_WITH_INVALID_TYPE_PARAMETERS], and
-   * [CompileTimeErrorCode.NEW_WITH_INVALID_TYPE_PARAMETERS].
    */
+  // #### Description
+  //
+  // The analyzer produces this diagnostic when a type that has type parameters
+  // is used and type arguments are provided, but the number of type arguments
+  // isn't the same as the number of type parameters.
+  //
+  // #### Example
+  //
+  // The following code produces this diagnostic because `C` has one type
+  // parameter but two type arguments are provided:
+  //
+  // ```dart
+  // class C<E> {}
+  //
+  // void f([!C<int, int>!] x) {}
+  // ```
+  //
+  // #### Common fixes
+  //
+  // Add or remove type arguments, as necessary, to match the number of type
+  // parameters defined for the type:
+  //
+  // ```dart
+  // class C<E> {}
+  //
+  // void f(C<int> x) {}
+  // ```
   static const StaticTypeWarningCode WRONG_NUMBER_OF_TYPE_ARGUMENTS =
       const StaticTypeWarningCode(
           'WRONG_NUMBER_OF_TYPE_ARGUMENTS',
@@ -5805,6 +6308,17 @@
   ErrorType get type => ErrorType.STATIC_TYPE_WARNING;
 }
 
+class StaticTypeWarningCodeWithUniqueName extends StaticTypeWarningCode {
+  @override
+  final String uniqueName;
+
+  const StaticTypeWarningCodeWithUniqueName(
+      String name, this.uniqueName, String message,
+      {String correction, bool hasPublishedDocs})
+      : super(name, message,
+            correction: correction, hasPublishedDocs: hasPublishedDocs);
+}
+
 /**
  * The error codes used for static warnings. The convention for this class is
  * for the name of the error code to indicate the problem that caused the error
@@ -5813,19 +6327,74 @@
  */
 class StaticWarningCode extends AnalyzerErrorCode {
   /**
-   * 14.1 Imports: If a name <i>N</i> is referenced by a library <i>L</i> and
-   * <i>N</i> is introduced into the top level scope <i>L</i> by more than one
-   * import then:
-   * 1. A static warning occurs.
-   * 2. If <i>N</i> is referenced as a function, getter or setter, a
-   *    <i>NoSuchMethodError</i> is raised.
-   * 3. If <i>N</i> is referenced as a type, it is treated as a malformed type.
-   *
    * Parameters:
    * 0: the name of the ambiguous type
    * 1: the name of the first library that the type is found
    * 2: the name of the second library that the type is found
    */
+  // #### Description
+  //
+  // The analyzer produces this diagnostic when a name is referenced that is
+  // declared in two or more imported libraries.
+  //
+  // #### Example
+  //
+  // Given a library (`a.dart`) that defines a class (`C` in this example):
+  //
+  // ```dart
+  // %uri="lib/a.dart"
+  // class A {}
+  // class C {}
+  // ```
+  //
+  // And a library (`b.dart`) that defines a different class with the same name:
+  //
+  // ```dart
+  // %uri="lib/b.dart"
+  // class B {}
+  // class C {}
+  // ```
+  //
+  // The following code produces this diagnostic:
+  //
+  // ```dart
+  // import 'a.dart';
+  // import 'b.dart';
+  //
+  // void f([!C!] c1, [!C!] c2) {}
+  // ```
+  //
+  // #### Common fixes
+  //
+  // If any of the libraries aren't needed, then remove the import directives
+  // for them:
+  //
+  // ```dart
+  // import 'a.dart';
+  //
+  // void f(C c1, C c2) {}
+  // ```
+  //
+  // If the name is still defined by more than one library, then add a `hide`
+  // clause to the import directives for all except one library:
+  //
+  // ```dart
+  // import 'a.dart' hide C;
+  // import 'b.dart';
+  //
+  // void f(C c1, C c2) {}
+  // ```
+  //
+  // If you must be able to reference more than one of these types, then add a
+  // prefix to each of the import directives, and qualify the references with
+  // the appropriate prefix:
+  //
+  // ```dart
+  // import 'a.dart' as a;
+  // import 'b.dart' as b;
+  //
+  // void f(a.C c1, b.C c2) {}
+  // ```
   static const StaticWarningCode AMBIGUOUS_IMPORT = const StaticWarningCode(
       'AMBIGUOUS_IMPORT', "The name '{0}' is defined in the libraries {1}.",
       correction: "Try using 'as prefix' for one of the import directives, or "
@@ -5843,7 +6412,8 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because a `num` can't be
+  // assigned to a `String`:
   //
   // ```dart
   // String f(String x) => x;
@@ -5924,13 +6494,62 @@
           correction: "Try making '{0}' non-final.");
 
   /**
-   * 5 Variables: Attempting to assign to a final variable elsewhere will cause
-   * a NoSuchMethodError to be thrown, because no setter is defined for it. The
-   * assignment will also give rise to a static warning for the same reason.
+   * No parameters.
    */
+  // #### Description
+  //
+  // The analyzer produces this diagnostic when a reference to a setter is
+  // found; there is no setter defined for the type; but there is a getter
+  // defined with the same name.
+  //
+  // #### Example
+  //
+  // The following code produces this diagnostic because there is no setter
+  // named `x` in `C`, but there is a getter named `x`:
+  //
+  // ```dart
+  // class C {
+  //   int get x => 0;
+  //   set y(int p) {}
+  // }
+  //
+  // void f(C c) {
+  //   c.[!x!] = 1;
+  // }
+  // ```
+  //
+  // #### Common fixes
+  //
+  // If you want to invoke an existing setter, then correct the name:
+  //
+  // ```dart
+  // class C {
+  //   int get x => 0;
+  //   set y(int p) {}
+  // }
+  //
+  // void f(C c) {
+  //   c.y = 1;
+  // }
+  // ```
+  //
+  // If you want to invoke the setter but it just doesn't exist yet, then
+  // declare it:
+  //
+  // ```dart
+  // class C {
+  //   int get x => 0;
+  //   set x(int p) {}
+  //   set y(int p) {}
+  // }
+  //
+  // void f(C c) {
+  //   c.x = 1;
+  // }
+  // ```
   static const StaticWarningCode ASSIGNMENT_TO_FINAL_NO_SETTER =
       const StaticWarningCode('ASSIGNMENT_TO_FINAL_NO_SETTER',
-          "No setter named '{0}' in class '{1}'.",
+          "There isn’t a setter named '{0}' in class '{1}'.",
           correction:
               "Try correcting the name to reference an existing setter, or "
               "declare the setter.");
@@ -5986,7 +6605,8 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because `x` is a variable, not
+  // a type:
   //
   // ```dart
   // num x = 0;
@@ -6009,13 +6629,46 @@
       hasPublishedDocs: true);
 
   /**
-   * 7.4 Abstract Instance Members: It is a static warning if an abstract member
-   * is declared or inherited in a concrete class.
-   *
    * Parameters:
    * 0: the name of the abstract method
    * 1: the name of the enclosing class
    */
+  // #### Description
+  //
+  // The analyzer produces this diagnostic when a member of a concrete class is
+  // found that doesn't have a concrete implementation. Concrete classes aren't
+  // allowed to contain abstract members.
+  //
+  // #### Example
+  //
+  // The following code produces this diagnostic because `m` is an abstract
+  // method but `C` isn't an abstract class:
+  //
+  // ```dart
+  // class C {
+  //   [!void m();!]
+  // }
+  // ```
+  //
+  // #### Common fixes
+  //
+  // If it's valid to create instances of the class, provide an implementation
+  // for the member:
+  //
+  // ```dart
+  // class C {
+  //   void m() {}
+  // }
+  // ```
+  //
+  // If it isn't valid to create instances of the class, mark the class as being
+  // abstract:
+  //
+  // ```dart
+  // abstract class C {
+  //   void m();
+  // }
+  // ```
   static const StaticWarningCode CONCRETE_CLASS_WITH_ABSTRACT_MEMBER =
       const StaticWarningCode('CONCRETE_CLASS_WITH_ABSTRACT_MEMBER',
           "'{0}' must have a method body because '{1}' isn't abstract.",
@@ -6136,7 +6789,8 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because `x` doesn't have an
+  // initializer:
   //
   // ```dart
   // final [!x!];
@@ -6180,57 +6834,122 @@
           hasPublishedDocs: true);
 
   /**
-   * 7.6.1 Generative Constructors: Each final instance variable <i>f</i>
-   * declared in the immediately enclosing class must have an initializer in
-   * <i>k</i>'s initializer list unless it has already been initialized by one
-   * of the following means:
-   * * Initialization at the declaration of <i>f</i>.
-   * * Initialization by means of an initializing formal of <i>k</i>.
-   * or a static warning occurs.
-   *
    * Parameters:
    * 0: the name of the uninitialized final variable
    */
+  // #### Description
+  //
+  // The analyzer produces this diagnostic when a class defines one or more
+  // final instance fields without initializers and has at least one constructor
+  // that doesn't initialize those fields. All final instance fields must be
+  // initialized when the instance is created, either by the field's initializer
+  // or by the constructor.
+  //
+  // #### Example
+  //
+  // The following code produces this diagnostic:
+  //
+  // ```dart
+  // class C {
+  //   final String value;
+  //
+  //   [!C!]();
+  // }
+  // ```
+  //
+  // #### Common fixes
+  //
+  // If the value should be passed in to the constructor directly, then use a
+  // field formal parameter to initialize the field `value`:
+  //
+  // ```dart
+  // class C {
+  //   final String value;
+  //
+  //   C(this.value);
+  // }
+  // ```
+  //
+  // If the value should be computed indirectly from a value provided by the
+  // caller, then add a parameter and include an initializer:
+  //
+  // ```dart
+  // class C {
+  //   final String value;
+  //
+  //   C(Object o) : value = o.toString();
+  // }
+  // ```
+  //
+  // If the value of the field doesn't depend on values that can be passed to
+  // the constructor, then add an initializer for the field as part of the field
+  // declaration:
+  //
+  // ```dart
+  // class C {
+  //   final String value = '';
+  //
+  //   C();
+  // }
+  // ```
+  //
+  // If the value of the field doesn't depend on values that can be passed to
+  // the constructor but different constructors need to initialize it to
+  // different values, then add an initializer for the field in the initializer
+  // list:
+  //
+  // ```dart
+  // class C {
+  //   final String value;
+  //
+  //   C() : value = '';
+  //
+  //   C.named() : value = 'c';
+  // }
+  // ```
+  //
+  // However, if the value is the same for all instances, then consider using a
+  // static field instead of an instance field:
+  //
+  // ```dart
+  // class C {
+  //   static const String value = '';
+  //
+  //   C();
+  // }
+  // ```
   static const StaticWarningCode FINAL_NOT_INITIALIZED_CONSTRUCTOR_1 =
-      const StaticWarningCode('FINAL_NOT_INITIALIZED_CONSTRUCTOR_1',
-          "The final variable '{0}' must be initialized.",
+      const StaticWarningCodeWithUniqueName(
+          'FINAL_NOT_INITIALIZED_CONSTRUCTOR',
+          'StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_1',
+          "All final variables must be initialized, but '{0}' is not.",
           correction: "Try adding an initializer for the field.");
 
   /**
-   * 7.6.1 Generative Constructors: Each final instance variable <i>f</i>
-   * declared in the immediately enclosing class must have an initializer in
-   * <i>k</i>'s initializer list unless it has already been initialized by one
-   * of the following means:
-   * * Initialization at the declaration of <i>f</i>.
-   * * Initialization by means of an initializing formal of <i>k</i>.
-   * or a static warning occurs.
-   *
    * Parameters:
    * 0: the name of the uninitialized final variable
    * 1: the name of the uninitialized final variable
    */
   static const StaticWarningCode FINAL_NOT_INITIALIZED_CONSTRUCTOR_2 =
-      const StaticWarningCode('FINAL_NOT_INITIALIZED_CONSTRUCTOR_2',
-          "The final variables '{0}' and '{1}' must be initialized.",
+      const StaticWarningCodeWithUniqueName(
+          'FINAL_NOT_INITIALIZED_CONSTRUCTOR',
+          'StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_2',
+          "All final variables must be initialized, but '{0}' and '{1}' are "
+              "not.",
           correction: "Try adding initializers for the fields.");
 
   /**
-   * 7.6.1 Generative Constructors: Each final instance variable <i>f</i>
-   * declared in the immediately enclosing class must have an initializer in
-   * <i>k</i>'s initializer list unless it has already been initialized by one
-   * of the following means:
-   * * Initialization at the declaration of <i>f</i>.
-   * * Initialization by means of an initializing formal of <i>k</i>.
-   * or a static warning occurs.
-   *
    * Parameters:
    * 0: the name of the uninitialized final variable
    * 1: the name of the uninitialized final variable
    * 2: the number of additional not initialized variables that aren't listed
    */
   static const StaticWarningCode FINAL_NOT_INITIALIZED_CONSTRUCTOR_3_PLUS =
-      const StaticWarningCode('FINAL_NOT_INITIALIZED_CONSTRUCTOR_3',
-          "The final variables '{0}', '{1}' and {2} more must be initialized.",
+      const StaticWarningCodeWithUniqueName(
+          'FINAL_NOT_INITIALIZED_CONSTRUCTOR',
+          'StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_3',
+          "All final variables must be initialized, but '{0}', '{1}', and {2} "
+              "others are not.",
           correction: "Try adding initializers for the fields.");
 
   /**
@@ -6286,22 +7005,45 @@
           errorSeverity: ErrorSeverity.WARNING);
 
   /**
-   * 12.6 Lists: A run-time list literal &lt;<i>E</i>&gt; [<i>e<sub>1</sub></i>
-   * &hellip; <i>e<sub>n</sub></i>] is evaluated as follows:
-   * * The operator []= is invoked on <i>a</i> with first argument <i>i</i> and
-   *   second argument <i>o<sub>i+1</sub></i><i>, 1 &lt;= i &lt;= n</i>
-   *
-   * 12.14.2 Binding Actuals to Formals: Let <i>T<sub>i</sub></i> be the static
-   * type of <i>a<sub>i</sub></i>, let <i>S<sub>i</sub></i> be the type of
-   * <i>p<sub>i</sub>, 1 &lt;= i &lt;= n+k</i> and let <i>S<sub>q</sub></i> be
-   * the type of the named parameter <i>q</i> of <i>f</i>. It is a static
-   * warning if <i>T<sub>j</sub></i> may not be assigned to <i>S<sub>j</sub>, 1
-   * &lt;= j &lt;= m</i>.
-   *
    * Parameters:
    * 0: the actual type of the list element
    * 1: the expected type of the list element
    */
+  // #### Description
+  //
+  // The analyzer produces this diagnostic when the type of an element in a list
+  // literal isn't assignable to the element type of the list.
+  //
+  // #### Example
+  //
+  // The following code produces this diagnostic because `2.5` is a double, and
+  // the list can hold only integers:
+  //
+  // ```dart
+  // List<int> x = [1, [!2.5!], 3];
+  // ```
+  //
+  // #### Common fixes
+  //
+  // If you intended to add a different object to the list, then replace the
+  // element with an expression that computes the intended object:
+  //
+  // ```dart
+  // List<int> x = [1, 2, 3];
+  // ```
+  //
+  // If the object shouldn't be in the list, then remove the element:
+  //
+  // ```dart
+  // List<int> x = [1, 3];
+  // ```
+  //
+  // If the object being computed is correct, then widen the element type of the
+  // list to allow all of the different types of objects it needs to contain:
+  //
+  // ```dart
+  // List<num> x = [1, 2.5, 3];
+  // ```
   static const StaticWarningCode LIST_ELEMENT_TYPE_NOT_ASSIGNABLE =
       const StaticWarningCode('LIST_ELEMENT_TYPE_NOT_ASSIGNABLE',
           "The element type '{0}' can't be assigned to the list type '{1}'.");
@@ -6385,16 +7127,10 @@
           correction: "Try adding a case clause for the missing constant, or "
               "adding a default clause.");
 
-  /**
-   * 13.12 Return: It is a static warning if a function contains both one or
-   * more return statements of the form <i>return;</i> and one or more return
-   * statements of the form <i>return e;</i>.
-   */
+  @Deprecated('No longer an error in the spec and no longer generated')
   static const StaticWarningCode MIXED_RETURN_TYPES = const StaticWarningCode(
       'MIXED_RETURN_TYPES',
       "Functions can't include return statements both with and without values.",
-      // TODO(brianwilkerson) Split this error code depending on whether the
-      // function declares a return type.
       correction: "Try making all the return statements consistent "
           "(either include a value or not).");
 
@@ -6475,19 +7211,6 @@
               "Try using one of the named constructors defined in '{0}'.");
 
   /**
-   * 7.9.1 Inheritance and Overriding: It is a static warning if a non-abstract
-   * class inherits an abstract method.
-   *
-   * 7.10 Superinterfaces: Let <i>C</i> be a concrete class that does not
-   * declare its own <i>noSuchMethod()</i> method. It is a static warning if the
-   * implicit interface of <i>C</i> includes an instance member <i>m</i> of type
-   * <i>F</i> and <i>C</i> does not declare or inherit a corresponding instance
-   * member <i>m</i> of type <i>F'</i> such that <i>F' <: F</i>.
-   *
-   * 7.4 Abstract Instance Members: It is a static warning if an abstract member
-   * is declared or inherited in a concrete class unless that member overrides a
-   * concrete one.
-   *
    * Parameters:
    * 0: the name of the first member
    * 1: the name of the second member
@@ -6497,27 +7220,15 @@
    */
   static const StaticWarningCode
       NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FIVE_PLUS =
-      const StaticWarningCode(
-          'NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FIVE_PLUS',
-          "Missing concrete implementations of {0}, {1}, {2}, {3} and {4} "
-              "more.",
+      const StaticWarningCodeWithUniqueName(
+          'NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER',
+          'StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FIVE_PLUS',
+          "Missing concrete implementations of '{0}', '{1}', '{2}', '{3}', and "
+              "{4} more.",
           correction: "Try implementing the missing methods, or make the class "
               "abstract.");
 
   /**
-   * 7.9.1 Inheritance and Overriding: It is a static warning if a non-abstract
-   * class inherits an abstract method.
-   *
-   * 7.10 Superinterfaces: Let <i>C</i> be a concrete class that does not
-   * declare its own <i>noSuchMethod()</i> method. It is a static warning if the
-   * implicit interface of <i>C</i> includes an instance member <i>m</i> of type
-   * <i>F</i> and <i>C</i> does not declare or inherit a corresponding instance
-   * member <i>m</i> of type <i>F'</i> such that <i>F' <: F</i>.
-   *
-   * 7.4 Abstract Instance Members: It is a static warning if an abstract member
-   * is declared or inherited in a concrete class unless that member overrides a
-   * concrete one.
-   *
    * Parameters:
    * 0: the name of the first member
    * 1: the name of the second member
@@ -6526,50 +7237,86 @@
    */
   static const StaticWarningCode
       NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FOUR =
-      const StaticWarningCode(
-          'NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FOUR',
-          "Missing concrete implementations of {0}, {1}, {2} and {3}.",
+      const StaticWarningCodeWithUniqueName(
+          'NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER',
+          'StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FOUR',
+          "Missing concrete implementations of '{0}', '{1}', '{2}', and '{3}'.",
           correction: "Try implementing the missing methods, or make the class "
               "abstract.");
 
   /**
-   * 7.9.1 Inheritance and Overriding: It is a static warning if a non-abstract
-   * class inherits an abstract method.
-   *
-   * 7.10 Superinterfaces: Let <i>C</i> be a concrete class that does not
-   * declare its own <i>noSuchMethod()</i> method. It is a static warning if the
-   * implicit interface of <i>C</i> includes an instance member <i>m</i> of type
-   * <i>F</i> and <i>C</i> does not declare or inherit a corresponding instance
-   * member <i>m</i> of type <i>F'</i> such that <i>F' <: F</i>.
-   *
-   * 7.4 Abstract Instance Members: It is a static warning if an abstract member
-   * is declared or inherited in a concrete class unless that member overrides a
-   * concrete one.
-   *
    * Parameters:
    * 0: the name of the member
    */
+  // #### Description
+  //
+  // The analyzer produces this diagnostic when a concrete class inherits one or
+  // more abstract members, and doesn't provide or inherit an implementation for
+  // at least one of those abstract members.
+  //
+  // #### Example
+  //
+  // The following code produces this diagnostic because the class `B` doesn't
+  // have a concrete implementation of `m`:
+  //
+  // ```dart
+  // abstract class A {
+  //   void m();
+  // }
+  //
+  // class [!B!] extends A {}
+  // ```
+  //
+  // #### Common fixes
+  //
+  // If the subclass can provide a concrete implementation for some or all of
+  // the abstract inherited members, then add the concrete implementations:
+  //
+  // ```dart
+  // abstract class A {
+  //   void m();
+  // }
+  //
+  // class B extends A {
+  //   void m() {}
+  // }
+  // ```
+  //
+  // If there is a mixin that provides an implementation of the inherited
+  // methods, then apply the mixin to the subclass:
+  //
+  // ```dart
+  // abstract class A {
+  //   void m();
+  // }
+  //
+  // class B extends A with M {}
+  //
+  // mixin M {
+  //   void m() {}
+  // }
+  // ```
+  //
+  // If the subclass can't provide a concrete implementation for all of the
+  // abstract inherited members, then mark the subclass as being abstract:
+  //
+  // ```dart
+  // abstract class A {
+  //   void m();
+  // }
+  //
+  // abstract class B extends A {}
+  // ```
   static const StaticWarningCode
-      NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE = const StaticWarningCode(
-          'NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE',
-          "Missing concrete implementation of {0}.",
+      NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE =
+      const StaticWarningCodeWithUniqueName(
+          'NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER',
+          'StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE',
+          "Missing concrete implementation of '{0}'.",
           correction: "Try implementing the missing method, or make the class "
               "abstract.");
 
   /**
-   * 7.9.1 Inheritance and Overriding: It is a static warning if a non-abstract
-   * class inherits an abstract method.
-   *
-   * 7.10 Superinterfaces: Let <i>C</i> be a concrete class that does not
-   * declare its own <i>noSuchMethod()</i> method. It is a static warning if the
-   * implicit interface of <i>C</i> includes an instance member <i>m</i> of type
-   * <i>F</i> and <i>C</i> does not declare or inherit a corresponding instance
-   * member <i>m</i> of type <i>F'</i> such that <i>F' <: F</i>.
-   *
-   * 7.4 Abstract Instance Members: It is a static warning if an abstract member
-   * is declared or inherited in a concrete class unless that member overrides a
-   * concrete one.
-   *
    * Parameters:
    * 0: the name of the first member
    * 1: the name of the second member
@@ -6577,34 +7324,24 @@
    */
   static const StaticWarningCode
       NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_THREE =
-      const StaticWarningCode(
-          'NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_THREE',
-          "Missing concrete implementations of {0}, {1} and {2}.",
+      const StaticWarningCodeWithUniqueName(
+          'NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER',
+          'StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_THREE',
+          "Missing concrete implementations of '{0}', '{1}', and '{2}'.",
           correction: "Try implementing the missing methods, or make the class "
               "abstract.");
 
   /**
-   * 7.9.1 Inheritance and Overriding: It is a static warning if a non-abstract
-   * class inherits an abstract method.
-   *
-   * 7.10 Superinterfaces: Let <i>C</i> be a concrete class that does not
-   * declare its own <i>noSuchMethod()</i> method. It is a static warning if the
-   * implicit interface of <i>C</i> includes an instance member <i>m</i> of type
-   * <i>F</i> and <i>C</i> does not declare or inherit a corresponding instance
-   * member <i>m</i> of type <i>F'</i> such that <i>F' <: F</i>.
-   *
-   * 7.4 Abstract Instance Members: It is a static warning if an abstract member
-   * is declared or inherited in a concrete class unless that member overrides a
-   * concrete one.
-   *
    * Parameters:
    * 0: the name of the first member
    * 1: the name of the second member
    */
   static const StaticWarningCode
-      NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_TWO = const StaticWarningCode(
-          'NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_TWO',
-          "Missing concrete implementations of {0} and {1}.",
+      NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_TWO =
+      const StaticWarningCodeWithUniqueName(
+          'NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER',
+          'StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_TWO',
+          "Missing concrete implementations of '{0}' and '{1}'.",
           correction: "Try implementing the missing methods, or make the class "
               "abstract.");
 
@@ -6808,7 +7545,8 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because the name `Srting` isn't
+  // defined:
   //
   // ```dart
   // void f(Object o) {
@@ -6878,7 +7616,8 @@
   //
   // #### Example
   //
-  // The following code produces this diagnostic:
+  // The following code produces this diagnostic because the name `rihgt` isn't
+  // defined:
   //
   // ```dart
   // int min(int left, int right) => left <= [!rihgt!] ? left : right;
@@ -7036,6 +7775,17 @@
   ErrorType get type => ErrorType.STATIC_WARNING;
 }
 
+class StaticWarningCodeWithUniqueName extends StaticWarningCode {
+  @override
+  final String uniqueName;
+
+  const StaticWarningCodeWithUniqueName(
+      String name, this.uniqueName, String message,
+      {String correction, bool hasPublishedDocs})
+      : super(name, message,
+            correction: correction, hasPublishedDocs: hasPublishedDocs);
+}
+
 /**
  * This class has Strong Mode specific error codes.
  *
diff --git a/pkg/analyzer/lib/src/error/inheritance_override.dart b/pkg/analyzer/lib/src/error/inheritance_override.dart
index 16ae004..fc45c4b 100644
--- a/pkg/analyzer/lib/src/error/inheritance_override.dart
+++ b/pkg/analyzer/lib/src/error/inheritance_override.dart
@@ -20,7 +20,7 @@
 class InheritanceOverrideVerifier {
   static const _missingOverridesKey = 'missingOverrides';
 
-  final TypeSystem _typeSystem;
+  final TypeSystemImpl _typeSystem;
   final TypeProvider _typeProvider;
   final InheritanceManager3 _inheritance;
   final ErrorReporter _reporter;
@@ -84,7 +84,7 @@
 }
 
 class _ClassVerifier {
-  final TypeSystem typeSystem;
+  final TypeSystemImpl typeSystem;
   final TypeProvider typeProvider;
   final InheritanceManager3 inheritance;
   final ErrorReporter reporter;
diff --git a/pkg/analyzer/lib/src/error/literal_element_verifier.dart b/pkg/analyzer/lib/src/error/literal_element_verifier.dart
index 8aeb435..411e42a 100644
--- a/pkg/analyzer/lib/src/error/literal_element_verifier.dart
+++ b/pkg/analyzer/lib/src/error/literal_element_verifier.dart
@@ -13,7 +13,7 @@
 /// Verifier for [CollectionElement]s in list, set, or map literals.
 class LiteralElementVerifier {
   final TypeProvider typeProvider;
-  final TypeSystem typeSystem;
+  final TypeSystemImpl typeSystem;
   final ErrorReporter errorReporter;
   final FeatureSet featureSet;
   final bool Function(Expression) checkForUseOfVoidResult;
diff --git a/pkg/analyzer/lib/src/error/type_arguments_verifier.dart b/pkg/analyzer/lib/src/error/type_arguments_verifier.dart
index c5ef35c..c19222c 100644
--- a/pkg/analyzer/lib/src/error/type_arguments_verifier.dart
+++ b/pkg/analyzer/lib/src/error/type_arguments_verifier.dart
@@ -17,7 +17,7 @@
 
 class TypeArgumentsVerifier {
   final AnalysisOptionsImpl _options;
-  final TypeSystem _typeSystem;
+  final TypeSystemImpl _typeSystem;
   final ErrorReporter _errorReporter;
 
   TypeArgumentsVerifier(this._options, this._typeSystem, this._errorReporter);
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index c40153a2..feb7883 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -2142,14 +2142,13 @@
 
     // Peek to leave type parameters on top of stack.
     List<TypeParameter> typeParameters = peek();
-    TypeParameter typeParameter = typeParameters[index];
-    typeParameter
-      ..extendsKeyword = extendsOrSuper
-      ..bound = bound;
 
-    if (typeParameter is TypeParameterImpl) {
-      typeParameter.varianceKeyword = variance;
-    }
+    // TODO (kallentu) : Clean up TypeParameterImpl casting once variance is
+    // added to the interface.
+    (typeParameters[index] as TypeParameterImpl)
+      ..extendsKeyword = extendsOrSuper
+      ..bound = bound
+      ..varianceKeyword = variance;
   }
 
   @override
@@ -3413,20 +3412,10 @@
 
   List<T> popTypedList<T>(int count, [List<T> list]) {
     if (count == 0) return null;
-    assert(stack.arrayLength >= count);
-
-    final table = stack.array;
-    final length = stack.arrayLength;
+    assert(stack.length >= count);
 
     final tailList = list ?? new List<T>.filled(count, null, growable: true);
-    final startIndex = length - count;
-    for (int i = 0; i < count; i++) {
-      final value = table[startIndex + i];
-      tailList[i] = value is NullValue ? null : value;
-      table[startIndex + i] = null;
-    }
-    stack.arrayLength -= count;
-
+    stack.popList(count, tailList, null);
     return tailList;
   }
 
diff --git a/pkg/analyzer/lib/src/fasta/error_converter.dart b/pkg/analyzer/lib/src/fasta/error_converter.dart
index 385b75f..eb81df0 100644
--- a/pkg/analyzer/lib/src/fasta/error_converter.dart
+++ b/pkg/analyzer/lib/src/fasta/error_converter.dart
@@ -278,10 +278,6 @@
             offset,
             length);
         return;
-      case "TYPE_PARAMETER_ON_CONSTRUCTOR":
-        errorReporter?.reportErrorForOffset(
-            CompileTimeErrorCode.TYPE_PARAMETER_ON_CONSTRUCTOR, offset, length);
-        return;
       case "UNDEFINED_CLASS":
         errorReporter?.reportErrorForOffset(
             CompileTimeErrorCode.UNDEFINED_CLASS, offset, length);
diff --git a/pkg/analyzer/lib/src/generated/constant.dart b/pkg/analyzer/lib/src/generated/constant.dart
index ea8336f..2cf8f0e 100644
--- a/pkg/analyzer/lib/src/generated/constant.dart
+++ b/pkg/analyzer/lib/src/generated/constant.dart
@@ -12,8 +12,7 @@
 import 'package:analyzer/src/generated/engine.dart' show RecordingErrorListener;
 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
 import 'package:analyzer/src/generated/source.dart' show Source;
-import 'package:analyzer/src/generated/type_system.dart'
-    show Dart2TypeSystem, TypeSystem;
+import 'package:analyzer/src/generated/type_system.dart' show TypeSystemImpl;
 
 export 'package:analyzer/dart/analysis/declared_variables.dart';
 export 'package:analyzer/dart/constant/value.dart';
@@ -110,7 +109,7 @@
   /**
    * The type system primitives.
    */
-  final TypeSystem _typeSystem;
+  final TypeSystemImpl _typeSystem;
 
   /**
    * Initialize a newly created evaluator to evaluate expressions in the given
@@ -118,8 +117,14 @@
    * types.
    */
   ConstantEvaluator(this._source, TypeProvider typeProvider,
-      {TypeSystem typeSystem})
-      : _typeSystem = typeSystem ?? new Dart2TypeSystem(typeProvider),
+      {TypeSystemImpl typeSystem})
+      : _typeSystem = typeSystem ??
+            TypeSystemImpl(
+              implicitCasts: true,
+              isNonNullableByDefault: false,
+              strictInference: false,
+              typeProvider: typeProvider,
+            ),
         _typeProvider = typeProvider;
 
   EvaluationResult evaluate(Expression expression) {
diff --git a/pkg/analyzer/lib/src/generated/element_resolver.dart b/pkg/analyzer/lib/src/generated/element_resolver.dart
index cb5fd6a..4f3f96f 100644
--- a/pkg/analyzer/lib/src/generated/element_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/element_resolver.dart
@@ -18,7 +18,6 @@
         SimpleIdentifierImpl;
 import 'package:analyzer/src/dart/ast/token.dart';
 import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/dart/resolver/extension_member_resolver.dart';
 import 'package:analyzer/src/dart/resolver/method_invocation_resolver.dart';
@@ -89,11 +88,6 @@
  */
 class ElementResolver extends SimpleAstVisitor<void> {
   /**
-   * The manager for the inheritance mappings.
-   */
-  final InheritanceManager3 _inheritance;
-
-  /**
    * The resolver driving this participant.
    */
   final ResolverVisitor _resolver;
@@ -127,8 +121,7 @@
    * resolve the nodes in a compilation unit.
    */
   ElementResolver(this._resolver, {this.reportConstEvaluationErrors: true})
-      : _inheritance = _resolver.inheritance,
-        _definingLibrary = _resolver.definingLibrary,
+      : _definingLibrary = _resolver.definingLibrary,
         _extensionResolver = _resolver.extensionResolver,
         _methodInvocationResolver = new MethodInvocationResolver(_resolver) {
     _dynamicType = _resolver.typeProvider.dynamicType;
@@ -332,8 +325,10 @@
       SimpleIdentifier name = node.name;
       if (name == null) {
         constructor = type.lookUpConstructor(null, _definingLibrary);
+        constructor = _resolver.toLegacyElement(constructor);
       } else {
         constructor = type.lookUpConstructor(name.name, _definingLibrary);
+        constructor = _resolver.toLegacyElement(constructor);
         name.staticElement = constructor;
       }
       node.staticElement = constructor;
@@ -600,6 +595,7 @@
                 "${node.identifier.name}=", node.identifier.offset - 1)));
         element = _resolver.nameScope.lookup(setterName, _definingLibrary);
       }
+      element = _resolver.toLegacyElement(element);
       if (element == null && _resolver.nameScope.shouldIgnoreUndefined(node)) {
         return;
       }
@@ -898,6 +894,7 @@
     String superName = name?.name;
     ConstructorElement element =
         superType.lookUpConstructor(superName, _definingLibrary);
+    element = _resolver.toLegacyElement(element);
     if (element == null || !element.isAccessibleIn(_definingLibrary)) {
       if (name != null) {
         _resolver.errorReporter.reportErrorForNode(
@@ -1241,7 +1238,7 @@
   }
 
   _PropertyResolver _newPropertyResolver() {
-    return _PropertyResolver(_resolver.typeProvider, _inheritance,
+    return _PropertyResolver(_resolver, _resolver.typeProvider,
         _definingLibrary, _extensionResolver);
   }
 
@@ -1552,6 +1549,7 @@
         element ??= extension.getGetter(memberName);
         element ??= extension.getMethod(memberName);
         if (element != null) {
+          element = _resolver.toLegacyElement(element);
           propertyName.staticElement = element;
           _checkForStaticAccessToInstanceMember(propertyName, element);
         } else {
@@ -1566,6 +1564,7 @@
       if (propertyName.inSetterContext()) {
         var element = extension.getSetter(memberName);
         if (element != null) {
+          element = _resolver.toLegacyElement(element);
           propertyName.staticElement = element;
           _checkForStaticAccessToInstanceMember(propertyName, element);
         } else {
@@ -1610,6 +1609,7 @@
         }
 
         if (element != null) {
+          element = _resolver.toLegacyElement(element);
           propertyName.staticElement = element;
           _checkForStaticAccessToInstanceMember(propertyName, element);
         } else {
@@ -1630,6 +1630,7 @@
         }
 
         if (element != null) {
+          element = _resolver.toLegacyElement(element);
           propertyName.staticElement = element;
           _checkForStaticAccessToInstanceMember(propertyName, element);
         } else {
@@ -1658,6 +1659,7 @@
               setter: false, concrete: true, forSuperInvocation: true);
 
           if (element != null) {
+            element = _resolver.toLegacyElement(element);
             propertyName.staticElement = element;
           } else {
             // We were not able to find the concrete dispatch target.
@@ -1693,6 +1695,7 @@
               setter: true, concrete: true, forSuperInvocation: true);
 
           if (element != null) {
+            element = _resolver.toLegacyElement(element);
             propertyName.staticElement = element;
           } else {
             // We were not able to find the concrete dispatch target.
@@ -1799,6 +1802,7 @@
    */
   Element _resolveSimpleIdentifier(SimpleIdentifier identifier) {
     Element element = _resolver.nameScope.lookup(identifier, _definingLibrary);
+    element = _resolver.toLegacyElement(element);
     if (element is PropertyAccessorElement && identifier.inSetterContext()) {
       PropertyInducingElement variable =
           (element as PropertyAccessorElement).variable;
@@ -2006,16 +2010,16 @@
 
 /// Helper for resolving properties (getters, setters, or methods).
 class _PropertyResolver {
+  final ResolverVisitor _resolver;
   final TypeProvider _typeProvider;
-  final InheritanceManager3 _inheritance;
   final LibraryElement _definingLibrary;
   final ExtensionMemberResolver _extensionResolver;
 
   ResolutionResult result = ResolutionResult.none;
 
   _PropertyResolver(
+    this._resolver,
     this._typeProvider,
-    this._inheritance,
     this._definingLibrary,
     this._extensionResolver,
   );
@@ -2073,6 +2077,13 @@
       result = _extensionResolver.findExtension(type, name, errorNode);
     }
 
+    if (result.isSingle) {
+      result = ResolutionResult(
+        getter: _resolver.toLegacyElement(result.getter),
+        setter: _resolver.toLegacyElement(result.setter),
+      );
+    }
+
     return result;
   }
 
diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
index f2af195..81081ba 100644
--- a/pkg/analyzer/lib/src/generated/engine.dart
+++ b/pkg/analyzer/lib/src/generated/engine.dart
@@ -10,7 +10,6 @@
 import 'package:analyzer/exception/exception.dart';
 import 'package:analyzer/instrumentation/instrumentation.dart';
 import 'package:analyzer/source/error_processor.dart';
-import 'package:analyzer/src/context/context.dart';
 import 'package:analyzer/src/dart/analysis/experiments.dart';
 import 'package:analyzer/src/generated/constant.dart';
 import 'package:analyzer/src/generated/java_engine.dart';
@@ -19,6 +18,7 @@
 import 'package:analyzer/src/generated/utilities_general.dart';
 import 'package:analyzer/src/services/lint.dart';
 import 'package:analyzer/src/summary/api_signature.dart';
+import 'package:meta/meta.dart';
 import 'package:path/path.dart' as pathos;
 import 'package:pub_semver/pub_semver.dart';
 
@@ -151,11 +151,6 @@
     StringToken.canonicalizer.clear();
   }
 
-  /// Create and return a new context in which analysis can be performed.
-  AnalysisContext createAnalysisContext() {
-    return new AnalysisContextImpl();
-  }
-
   /// A utility method that clients can use to process all of the required
   /// plugins. This method can only be used by clients that do not need to
   /// process any other plugins.
@@ -853,8 +848,11 @@
 /// Additional behavior for an analysis context that is required by internal
 /// users of the context.
 abstract class InternalAnalysisContext implements AnalysisContext {
-  /// Sets the [TypeProvider] for this context.
-  void set typeProvider(TypeProvider typeProvider);
+  /// Sets the [TypeProvider]s for this context.
+  void setTypeProviders({
+    @required TypeProvider legacy,
+    @required TypeProvider nonNullableByDefault,
+  });
 }
 
 /// Container with global [AnalysisContext] performance statistics.
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index b7ce355..341e266 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -16,6 +16,7 @@
 import 'package:analyzer/src/dart/ast/ast.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
+import 'package:analyzer/src/dart/element/nullability_eliminator.dart';
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/dart/resolver/variance.dart';
 import 'package:analyzer/src/diagnostic/diagnostic_factory.dart';
@@ -80,7 +81,7 @@
   /**
    * The type system primitives
    */
-  TypeSystem _typeSystem;
+  TypeSystemImpl _typeSystem;
 
   /**
    * The manager for the inheritance mappings.
@@ -181,16 +182,6 @@
   bool _hasExtUri = false;
 
   /**
-   * This is set to `false` on the entry of every [BlockFunctionBody], and is
-   * restored to the enclosing value on exit. The value is used in
-   * [_checkForMixedReturns] to prevent both
-   * [StaticWarningCode.MIXED_RETURN_TYPES] and
-   * [StaticWarningCode.RETURN_WITHOUT_VALUE] from being generated in the same
-   * function body.
-   */
-  bool _hasReturnWithoutValue = false;
-
-  /**
    * The class containing the AST nodes being visited, or `null` if we are not
    * in the scope of a class.
    */
@@ -446,8 +437,6 @@
   void visitBlockFunctionBody(BlockFunctionBody node) {
     bool wasInAsync = _inAsync;
     bool wasInGenerator = _inGenerator;
-    bool previousHasReturnWithoutValue = _hasReturnWithoutValue;
-    _hasReturnWithoutValue = false;
     List<ReturnStatement> previousReturnsWith = _returnsWith;
     List<ReturnStatement> previousReturnsWithout = _returnsWithout;
     try {
@@ -456,13 +445,11 @@
       _returnsWith = new List<ReturnStatement>();
       _returnsWithout = new List<ReturnStatement>();
       super.visitBlockFunctionBody(node);
-      _checkForMixedReturns(node);
     } finally {
       _inAsync = wasInAsync;
       _inGenerator = wasInGenerator;
       _returnsWith = previousReturnsWith;
       _returnsWithout = previousReturnsWithout;
-      _hasReturnWithoutValue = previousHasReturnWithoutValue;
     }
   }
 
@@ -720,6 +707,7 @@
     }
     try {
       _checkForNotInitializedNonNullableStaticField(node);
+      _checkForWrongTypeParameterVarianceInField(node);
       super.visitFieldDeclaration(node);
     } finally {
       _isInStaticVariableDeclaration = false;
@@ -1040,6 +1028,7 @@
       _checkForIllegalReturnType(returnType);
       _checkForImplicitDynamicReturn(node, node.declaredElement);
       _checkForMustCallSuper(node);
+      _checkForWrongTypeParameterVarianceInMethod(node);
       super.visitMethodDeclaration(node);
     } finally {
       _enclosingFunction = previousFunction;
@@ -1480,10 +1469,6 @@
    * constructor and the return type is not assignable to `null`; that is, we
    * don't have `return;` if the enclosing method has a non-void containing
    * return type.
-   *
-   * See [CompileTimeErrorCode.RETURN_IN_GENERATIVE_CONSTRUCTOR],
-   * [StaticWarningCode.RETURN_WITHOUT_VALUE], and
-   * [StaticTypeWarningCode.RETURN_OF_INVALID_TYPE].
    */
   void _checkForAllEmptyReturnStatementErrorCodes(
       ReturnStatement statement, DartType expectedReturnType) {
@@ -1498,7 +1483,6 @@
       return;
     }
     // If we reach here, this is an invalid return
-    _hasReturnWithoutValue = true;
     _errorReporter.reportErrorForNode(
         StaticWarningCode.RETURN_WITHOUT_VALUE, statement);
     return;
@@ -1781,10 +1765,6 @@
    *
    * Check that the return type matches the type of the declared return type in
    * the enclosing method or function.
-   *
-   * See [CompileTimeErrorCode.RETURN_IN_GENERATIVE_CONSTRUCTOR],
-   * [StaticWarningCode.RETURN_WITHOUT_VALUE], and
-   * [StaticTypeWarningCode.RETURN_OF_INVALID_TYPE].
    */
   void _checkForAllReturnStatementErrorCodes(ReturnStatement statement) {
     FunctionType functionType = _enclosingFunction?.type;
@@ -2261,26 +2241,33 @@
   void _checkForConflictingGenerics(NamedCompilationUnitMember node) {
     var visitedClasses = <ClassElement>[];
     var interfaces = <ClassElement, InterfaceType>{};
+
     void visit(InterfaceType type) {
       if (type == null) return;
+
       var element = type.element;
       if (visitedClasses.contains(element)) return;
       visitedClasses.add(element);
+
       if (element.typeParameters.isNotEmpty) {
+        type = _toLegacyType(type);
         var oldType = interfaces[element];
         if (oldType == null) {
           interfaces[element] = type;
         } else if (type != oldType) {
           _errorReporter.reportErrorForNode(
-              CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES,
-              node,
-              [_enclosingClass.name, oldType, type]);
+            CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES,
+            node,
+            [_enclosingClass.name, oldType, type],
+          );
         }
       }
+
       visit(type.superclass);
       type.mixins.forEach(visit);
       type.superclassConstraints.forEach(visit);
       type.interfaces.forEach(visit);
+
       visitedClasses.removeLast();
     }
 
@@ -2624,29 +2611,13 @@
    */
   void _checkForDeferredImportOfExtensions(
       ImportDirective directive, ImportElement importElement) {
-    List<String> shownNames = [];
-    List<String> hiddenNames = [];
-
-    Iterable<String> namesOf(List<SimpleIdentifier> identifiers) =>
-        identifiers.map((identifier) => identifier.name);
-    for (Combinator combinator in directive.combinators) {
-      if (combinator is HideCombinator) {
-        hiddenNames.addAll(namesOf(combinator.hiddenNames));
-      } else if (combinator is ShowCombinator) {
-        shownNames.addAll(namesOf(combinator.shownNames));
-      }
-    }
-    for (Element element in importElement.importedLibrary.topLevelElements) {
+    for (var element in importElement.namespace.definedNames.values) {
       if (element is ExtensionElement) {
-        String name = element.name;
-        if (name != null &&
-            name.isNotEmpty &&
-            (shownNames.contains(name) ||
-                (shownNames.isEmpty && !hiddenNames.contains(name)))) {
-          _errorReporter.reportErrorForNode(
-              CompileTimeErrorCode.DEFERRED_IMPORT_OF_EXTENSION, directive.uri);
-          return;
-        }
+        _errorReporter.reportErrorForNode(
+          CompileTimeErrorCode.DEFERRED_IMPORT_OF_EXTENSION,
+          directive.uri,
+        );
+        return;
       }
     }
   }
@@ -3789,30 +3760,6 @@
   }
 
   /**
-   * Verify that the given function [body] does not contain return statements
-   * that both have and do not have return values.
-   *
-   * See [StaticWarningCode.MIXED_RETURN_TYPES].
-   */
-  void _checkForMixedReturns(BlockFunctionBody body) {
-    if (_hasReturnWithoutValue) {
-      return;
-    }
-    var nonVoidReturnsWith =
-        _returnsWith.where((stmt) => !getStaticType(stmt.expression).isVoid);
-    if (nonVoidReturnsWith.isNotEmpty && _returnsWithout.isNotEmpty) {
-      for (ReturnStatement returnWith in nonVoidReturnsWith) {
-        _errorReporter.reportErrorForToken(
-            StaticWarningCode.MIXED_RETURN_TYPES, returnWith.returnKeyword);
-      }
-      for (ReturnStatement returnWithout in _returnsWithout) {
-        _errorReporter.reportErrorForToken(
-            StaticWarningCode.MIXED_RETURN_TYPES, returnWithout.returnKeyword);
-      }
-    }
-  }
-
-  /**
    * Verify that the given mixin does not have an explicitly declared
    * constructor. The [mixinName] is the node to report problem on. The
    * [mixinElement] is the mixing to evaluate.
@@ -4717,8 +4664,6 @@
    *
    * This method is called both by [_checkForAllReturnStatementErrorCodes]
    * and [visitExpressionFunctionBody].
-   *
-   * See [StaticTypeWarningCode.RETURN_OF_INVALID_TYPE].
    */
   void _checkForReturnOfInvalidType(
       Expression returnExpression, DartType expectedType,
@@ -4746,9 +4691,14 @@
             StaticTypeWarningCode.RETURN_OF_INVALID_TYPE_FROM_CLOSURE,
             returnExpression,
             [expressionType, expectedType]);
+      } else if (_enclosingFunction is MethodElement) {
+        _errorReporter.reportTypeErrorForNode(
+            StaticTypeWarningCode.RETURN_OF_INVALID_TYPE_FROM_METHOD,
+            returnExpression,
+            [expressionType, expectedType, displayName]);
       } else {
         _errorReporter.reportTypeErrorForNode(
-            StaticTypeWarningCode.RETURN_OF_INVALID_TYPE,
+            StaticTypeWarningCode.RETURN_OF_INVALID_TYPE_FROM_FUNCTION,
             returnExpression,
             [expressionType, expectedType, displayName]);
       }
@@ -5299,18 +5249,112 @@
     }
   }
 
+  void _checkForWrongTypeParameterVarianceInField(FieldDeclaration node) {
+    if (_enclosingClass != null) {
+      for (var typeParameter in _enclosingClass.typeParameters) {
+        // TODO (kallentu) : Clean up TypeParameterElementImpl casting once
+        // variance is added to the interface.
+        if (!(typeParameter as TypeParameterElementImpl).isLegacyCovariant) {
+          var fields = node.fields;
+          var fieldElement = fields.variables.first.declaredElement;
+          var fieldName = fields.variables.first.name;
+          Variance fieldVariance = Variance(typeParameter, fieldElement.type);
+
+          _checkForWrongVariancePosition(
+              fieldVariance, typeParameter, fieldName);
+          if (!fields.isFinal && node.covariantKeyword == null) {
+            _checkForWrongVariancePosition(
+                Variance.contravariant.combine(fieldVariance),
+                typeParameter,
+                fieldName);
+          }
+        }
+      }
+    }
+  }
+
+  void _checkForWrongTypeParameterVarianceInMethod(MethodDeclaration method) {
+    // Only need to report errors for parameters with explicitly defined type
+    // parameters in classes or mixins.
+    if (_enclosingClass != null) {
+      for (var typeParameter in _enclosingClass.typeParameters) {
+        // TODO (kallentu) : Clean up TypeParameterElementImpl casting once
+        // variance is added to the interface.
+        if (!(typeParameter as TypeParameterElementImpl).isLegacyCovariant) {
+          if (method.typeParameters != null) {
+            for (var methodTypeParameter
+                in method.typeParameters.typeParameters) {
+              Variance methodTypeParameterVariance = Variance.invariant.combine(
+                  Variance(typeParameter, methodTypeParameter.bound.type));
+              _checkForWrongVariancePosition(methodTypeParameterVariance,
+                  typeParameter, methodTypeParameter);
+            }
+          }
+          if (method.parameters != null) {
+            for (int i = 0; i < method.parameters.parameters.length; i++) {
+              var methodParameterElement =
+                  method.parameters.parameterElements[i];
+              var methodParameterNode = method.parameters.parameters[i];
+              if (!methodParameterElement.isCovariant) {
+                Variance methodParameterVariance = Variance.contravariant
+                    .combine(
+                        Variance(typeParameter, methodParameterElement.type));
+                _checkForWrongVariancePosition(methodParameterVariance,
+                    typeParameter, methodParameterNode);
+              }
+            }
+          }
+          if (method.returnType != null) {
+            Variance methodReturnTypeVariance =
+                Variance(typeParameter, method.returnType.type);
+            _checkForWrongVariancePosition(
+                methodReturnTypeVariance, typeParameter, method.returnType);
+          }
+        }
+      }
+    }
+  }
+
   void _checkForWrongTypeParameterVarianceInSuperinterfaces() {
     void checkOne(DartType superInterface) {
       if (superInterface != null) {
         for (var typeParameter in _enclosingClass.typeParameters) {
-          var variance = Variance(typeParameter, superInterface);
-          if (variance.isContravariant || variance.isInvariant) {
-            _errorReporter.reportErrorForElement(
-              CompileTimeErrorCode
-                  .WRONG_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE,
-              typeParameter,
-              [typeParameter.name, superInterface],
-            );
+          var superVariance = Variance(typeParameter, superInterface);
+          // TODO (kallentu) : Clean up TypeParameterElementImpl casting once
+          // variance is added to the interface.
+          var typeParameterElementImpl =
+              typeParameter as TypeParameterElementImpl;
+          // Let `D` be a class or mixin declaration, let `S` be a direct
+          // superinterface of `D`, and let `X` be a type parameter declared by
+          // `D`.
+          // If `X` is an `out` type parameter, it can only occur in `S` in an
+          // covariant or unrelated position.
+          // If `X` is an `in` type parameter, it can only occur in `S` in an
+          // contravariant or unrelated position.
+          // If `X` is an `inout` type parameter, it can occur in `S` in any
+          // position.
+          if (!superVariance
+              .greaterThanOrEqual(typeParameterElementImpl.variance)) {
+            if (!typeParameterElementImpl.isLegacyCovariant) {
+              _errorReporter.reportErrorForElement(
+                CompileTimeErrorCode
+                    .WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE,
+                typeParameter,
+                [
+                  typeParameter.name,
+                  typeParameterElementImpl.variance.toKeywordString(),
+                  superVariance.toKeywordString(),
+                  superInterface
+                ],
+              );
+            } else {
+              _errorReporter.reportErrorForElement(
+                CompileTimeErrorCode
+                    .WRONG_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE,
+                typeParameter,
+                [typeParameter.name, superInterface],
+              );
+            }
           }
         }
       }
@@ -5323,6 +5367,38 @@
   }
 
   /**
+   * Check for invalid variance positions in members of a class or mixin.
+   *
+   * Let `C` be a class or mixin declaration with type parameter `T`.
+   * If `T` is an `out` type parameter then `T` can only appear in covariant
+   * positions within the accessors and methods of `C`.
+   * If `T` is an `in` type parameter then `T` can only appear in contravariant
+   * positions within the accessors and methods of `C`.
+   * If `T` is an `inout` type parameter or a type parameter with no explicit
+   * variance modifier then `T` can appear in any variant position within the
+   * accessors and methods of `C`.
+   *
+   * Errors should only be reported in classes and mixins since those are the
+   * only components that allow explicit variance modifiers.
+   */
+  void _checkForWrongVariancePosition(
+      Variance variance, TypeParameterElement typeParameter, AstNode node) {
+    TypeParameterElementImpl typeParameterImpl =
+        typeParameter as TypeParameterElementImpl;
+    if (!variance.greaterThanOrEqual(typeParameterImpl.variance)) {
+      _errorReporter.reportErrorForNode(
+        CompileTimeErrorCode.WRONG_TYPE_PARAMETER_VARIANCE_POSITION,
+        node,
+        [
+          typeParameterImpl.variance.toKeywordString(),
+          typeParameterImpl.name,
+          variance.toKeywordString()
+        ],
+      );
+    }
+  }
+
+  /**
    * Check for a type mis-match between the yielded type and the declared
    * return type of a generator function.
    *
@@ -5879,6 +5955,13 @@
     return null;
   }
 
+  /// If in a legacy library, return the legacy version of the [type].
+  /// Otherwise, return the original type.
+  DartType _toLegacyType(DartType type) {
+    if (_isNonNullable) return type;
+    return NullabilityEliminator.perform(type);
+  }
+
   /**
    * Return [FieldElement]s that are declared in the [ClassDeclaration] with
    * the given [constructor], but are not initialized.
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 8a3ddfc..08aaa19 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -21,7 +21,9 @@
 import 'package:analyzer/src/dart/ast/utilities.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
-import 'package:analyzer/src/dart/element/member.dart' show ConstructorMember;
+import 'package:analyzer/src/dart/element/member.dart'
+    show ConstructorMember, ExecutableMember, Member;
+import 'package:analyzer/src/dart/element/nullability_eliminator.dart';
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/type_provider.dart';
 import 'package:analyzer/src/dart/resolver/exit_detector.dart';
@@ -73,7 +75,7 @@
   final InterfaceType _nullType;
 
   /// The type system primitives
-  final TypeSystem _typeSystem;
+  final TypeSystemImpl _typeSystem;
 
   /// The inheritance manager to access interface type hierarchy.
   final InheritanceManager3 _inheritanceManager;
@@ -104,13 +106,19 @@
     this._currentLibrary,
     CompilationUnit unit,
     String content, {
-    TypeSystem typeSystem,
+    TypeSystemImpl typeSystem,
     @required InheritanceManager3 inheritanceManager,
     ResourceProvider resourceProvider,
     DeclaredVariables declaredVariables,
     AnalysisOptions analysisOptions,
   })  : _nullType = typeProvider.nullType,
-        _typeSystem = typeSystem ?? new Dart2TypeSystem(typeProvider),
+        _typeSystem = typeSystem ??
+            TypeSystemImpl(
+              implicitCasts: true,
+              isNonNullableByDefault: false,
+              strictInference: false,
+              typeProvider: typeProvider,
+            ),
         _isNonNullable = unit.featureSet.isEnabled(Feature.non_nullable),
         _strictInference =
             (analysisOptions as AnalysisOptionsImpl).strictInference,
@@ -1077,7 +1085,8 @@
       if (flattenedType.isDartAsyncFutureOr) {
         flattenedType = (flattenedType as InterfaceType).typeArguments[0];
       }
-      if (flattenedType.isDynamic ||
+      if (flattenedType.isBottom ||
+          flattenedType.isDynamic ||
           flattenedType.isDartCoreNull ||
           flattenedType.isVoid) {
         return;
@@ -1519,7 +1528,7 @@
   final ErrorReporter _errorReporter;
 
   ///  The type system for this visitor
-  final TypeSystem _typeSystem;
+  final TypeSystemImpl _typeSystem;
 
   /// The object used to track the usage of labels within a given label scope.
   _LabelTracker labelTracker;
@@ -1531,8 +1540,14 @@
   /// to the given [errorReporter] and will use the given [typeSystem] if one is
   /// provided.
   DeadCodeVerifier(this._errorReporter, FeatureSet featureSet,
-      {TypeSystem typeSystem})
-      : this._typeSystem = typeSystem ?? new Dart2TypeSystem(null),
+      {TypeSystemImpl typeSystem})
+      : this._typeSystem = typeSystem ??
+            TypeSystemImpl(
+              implicitCasts: true,
+              isNonNullableByDefault: false,
+              strictInference: false,
+              typeProvider: null,
+            ),
         _isNonNullableUnit = featureSet.isEnabled(Feature.non_nullable);
 
   @override
@@ -2060,6 +2075,10 @@
       return;
     }
     Element element = node.staticElement;
+    // Store un-parameterized members.
+    if (element is ExecutableMember) {
+      element = element.declaration;
+    }
     bool isIdentifierRead = _isReadIdentifier(node);
     if (element is PropertyAccessorElement &&
         element.isSynthetic &&
@@ -2072,12 +2091,20 @@
       }
     } else {
       _useIdentifierElement(node);
-      if (element == null ||
-          element.enclosingElement is ClassElement &&
-              !identical(element, _enclosingExec)) {
-        usedElements.members.add(node.name);
+      if (element == null) {
         if (isIdentifierRead) {
-          usedElements.readMembers.add(node.name);
+          usedElements.unresolvedReadMembers.add(node.name);
+        }
+      } else if (element.enclosingElement is ClassElement &&
+          !identical(element, _enclosingExec)) {
+        usedElements.members.add(element);
+        if (isIdentifierRead) {
+          // Store the corresponding getter.
+          if (element is PropertyAccessorElement && element.isSetter) {
+            element = (element as PropertyAccessorElement).correspondingGetter;
+          }
+          usedElements.members.add(element);
+          usedElements.readMembers.add(element);
         }
       }
     }
@@ -2153,6 +2180,8 @@
   static const String _typeProperty =
       'analyzer.src.generated.InferenceContext.contextType';
 
+  final ResolverVisitor _resolver;
+
   /// The error listener on which to record inference information.
   final ErrorReporter _errorReporter;
 
@@ -2163,7 +2192,7 @@
   final TypeProvider _typeProvider;
 
   /// The type system in use.
-  final TypeSystem _typeSystem;
+  final TypeSystemImpl _typeSystem;
 
   /// When no context type is available, this will track the least upper bound
   /// of all return statements in a lambda.
@@ -2175,9 +2204,13 @@
   /// functions and methods.
   final List<DartType> _returnStack = <DartType>[];
 
-  InferenceContext._(TypeProvider typeProvider, this._typeSystem,
-      this._inferenceHints, this._errorReporter)
-      : _typeProvider = typeProvider;
+  InferenceContext._(
+    ResolverVisitor resolver,
+    this._inferenceHints,
+  )   : _resolver = resolver,
+        _typeProvider = resolver.typeProvider,
+        _errorReporter = resolver.errorReporter,
+        _typeSystem = resolver.typeSystem;
 
   /// Get the return type of the current enclosing function, if any.
   ///
@@ -2199,7 +2232,12 @@
     }
 
     DartType inferred = _inferredReturn.last;
-    inferred = _typeSystem.getLeastUpperBound(type, inferred);
+    if (inferred == null) {
+      inferred = type;
+    } else {
+      inferred = _typeSystem.getLeastUpperBound(type, inferred);
+      inferred = _resolver.toLegacyTypeIfOptOut(inferred);
+    }
     _inferredReturn[_inferredReturn.length - 1] = inferred;
   }
 
@@ -2210,8 +2248,21 @@
   /// bound of all types added with [addReturnOrYieldType].
   void popReturnContext(FunctionBody node) {
     if (_returnStack.isNotEmpty && _inferredReturn.isNotEmpty) {
-      DartType context = _returnStack.removeLast() ?? DynamicTypeImpl.instance;
+      // If NNBD, and the function body end is reachable, infer nullable.
+      // If legacy, we consider the end as always reachable, and return Null.
+      if (_resolver._nonNullableEnabled) {
+        var flow = _resolver._flowAnalysis?.flow;
+        if (flow != null && flow.isReachable) {
+          addReturnOrYieldType(_typeProvider.nullType);
+        }
+      } else {
+        addReturnOrYieldType(_typeProvider.nullType);
+      }
+
+      DartType context = _returnStack.removeLast();
       DartType inferred = _inferredReturn.removeLast();
+      context ??= DynamicTypeImpl.instance;
+      inferred ??= DynamicTypeImpl.instance;
 
       if (_typeSystem.isSubtypeOf(inferred, context)) {
         setType(node, inferred);
@@ -2224,7 +2275,7 @@
   /// Push a block function body's return type onto the return stack.
   void pushReturnContext(FunctionBody node) {
     _returnStack.add(getContext(node));
-    _inferredReturn.add(_typeProvider.nullType);
+    _inferredReturn.add(null);
   }
 
   /// Place an info node into the error stream indicating that a
@@ -2258,8 +2309,8 @@
   ///
   /// The returned type may be partially or completely unknown, denoted with an
   /// unknown type `?`, for example `List<?>` or `(?, int) -> void`.
-  /// You can use [Dart2TypeSystem.upperBoundForType] or
-  /// [Dart2TypeSystem.lowerBoundForType] if you would prefer a known type
+  /// You can use [TypeSystemImpl.upperBoundForType] or
+  /// [TypeSystemImpl.lowerBoundForType] if you would prefer a known type
   /// that represents the bound of the context type.
   static DartType getContext(AstNode node) => node?.getProperty(_typeProperty);
 
@@ -2664,7 +2715,7 @@
   StaticTypeAnalyzer typeAnalyzer;
 
   /// The type system in use during resolution.
-  Dart2TypeSystem typeSystem;
+  TypeSystemImpl typeSystem;
 
   /// The class declaration representing the class containing the current node,
   /// or `null` if the current node is not contained in a class.
@@ -2775,8 +2826,7 @@
     if (options is AnalysisOptionsImpl) {
       strongModeHints = options.strongModeHints;
     }
-    this.inferenceContext = new InferenceContext._(
-        typeProvider, typeSystem, strongModeHints, errorReporter);
+    this.inferenceContext = new InferenceContext._(this, strongModeHints);
     this.typeAnalyzer = new StaticTypeAnalyzer(this, featureSet, _flowAnalysis);
   }
 
@@ -2914,6 +2964,20 @@
     }
   }
 
+  /// If in a legacy library, return the legacy view on the [element].
+  /// Otherwise, return the original element.
+  T toLegacyElement<T extends Element>(T element) {
+    if (_nonNullableEnabled) return element;
+    return Member.legacy(element);
+  }
+
+  /// If in a legacy library, return the legacy version of the [type].
+  /// Otherwise, return the original type.
+  DartType toLegacyTypeIfOptOut(DartType type) {
+    if (_nonNullableEnabled) return type;
+    return NullabilityEliminator.perform(type);
+  }
+
   @override
   void visitAnnotation(Annotation node) {
     AstNode parent = node.parent;
@@ -3540,7 +3604,7 @@
           node,
           identifierElement is VariableElement
               ? identifierElement
-              : loopVariable.declaredElement,
+              : loopVariable?.declaredElement,
           elementType ?? typeProvider.dynamicType);
       node.body?.accept(this);
       _flowAnalysis?.flow?.forEach_end();
@@ -4555,6 +4619,7 @@
         isConst: isConst,
         errorReporter: errorReporter,
         errorNode: errorNode,
+        isNonNullableByDefault: _nonNullableEnabled,
       );
       if (typeArguments != null) {
         return uninstantiatedType.instantiate(typeArguments);
@@ -5596,7 +5661,7 @@
 ///
 /// The client must set [nameScope] before calling [resolveTypeName].
 class TypeNameResolver {
-  final Dart2TypeSystem typeSystem;
+  final TypeSystemImpl typeSystem;
   final DartType dynamicType;
   final bool isNonNullableUnit;
   final AnalysisOptionsImpl analysisOptions;
@@ -6082,6 +6147,7 @@
           declaredReturnType: typeElement.thisType,
           argumentTypes: const [],
           contextReturnType: enclosingClassElement.thisType,
+          isNonNullableByDefault: isNonNullableUnit,
         );
       }
     }
@@ -6481,8 +6547,16 @@
   /// The elements know to be used.
   final UsedLocalElements _usedElements;
 
+  /// The inheritance manager used to find overridden methods.
+  final InheritanceManager3 _inheritanceManager;
+
+  /// The URI of the library being verified.
+  final Uri _libraryUri;
+
   /// Create a new instance of the [UnusedLocalElementsVerifier].
-  UnusedLocalElementsVerifier(this._errorListener, this._usedElements);
+  UnusedLocalElementsVerifier(this._errorListener, this._usedElements,
+      this._inheritanceManager, LibraryElement library)
+      : _libraryUri = library.source.uri;
 
   visitSimpleIdentifier(SimpleIdentifier node) {
     if (node.inDeclarationContext()) {
@@ -6507,6 +6581,8 @@
     }
   }
 
+  /// Returns whether the name of [element] consists only of underscore
+  /// characters.
   bool _isNamedUnderscore(LocalVariableElement element) {
     String name = element.name;
     if (name != null) {
@@ -6521,6 +6597,8 @@
     return false;
   }
 
+  /// Returns whether [element] is a private element which is read somewhere in
+  /// the library.
   bool _isReadMember(Element element) {
     if (element.isPublic) {
       return true;
@@ -6528,7 +6606,15 @@
     if (element.isSynthetic) {
       return true;
     }
-    return _usedElements.readMembers.contains(element.displayName);
+    if (element is FieldElement) {
+      element = (element as FieldElement).getter;
+    }
+    if (_usedElements.readMembers.contains(element) ||
+        _usedElements.unresolvedReadMembers.contains(element.name)) {
+      return true;
+    }
+
+    return _overridesUsedElement(element);
   }
 
   bool _isUsedElement(Element element) {
@@ -6553,10 +6639,32 @@
     if (element.isSynthetic) {
       return true;
     }
-    if (_usedElements.members.contains(element.displayName)) {
+    if (_usedElements.members.contains(element)) {
       return true;
     }
-    return _usedElements.elements.contains(element);
+    if (_usedElements.elements.contains(element)) {
+      return true;
+    }
+
+    return _overridesUsedElement(element);
+  }
+
+  // Check if this is a class member which overrides a super class's class
+  // member which is used.
+  bool _overridesUsedElement(Element element) {
+    Element enclosingElement = element.enclosingElement;
+    if (enclosingElement is ClassElement) {
+      Name name = new Name(_libraryUri, element.name);
+      Iterable<ExecutableElement> overriddenElements = _inheritanceManager
+          .getOverridden(enclosingElement.thisType, name)
+          ?.map((ExecutableElement e) =>
+              (e is ExecutableMember) ? e.declaration : e);
+      if (overriddenElements != null) {
+        return overriddenElements.any((ExecutableElement e) =>
+            _usedElements.members.contains(e) || _overridesUsedElement(e));
+      }
+    }
+    return false;
   }
 
   void _reportErrorForElement(
@@ -6646,13 +6754,14 @@
   final HashSet<LocalVariableElement> catchStackTraceElements =
       new HashSet<LocalVariableElement>();
 
-  /// Names of resolved or unresolved class members that are referenced in the
-  /// library.
-  final HashSet<String> members = new HashSet<String>();
+  /// Resolved class members that are referenced in the library.
+  final HashSet<Element> members = new HashSet<Element>();
 
-  /// Names of resolved or unresolved class members that are read in the
-  /// library.
-  final HashSet<String> readMembers = new HashSet<String>();
+  /// Resolved class members that are read in the library.
+  final HashSet<Element> readMembers = new HashSet<Element>();
+
+  /// Unresolved class members that are read in the library.
+  final HashSet<String> unresolvedReadMembers = new HashSet<String>();
 
   UsedLocalElements();
 
@@ -6666,6 +6775,7 @@
       result.catchStackTraceElements.addAll(part.catchStackTraceElements);
       result.members.addAll(part.members);
       result.readMembers.addAll(part.readMembers);
+      result.unresolvedReadMembers.addAll(part.unresolvedReadMembers);
     }
     return result;
   }
diff --git a/pkg/analyzer/lib/src/generated/sdk_io.dart b/pkg/analyzer/lib/src/generated/sdk_io.dart
index 48993a4..c2c8506 100644
--- a/pkg/analyzer/lib/src/generated/sdk_io.dart
+++ b/pkg/analyzer/lib/src/generated/sdk_io.dart
@@ -63,9 +63,8 @@
   @override
   AnalysisContext get context {
     if (_analysisContext == null) {
-      _analysisContext = new SdkAnalysisContext(_analysisOptions);
-      SourceFactory factory = new SourceFactory([new DartUriResolver(this)]);
-      _analysisContext.sourceFactory = factory;
+      var factory = SourceFactory([DartUriResolver(this)]);
+      _analysisContext = SdkAnalysisContext(_analysisOptions, factory);
     }
     return _analysisContext;
   }
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index ff85dcb..f6872ad 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -53,7 +53,7 @@
   /**
    * The type system in use for static type analysis.
    */
-  Dart2TypeSystem _typeSystem;
+  TypeSystemImpl _typeSystem;
 
   /**
    * The type representing the type 'dynamic'.
@@ -250,6 +250,7 @@
       isConst: node.isConst,
       errorReporter: _resolver.errorReporter,
       errorNode: node,
+      isNonNullableByDefault: _nonNullableEnabled,
     );
     return element.instantiate(
       typeArguments: typeArguments,
@@ -274,6 +275,7 @@
       isConst: node.isConst,
       errorReporter: _resolver.errorReporter,
       errorNode: node,
+      isNonNullableByDefault: _nonNullableEnabled,
     );
     return element.instantiate(
       typeArguments: typeArguments,
@@ -297,6 +299,7 @@
       isConst: node.isConst,
       errorReporter: _resolver.errorReporter,
       errorNode: node,
+      isNonNullableByDefault: _nonNullableEnabled,
     );
     return element.instantiate(
       typeArguments: typeArguments,
@@ -1279,6 +1282,8 @@
         _typeSystem.getLeastUpperBound(staticType1, staticType2) ??
             _dynamicType;
 
+    staticType = _resolver.toLegacyTypeIfOptOut(staticType);
+
     _recordStaticType(node, staticType);
   }
 
@@ -1679,6 +1684,7 @@
         isConst: isConst,
         errorReporter: _resolver.errorReporter,
         errorNode: errorNode,
+        isNonNullableByDefault: _nonNullableEnabled,
       );
       if (node is InvocationExpressionImpl) {
         node.typeArgumentTypes = typeArgs;
@@ -2124,6 +2130,7 @@
       declaredReturnType: element.thisType,
       argumentTypes: argumentTypes,
       contextReturnType: contextType,
+      isNonNullableByDefault: _nonNullableEnabled,
     );
     return element.instantiate(
       typeArguments: typeArguments,
@@ -2155,6 +2162,7 @@
       declaredReturnType: element.thisType,
       argumentTypes: argumentTypes,
       contextReturnType: contextType,
+      isNonNullableByDefault: _nonNullableEnabled,
     );
     return element.instantiate(
       typeArguments: typeArguments,
@@ -2205,7 +2213,7 @@
       {this.elementType, this.keyType, this.valueType});
 
   factory _InferredCollectionElementTypeInformation.forIfElement(
-      TypeSystem typeSystem,
+      TypeSystemImpl typeSystem,
       _InferredCollectionElementTypeInformation thenInfo,
       _InferredCollectionElementTypeInformation elseInfo) {
     if (thenInfo.isDynamic) {
@@ -2259,7 +2267,7 @@
   }
 
   static DartType _leastUpperBoundOfTypes(
-      TypeSystem typeSystem, DartType first, DartType second) {
+      TypeSystemImpl typeSystem, DartType first, DartType second) {
     if (first == null) {
       return second;
     } else if (second == null) {
diff --git a/pkg/analyzer/lib/src/generated/super_context.dart b/pkg/analyzer/lib/src/generated/super_context.dart
index 3613971..bee205b 100644
--- a/pkg/analyzer/lib/src/generated/super_context.dart
+++ b/pkg/analyzer/lib/src/generated/super_context.dart
@@ -7,6 +7,10 @@
 /// An indication of the kind of context in which a super expression was found.
 class SuperContext {
   /// An indication that the super expression is in a context in which it is
+  /// invalid because it is in an annotation.
+  static const SuperContext annotation = SuperContext._('annotation');
+
+  /// An indication that the super expression is in a context in which it is
   /// invalid because it is in an instance member of an extension.
   static const SuperContext extension = SuperContext._('extension');
 
@@ -25,7 +29,9 @@
   /// being used.
   factory SuperContext.of(SuperExpression expression) {
     for (AstNode node = expression; node != null; node = node.parent) {
-      if (node is CompilationUnit) {
+      if (node is Annotation) {
+        return SuperContext.annotation;
+      } else if (node is CompilationUnit) {
         return SuperContext.static;
       } else if (node is ConstructorDeclaration) {
         return node.factoryKeyword == null
diff --git a/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart b/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart
index a854d3f..a041a8a 100644
--- a/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart
+++ b/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart
@@ -8,6 +8,7 @@
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/nullability_suffix.dart';
+import 'package:analyzer/src/dart/ast/ast_factory.dart';
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/generated/testing/token_factory.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
@@ -1360,6 +1361,17 @@
       astFactory.typeParameter(null, null, identifier3(name),
           TokenFactory.tokenFromKeyword(Keyword.EXTENDS), bound);
 
+  static TypeParameter typeParameter3(String name, String varianceLexeme) =>
+      // TODO (kallentu) : Clean up AstFactoryImpl casting once variance is
+      // added to the interface.
+      (astFactory as AstFactoryImpl).typeParameter2(
+          comment: null,
+          metadata: null,
+          name: identifier3(name),
+          extendsKeyword: null,
+          bound: null,
+          varianceKeyword: TokenFactory.tokenFromString(varianceLexeme));
+
   static TypeParameterList typeParameterList([List<String> typeNames]) {
     List<TypeParameter> typeParameters;
     if (typeNames != null && typeNames.isNotEmpty) {
diff --git a/pkg/analyzer/lib/src/generated/testing/element_factory.dart b/pkg/analyzer/lib/src/generated/testing/element_factory.dart
index 846783b..05ea5ae 100644
--- a/pkg/analyzer/lib/src/generated/testing/element_factory.dart
+++ b/pkg/analyzer/lib/src/generated/testing/element_factory.dart
@@ -11,6 +11,7 @@
 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/resolver/variance.dart';
 import 'package:analyzer/src/generated/constant.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/resolver.dart';
@@ -223,8 +224,7 @@
 
   static ExtensionElementImpl extensionElement(
           [String name, DartType extendedType]) =>
-      ExtensionElementImpl.forNode(AstTestFactory.identifier3(name))
-        ..extendedType = extendedType;
+      ExtensionElementImpl(name, -1)..extendedType = extendedType;
 
   static FieldElementImpl fieldElement(
       String name, bool isStatic, bool isFinal, bool isConst, DartType type,
@@ -248,7 +248,7 @@
 
   static FieldFormalParameterElementImpl fieldFormalParameter(
           Identifier name) =>
-      new FieldFormalParameterElementImpl.forNode(name);
+      new FieldFormalParameterElementImpl(name.name, name.offset);
 
   /**
    * Destroy any static state retained by [ElementFactory].  This should be
@@ -452,7 +452,7 @@
   }
 
   static LocalVariableElementImpl localVariableElement(Identifier name) =>
-      new LocalVariableElementImpl.forNode(name);
+      new LocalVariableElementImpl(name.name, name.offset);
 
   static LocalVariableElementImpl localVariableElement2(String name) =>
       new LocalVariableElementImpl(name, 0);
@@ -589,7 +589,7 @@
   }
 
   static TopLevelVariableElementImpl topLevelVariableElement(Identifier name) =>
-      new TopLevelVariableElementImpl.forNode(name);
+      new TopLevelVariableElementImpl(name.name, name.offset);
 
   static TopLevelVariableElementImpl topLevelVariableElement2(String name) =>
       topLevelVariableElement3(name, false, false, null);
@@ -599,8 +599,7 @@
     TopLevelVariableElementImpl variable;
     if (isConst) {
       ConstTopLevelVariableElementImpl constant =
-          new ConstTopLevelVariableElementImpl.forNode(
-              AstTestFactory.identifier3(name));
+          new ConstTopLevelVariableElementImpl(name, -1);
       InstanceCreationExpression initializer =
           AstTestFactory.instanceCreationExpression2(
               Keyword.CONST, AstTestFactory.typeName(type.element));
@@ -643,9 +642,10 @@
   }
 
   static TypeParameterElementImpl typeParameterWithType(String name,
-      [DartType bound]) {
+      [DartType bound, Variance variance]) {
     TypeParameterElementImpl typeParameter = typeParameterElement(name);
     typeParameter.bound = bound;
+    typeParameter.variance = variance;
     return typeParameter;
   }
 
diff --git a/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart b/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart
index 411503d..8113abe 100644
--- a/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart
+++ b/pkg/analyzer/lib/src/generated/testing/test_type_provider.dart
@@ -16,22 +16,29 @@
  */
 class TestTypeProvider extends TypeProviderImpl {
   factory TestTypeProvider({
-    NullabilitySuffix nullabilitySuffix = NullabilitySuffix.star,
+    bool isNonNullableByDefault = false,
   }) {
     var context = _MockAnalysisContext();
-    var sdkElements = MockSdkElements(context, nullabilitySuffix);
+    var sdkElements = MockSdkElements(
+      context,
+      isNonNullableByDefault ? NullabilitySuffix.none : NullabilitySuffix.star,
+    );
     return TestTypeProvider._(
-      nullabilitySuffix,
       sdkElements.coreLibrary,
       sdkElements.asyncLibrary,
+      isNonNullableByDefault,
     );
   }
 
   TestTypeProvider._(
-    NullabilitySuffix nullabilitySuffix,
     LibraryElement coreLibrary,
     LibraryElement asyncLibrary,
-  ) : super(coreLibrary, asyncLibrary, nullabilitySuffix: nullabilitySuffix);
+    bool isNonNullableByDefault,
+  ) : super(
+          coreLibrary: coreLibrary,
+          asyncLibrary: asyncLibrary,
+          isNonNullableByDefault: isNonNullableByDefault,
+        );
 }
 
 class _MockAnalysisContext implements AnalysisContext {
diff --git a/pkg/analyzer/lib/src/generated/type_promotion_manager.dart b/pkg/analyzer/lib/src/generated/type_promotion_manager.dart
index 9ecf575..8411dc2 100644
--- a/pkg/analyzer/lib/src/generated/type_promotion_manager.dart
+++ b/pkg/analyzer/lib/src/generated/type_promotion_manager.dart
@@ -15,7 +15,7 @@
 /// types of local variables and formal parameters from their declared types
 /// based on control flow.
 class TypePromotionManager {
-  final TypeSystem _typeSystem;
+  final TypeSystemImpl _typeSystem;
 
   /// The current promotion scope, or `null` if no scope has been entered.
   _TypePromoteScope _currentScope;
diff --git a/pkg/analyzer/lib/src/generated/type_system.dart b/pkg/analyzer/lib/src/generated/type_system.dart
index 1b841ec..74c495c 100644
--- a/pkg/analyzer/lib/src/generated/type_system.dart
+++ b/pkg/analyzer/lib/src/generated/type_system.dart
@@ -15,12 +15,11 @@
 import 'package:analyzer/error/listener.dart' show ErrorReporter;
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/member.dart' show TypeParameterMember;
+import 'package:analyzer/src/dart/element/nullability_eliminator.dart';
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/type_algebra.dart';
 import 'package:analyzer/src/dart/resolver/variance.dart';
 import 'package:analyzer/src/error/codes.dart' show HintCode, StrongModeCode;
-import 'package:analyzer/src/generated/engine.dart'
-    show AnalysisContext, AnalysisOptionsImpl;
 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
 import 'package:analyzer/src/generated/utilities_dart.dart' show ParameterKind;
 import 'package:meta/meta.dart';
@@ -92,6 +91,8 @@
 
 /**
  * A type system that implements the type semantics for Dart 2.0.
+ *
+ * TODO(scheglov) Merge it into TypeSystemImpl.
  */
 class Dart2TypeSystem extends TypeSystem {
   /**
@@ -102,6 +103,10 @@
    */
   final bool implicitCasts;
 
+  /// If `true`, then NNBD type rules should be used.
+  /// If `false`, then legacy type rules should be used.
+  final bool isNonNullableByDefault;
+
   /// A flag indicating whether inference failures are allowed, off by default.
   ///
   /// This option is experimental and subject to change.
@@ -118,8 +123,12 @@
   /// The cached instance of `Null!`.
   InterfaceTypeImpl _nullNoneCached;
 
-  Dart2TypeSystem(this.typeProvider,
-      {this.implicitCasts: true, this.strictInference: false});
+  Dart2TypeSystem({
+    @required this.implicitCasts,
+    @required this.isNonNullableByDefault,
+    @required this.strictInference,
+    @required this.typeProvider,
+  });
 
   InterfaceTypeImpl get _nullNone =>
       _nullNoneCached ??= (typeProvider.nullType as TypeImpl)
@@ -222,6 +231,241 @@
   }
 
   /**
+   * Compute the least upper bound of two types.
+   *
+   * https://github.com/dart-lang/language
+   * See `resources/type-system/upper-lower-bounds.md`
+   */
+  DartType getLeastUpperBound(DartType T1, DartType T2) {
+    // UP(T, T) = T
+    if (identical(T1, T2)) {
+      return T1;
+    }
+
+    // For any type T, LUB(?, T) == T.
+    if (identical(T1, UnknownInferredType.instance)) {
+      return T2;
+    }
+    if (identical(T2, UnknownInferredType.instance)) {
+      return T1;
+    }
+
+    var T1_isTop = isTop(T1);
+    var T2_isTop = isTop(T2);
+
+    // UP(T1, T2) where TOP(T1) and TOP(T2)
+    if (T1_isTop && T2_isTop) {
+      // * T1 if MORETOP(T1, T2)
+      // * T2 otherwise
+      if (isMoreTop(T1, T2)) {
+        return T1;
+      } else {
+        return T2;
+      }
+    }
+
+    // UP(T1, T2) = T1 if TOP(T1)
+    if (T1_isTop) {
+      return T1;
+    }
+
+    // UP(T1, T2) = T2 if TOP(T2)
+    if (T2_isTop) {
+      return T2;
+    }
+
+    var T1_isBottom = isBottom(T1);
+    var T2_isBottom = isBottom(T2);
+
+    // UP(T1, T2) where BOTTOM(T1) and BOTTOM(T2)
+    if (T1_isBottom && T2_isBottom) {
+      // * T2 if MOREBOTTOM(T1, T2)
+      // * T1 otherwise
+      if (isMoreBottom(T1, T2)) {
+        return T2;
+      } else {
+        return T1;
+      }
+    }
+
+    // UP(T1, T2) = T2 if BOTTOM(T1)
+    if (T1_isBottom) {
+      return T2;
+    }
+
+    // UP(T1, T2) = T1 if BOTTOM(T2)
+    if (T2_isBottom) {
+      return T1;
+    }
+
+    var T1_isNull = isNull(T1);
+    var T2_isNull = isNull(T2);
+
+    // UP(T1, T2) where NULL(T1) and NULL(T2)
+    if (T1_isNull && T2_isNull) {
+      // * T2 if MOREBOTTOM(T1, T2)
+      // * T1 otherwise
+      if (isMoreBottom(T1, T2)) {
+        return T2;
+      } else {
+        return T1;
+      }
+    }
+
+    // UP(T1, T2) where NULL(T1)
+    if (T1_isNull) {
+      // * T2 if T2 is nullable
+      // * T2? otherwise
+      if (isNullable(T2)) {
+        return T2;
+      } else {
+        return makeNullable(T2);
+      }
+    }
+
+    // UP(T1, T2) where NULL(T2)
+    if (T2_isNull) {
+      // * T1 if T1 is nullable
+      // * T1? otherwise
+      if (isNullable(T1)) {
+        return T1;
+      } else {
+        return makeNullable(T1);
+      }
+    }
+
+    var T1_isObject = isObject(T1);
+    var T2_isObject = isObject(T2);
+
+    // UP(T1, T2) where OBJECT(T1) and OBJECT(T2)
+    if (T1_isObject && T2_isObject) {
+      // * T1 if MORETOP(T1, T2)
+      // * T2 otherwise
+      if (isMoreTop(T1, T2)) {
+        return T1;
+      } else {
+        return T2;
+      }
+    }
+
+    // UP(T1, T2) where OBJECT(T1)
+    if (T1_isObject) {
+      // * T1 if T2 is non-nullable
+      // * T1? otherwise
+      if (isNonNullable(T2)) {
+        return T1;
+      } else {
+        return makeNullable(T1);
+      }
+    }
+
+    // UP(T1, T2) where OBJECT(T2)
+    if (T2_isObject) {
+      // * T2 if T1 is non-nullable
+      // * T2? otherwise
+      if (isNonNullable(T1)) {
+        return T2;
+      } else {
+        return makeNullable(T2);
+      }
+    }
+
+    var T1_impl = T1 as TypeImpl;
+    var T2_impl = T2 as TypeImpl;
+
+    var T1_nullability = T1_impl.nullabilitySuffix;
+    var T2_nullability = T2_impl.nullabilitySuffix;
+
+    // UP(T1*, T2*) = S* where S is UP(T1, T2)
+    // UP(T1*, T2?) = S? where S is UP(T1, T2)
+    // UP(T1?, T2*) = S? where S is UP(T1, T2)
+    // UP(T1*, T2) = S* where S is UP(T1, T2)
+    // UP(T1, T2*) = S* where S is UP(T1, T2)
+    // UP(T1?, T2?) = S? where S is UP(T1, T2)
+    // UP(T1?, T2) = S? where S is UP(T1, T2)
+    // UP(T1, T2?) = S? where S is UP(T1, T2)
+    if (T1_nullability != NullabilitySuffix.none ||
+        T2_nullability != NullabilitySuffix.none) {
+      var resultNullability = NullabilitySuffix.none;
+      if (T1_nullability == NullabilitySuffix.question ||
+          T2_nullability == NullabilitySuffix.question) {
+        resultNullability = NullabilitySuffix.question;
+      } else if (T1_nullability == NullabilitySuffix.star ||
+          T2_nullability == NullabilitySuffix.star) {
+        resultNullability = NullabilitySuffix.star;
+      }
+      var T1_none = T1_impl.withNullability(NullabilitySuffix.none);
+      var T2_none = T2_impl.withNullability(NullabilitySuffix.none);
+      var S = getLeastUpperBound(T1_none, T2_none);
+      return (S as TypeImpl).withNullability(resultNullability);
+    }
+
+    assert(T1_nullability == NullabilitySuffix.none);
+    assert(T2_nullability == NullabilitySuffix.none);
+
+    // UP(X1 extends B1, T2)
+    // UP(X1 & B1, T2)
+    if (T1 is TypeParameterType) {
+      // T2 if X1 <: T2
+      if (isSubtypeOf(T1, T2)) {
+        return T2;
+      }
+      // otherwise X1 if T2 <: X1
+      if (isSubtypeOf(T2, T1)) {
+        return T1;
+      }
+      // otherwise UP(B1[Object/X1], T2)
+      var T1_toObject = _typeParameterResolveToObjectBounds(T1);
+      return getLeastUpperBound(T1_toObject, T2);
+    }
+
+    // UP(T1, X2 extends B2)
+    // UP(T1, X2 & B2)
+    if (T2 is TypeParameterType) {
+      // X2 if T1 <: X2
+      if (isSubtypeOf(T1, T2)) {
+        // TODO(scheglov) How to get here?
+        return T2;
+      }
+      // otherwise T1 if X2 <: T1
+      if (isSubtypeOf(T2, T1)) {
+        return T1;
+      }
+      // otherwise UP(T1, B2[Object/X2])
+      var T2_toObject = _typeParameterResolveToObjectBounds(T2);
+      return getLeastUpperBound(T1, T2_toObject);
+    }
+
+    // UP(T Function<...>(...), Function) = Function
+    if (T1 is FunctionType && T2.isDartCoreFunction) {
+      return T2;
+    }
+
+    // UP(Function, T Function<...>(...)) = Function
+    if (T1.isDartCoreFunction && T2 is FunctionType) {
+      return T1;
+    }
+
+    // UP(T Function<...>(...), S Function<...>(...)) = Function
+    // And other, more interesting variants.
+    if (T1 is FunctionType && T2 is FunctionType) {
+      return _functionLeastUpperBound(T1, T2);
+    }
+
+    // UP(T Function<...>(...), T2) = Object
+    // UP(T1, T Function<...>(...)) = Object
+    if (T1 is FunctionType || T2 is FunctionType) {
+      return _objectNone;
+    }
+
+    // UP(T1, T2) = T2 if T1 <: T2
+    // UP(T1, T2) = T1 if T2 <: T1
+    // And other, more complex variants of interface types.
+    var helper = InterfaceLeastUpperBoundHelper(this);
+    return helper.compute(T1, T2);
+  }
+
+  /**
    * Given a generic function type `F<T0, T1, ... Tn>` and a context type C,
    * infer an instantiation of F, such that `F<S0, S1, ..., Sn>` <: C.
    *
@@ -282,6 +526,7 @@
     @required DartType declaredReturnType,
     @required List<DartType> argumentTypes,
     @required DartType contextReturnType,
+    @required bool isNonNullableByDefault,
     ErrorReporter errorReporter,
     AstNode errorNode,
     bool downwards: false,
@@ -295,7 +540,12 @@
     // inferred. It will optimistically assume these type parameters can be
     // subtypes (or supertypes) as necessary, and track the constraints that
     // are implied by this.
-    var inferrer = new GenericInferrer(typeProvider, this, typeParameters);
+    var inferrer = new GenericInferrer(
+      typeProvider,
+      this,
+      typeParameters,
+      isNonNullableByDefault: isNonNullableByDefault,
+    );
 
     if (contextReturnType != null) {
       if (isConst) {
@@ -538,6 +788,24 @@
     return false;
   }
 
+  /// Return `true`  for things in the equivalence class of `Never`.
+  bool isBottom(DartType type) {
+    // BOTTOM(Never) is true
+    if (identical(type, NeverTypeImpl.instance)) {
+      return true;
+    }
+
+    // BOTTOM(X&T) is true iff BOTTOM(T)
+    // BOTTOM(X extends T) is true iff BOTTOM(T)
+    if (type is TypeParameterType) {
+      var T = type.element.bound;
+      return isBottom(T);
+    }
+
+    // BOTTOM(T) is false otherwise
+    return false;
+  }
+
   bool isGroundType(DartType t) {
     // TODO(leafp): Revisit this.
     if (t is TypeParameterType) {
@@ -573,9 +841,248 @@
     return false;
   }
 
+  /// Defines an (almost) total order on bottom and `Null` types. This does not
+  /// currently consistently order two different type variables with the same
+  /// bound.
+  bool isMoreBottom(DartType T, DartType S) {
+    var T_impl = T as TypeImpl;
+    var S_impl = S as TypeImpl;
+
+    var T_nullability = T_impl.nullabilitySuffix;
+    var S_nullability = S_impl.nullabilitySuffix;
+
+    // MOREBOTTOM(Never, T) = true
+    if (identical(T, NeverTypeImpl.instance)) {
+      return true;
+    }
+
+    // MOREBOTTOM(T, Never) = false
+    if (identical(S, NeverTypeImpl.instance)) {
+      return false;
+    }
+
+    // MOREBOTTOM(Null, T) = true
+    if (T_nullability == NullabilitySuffix.none && T.isDartCoreNull) {
+      return true;
+    }
+
+    // MOREBOTTOM(T, Null) = false
+    if (S_nullability == NullabilitySuffix.none && S.isDartCoreNull) {
+      return false;
+    }
+
+    // MOREBOTTOM(T?, S?) = MOREBOTTOM(T, S)
+    if (T_nullability == NullabilitySuffix.question &&
+        S_nullability == NullabilitySuffix.question) {
+      var T2 = T_impl.withNullability(NullabilitySuffix.none);
+      var S2 = S_impl.withNullability(NullabilitySuffix.none);
+      return isMoreBottom(T2, S2);
+    }
+
+    // MOREBOTTOM(T, S?) = true
+    if (S_nullability == NullabilitySuffix.question) {
+      return true;
+    }
+
+    // MOREBOTTOM(T?, S) = false
+    if (T_nullability == NullabilitySuffix.question) {
+      return false;
+    }
+
+    // MOREBOTTOM(T*, S*) = MOREBOTTOM(T, S)
+    if (T_nullability == NullabilitySuffix.star &&
+        S_nullability == NullabilitySuffix.star) {
+      var T2 = T_impl.withNullability(NullabilitySuffix.none);
+      var S2 = S_impl.withNullability(NullabilitySuffix.none);
+      return isMoreBottom(T2, S2);
+    }
+
+    // MOREBOTTOM(T, S*) = true
+    if (S_nullability == NullabilitySuffix.star) {
+      return true;
+    }
+
+    // MOREBOTTOM(T*, S) = false
+    if (T_nullability == NullabilitySuffix.star) {
+      return false;
+    }
+
+    // Type parameters.
+    if (T is TypeParameterType && S is TypeParameterType) {
+      // We have eliminated the possibility that T_nullability or S_nullability
+      // is anything except none by this point.
+      assert(T_nullability == NullabilitySuffix.none);
+      assert(S_nullability == NullabilitySuffix.none);
+      var T_element = T.element;
+      var S_element = S.element;
+      // MOREBOTTOM(X&T, Y&S) = MOREBOTTOM(T, S)
+      if (T_element is TypeParameterMember &&
+          S_element is TypeParameterMember) {
+        var T_bound = T_element.bound;
+        var S_bound = S_element.bound;
+        return isMoreBottom(T_bound, S_bound);
+      }
+      // MOREBOTTOM(X&T, S) = true
+      if (T_element is TypeParameterMember) {
+        return true;
+      }
+      // MOREBOTTOM(T, Y&S) = false
+      if (S_element is TypeParameterMember) {
+        return false;
+      }
+      // MOREBOTTOM(X extends T, Y extends S) = MOREBOTTOM(T, S)
+      var T_bound = T_element.bound;
+      var S_bound = S_element.bound;
+      // The invariant of the larger algorithm that this is only called with
+      // types that satisfy `BOTTOM(T)` or `NULL(T)`, and all such types, if
+      // they are type variables, have bounds which themselves are
+      // `BOTTOM` or `NULL` types.
+      assert(T_bound != null);
+      assert(S_bound != null);
+      return isMoreBottom(T_bound, S_bound);
+    }
+
+    return false;
+  }
+
   @override
   bool isMoreSpecificThan(DartType t1, DartType t2) => isSubtypeOf(t1, t2);
 
+  /// Defines a total order on top and Object types.
+  bool isMoreTop(DartType T, DartType S) {
+    var T_impl = T as TypeImpl;
+    var S_impl = S as TypeImpl;
+
+    var T_nullability = T_impl.nullabilitySuffix;
+    var S_nullability = S_impl.nullabilitySuffix;
+
+    // MORETOP(void, S) = true
+    if (identical(T, VoidTypeImpl.instance)) {
+      return true;
+    }
+
+    // MORETOP(T, void) = false
+    if (identical(S, VoidTypeImpl.instance)) {
+      return false;
+    }
+
+    // MORETOP(dynamic, S) = true
+    if (identical(T, DynamicTypeImpl.instance)) {
+      return true;
+    }
+
+    // MORETOP(T, dynamic) = false
+    if (identical(S, DynamicTypeImpl.instance)) {
+      return false;
+    }
+
+    // MORETOP(Object, S) = true
+    if (T_nullability == NullabilitySuffix.none && T.isDartCoreObject) {
+      return true;
+    }
+
+    // MORETOP(T, Object) = false
+    if (S_nullability == NullabilitySuffix.none && S.isDartCoreObject) {
+      return false;
+    }
+
+    // MORETOP(T*, S*) = MORETOP(T, S)
+    if (T_nullability == NullabilitySuffix.star &&
+        S_nullability == NullabilitySuffix.star) {
+      var T2 = T_impl.withNullability(NullabilitySuffix.none);
+      var S2 = S_impl.withNullability(NullabilitySuffix.none);
+      return isMoreTop(T2, S2);
+    }
+
+    // MORETOP(T, S*) = true
+    if (S_nullability == NullabilitySuffix.star) {
+      return true;
+    }
+
+    // MORETOP(T*, S) = false
+    if (T_nullability == NullabilitySuffix.star) {
+      return false;
+    }
+
+    // MORETOP(T?, S?) = MORETOP(T, S)
+    if (T_nullability == NullabilitySuffix.question &&
+        S_nullability == NullabilitySuffix.question) {
+      var T2 = T_impl.withNullability(NullabilitySuffix.none);
+      var S2 = S_impl.withNullability(NullabilitySuffix.none);
+      return isMoreTop(T2, S2);
+    }
+
+    // MORETOP(T, S?) = true
+    if (S_nullability == NullabilitySuffix.question) {
+      return true;
+    }
+
+    // MORETOP(T?, S) = false
+    if (T_nullability == NullabilitySuffix.question) {
+      return false;
+    }
+
+    // MORETOP(FutureOr<T>, FutureOr<S>) = MORETOP(T, S)
+    if (T is InterfaceType &&
+        T.isDartAsyncFutureOr &&
+        S is InterfaceType &&
+        S.isDartAsyncFutureOr) {
+      assert(T_nullability == NullabilitySuffix.none);
+      assert(S_nullability == NullabilitySuffix.none);
+      var T2 = T.typeArguments[0];
+      var S2 = S.typeArguments[0];
+      return isMoreTop(T2, S2);
+    }
+
+    return false;
+  }
+
+  /// Return `true` for things in the equivalence class of `Null`.
+  bool isNull(DartType type) {
+    var typeImpl = type as TypeImpl;
+    var nullabilitySuffix = typeImpl.nullabilitySuffix;
+
+    // NULL(Null) is true
+    // Also includes `Null?` and `Null*` from the rules below.
+    if (type.isDartCoreNull) {
+      return true;
+    }
+
+    // NULL(T?) is true iff NULL(T) or BOTTOM(T)
+    // NULL(T*) is true iff NULL(T) or BOTTOM(T)
+    // Cases for `Null?` and `Null*` are already checked above.
+    if (nullabilitySuffix == NullabilitySuffix.question ||
+        nullabilitySuffix == NullabilitySuffix.star) {
+      var T = typeImpl.withNullability(NullabilitySuffix.none);
+      return isBottom(T);
+    }
+
+    // NULL(T) is false otherwise
+    return false;
+  }
+
+  /// Return `true` for any type which is in the equivalence class of `Object`.
+  bool isObject(DartType type) {
+    TypeImpl typeImpl = type;
+    if (typeImpl.nullabilitySuffix != NullabilitySuffix.none) {
+      return false;
+    }
+
+    // OBJECT(Object) is true
+    if (type.isDartCoreObject) {
+      return true;
+    }
+
+    // OBJECT(FutureOr<T>) is OBJECT(T)
+    if (type is InterfaceType && type.isDartAsyncFutureOr) {
+      var T = type.typeArguments[0];
+      return isObject(T);
+    }
+
+    // OBJECT(T) is false otherwise
+    return false;
+  }
+
   @override
   bool isOverrideSubtypeOf(FunctionType f1, FunctionType f2) {
     return FunctionTypeImpl.relate(f1, f2, isSubtypeOf,
@@ -840,6 +1347,40 @@
     return false;
   }
 
+  /// Return `true` for any type which is in the equivalence class of top types.
+  bool isTop(DartType type) {
+    // TOP(dynamic) is true
+    if (identical(type, DynamicTypeImpl.instance)) {
+      return true;
+    }
+
+    // TOP(void) is true
+    if (identical(type, VoidTypeImpl.instance)) {
+      return true;
+    }
+
+    var typeImpl = type as TypeImpl;
+    var nullabilitySuffix = typeImpl.nullabilitySuffix;
+
+    // TOP(T?) is true iff TOP(T) or OBJECT(T)
+    // TOP(T*) is true iff TOP(T) or OBJECT(T)
+    if (nullabilitySuffix == NullabilitySuffix.question ||
+        nullabilitySuffix == NullabilitySuffix.star) {
+      var T = typeImpl.withNullability(NullabilitySuffix.none);
+      return isTop(T) || isObject(T);
+    }
+
+    // TOP(FutureOr<T>) is TOP(T)
+    if (type is InterfaceType && type.isDartAsyncFutureOr) {
+      assert(nullabilitySuffix == NullabilitySuffix.none);
+      var T = type.typeArguments[0];
+      return isTop(T);
+    }
+
+    // TOP(T) is false otherwise
+    return false;
+  }
+
   /// Given a [type] T that may have an unknown type `?`, returns a type
   /// R such that R <: T for any type substituted for `?`.
   ///
@@ -1062,14 +1603,111 @@
     return new FunctionElementImpl.synthetic(parameters, returnType).type;
   }
 
-  @override
-  DartType _functionParameterBound(DartType f, DartType g) =>
-      getGreatestLowerBound(f, g);
+  /**
+   * Compute the least upper bound of function types [f] and [g].
+   *
+   * https://github.com/dart-lang/language
+   * See `resources/type-system/upper-lower-bounds.md`
+   */
+  DartType _functionLeastUpperBound(FunctionType f, FunctionType g) {
+    var fTypeFormals = f.typeFormals;
+    var gTypeFormals = g.typeFormals;
 
-  @override
-  DartType _interfaceLeastUpperBound(InterfaceType type1, InterfaceType type2) {
-    var helper = InterfaceLeastUpperBoundHelper(this);
-    return helper.compute(type1, type2);
+    // The number of type parameters must be the same.
+    // Otherwise the result is `Function`.
+    if (fTypeFormals.length != gTypeFormals.length) {
+      return typeProvider.functionType.element.instantiate(
+        typeArguments: const [],
+        nullabilitySuffix: NullabilitySuffix.none,
+      );
+    }
+
+    // The bounds of type parameters must be equal.
+    // Otherwise the result is `Function`.
+    var freshTypeFormalTypes =
+        FunctionTypeImpl.relateTypeFormals(f, g, (t, s, _, __) => t == s);
+    if (freshTypeFormalTypes == null) {
+      return typeProvider.functionType.element.instantiate(
+        typeArguments: const [],
+        nullabilitySuffix: NullabilitySuffix.none,
+      );
+    }
+
+    var typeFormals = freshTypeFormalTypes
+        .map<TypeParameterElement>((t) => t.element)
+        .toList();
+
+    f = f.instantiate(freshTypeFormalTypes);
+    g = g.instantiate(freshTypeFormalTypes);
+
+    List<DartType> fRequired = f.normalParameterTypes;
+    List<DartType> gRequired = g.normalParameterTypes;
+
+    // The number of required parameters must be the same.
+    if (fRequired.length != gRequired.length) {
+      return typeProvider.functionType.element.instantiate(
+        typeArguments: const [],
+        nullabilitySuffix: NullabilitySuffix.none,
+      );
+    }
+
+    // We need some parameter names for the result, so arbitrarily use F's.
+    var fRequiredNames = f.normalParameterNames;
+    var fPositionalNames = f.optionalParameterNames;
+
+    // Calculate the DOWN of each corresponding pair of parameters.
+    var parameters = <ParameterElement>[];
+
+    for (int i = 0; i < fRequired.length; i++) {
+      parameters.add(
+        new ParameterElementImpl.synthetic(
+          fRequiredNames[i],
+          // TODO(scheglov) Update for NNBD aware DOWN.
+          getGreatestLowerBound(fRequired[i], gRequired[i]),
+          ParameterKind.REQUIRED,
+        ),
+      );
+    }
+
+    List<DartType> fPositional = f.optionalParameterTypes;
+    List<DartType> gPositional = g.optionalParameterTypes;
+
+    // Ignore any extra optional positional parameters.
+    int length = math.min(fPositional.length, gPositional.length);
+    for (int i = 0; i < length; i++) {
+      parameters.add(
+        new ParameterElementImpl.synthetic(
+          fPositionalNames[i],
+          // TODO(scheglov) Update for NNBD aware DOWN.
+          getGreatestLowerBound(fPositional[i], gPositional[i]),
+          ParameterKind.POSITIONAL,
+        ),
+      );
+    }
+
+    // TODO(brianwilkerson) Handle the fact that named parameters can now be
+    //  required.
+    Map<String, DartType> fNamed = f.namedParameterTypes;
+    Map<String, DartType> gNamed = g.namedParameterTypes;
+    for (String name in fNamed.keys.toSet()..retainAll(gNamed.keys)) {
+      parameters.add(
+        new ParameterElementImpl.synthetic(
+          name,
+          // TODO(scheglov) Update for NNBD aware DOWN.
+          getGreatestLowerBound(fNamed[name], gNamed[name]),
+          ParameterKind.NAMED,
+        ),
+      );
+    }
+
+    var returnType = getLeastUpperBound(f.returnType, g.returnType);
+
+    return FunctionTypeImpl(
+      typeFormals: typeFormals,
+      parameters: parameters,
+      returnType: returnType,
+      nullabilitySuffix: NullabilitySuffix.none,
+    );
   }
 
   /// Check that [f1] is a subtype of [f2].
@@ -1117,15 +1755,14 @@
         DartType t1 = tArgs1[i];
         DartType t2 = tArgs2[i];
 
-        // TODO (kallentu) : Clean up TypeParameterElementImpl checks and
-        // casting once variance is added to the interface.
-        TypeParameterElement parameterElement = tParams[i];
-        Variance variance = Variance.covariant;
-        if (parameterElement is TypeParameterElementImpl) {
-          variance = parameterElement.variance;
-        }
-
-        if (variance.isContravariant) {
+        // TODO (kallentu) : Clean up TypeParameterElementImpl casting once
+        // variance is added to the interface.
+        Variance variance = (tParams[i] as TypeParameterElementImpl).variance;
+        if (variance.isCovariant) {
+          if (!isSubtypeOf(t1, t2)) {
+            return false;
+          }
+        } else if (variance.isContravariant) {
           if (!isSubtypeOf(t2, t1)) {
             return false;
           }
@@ -1134,9 +1771,8 @@
             return false;
           }
         } else {
-          if (!isSubtypeOf(t1, t2)) {
-            return false;
-          }
+          throw new StateError('Type parameter ${tParams[i]} has unknown '
+              'variance $variance for subtype checking.');
         }
       }
       return true;
@@ -1254,59 +1890,6 @@
     return type;
   }
 
-  /**
-   * This currently just implements a simple least upper bound to
-   * handle some common cases.  It also avoids some termination issues
-   * with the naive spec algorithm.  The least upper bound of two types
-   * (at least one of which is a type parameter) is computed here as:
-   * 1. If either type is a supertype of the other, return it.
-   * 2. If the first type is a type parameter, replace it with its bound,
-   *    with recursive occurrences of itself replaced with Object.
-   *    The second part of this should ensure termination.  Informally,
-   *    each type variable instantiation in one of the arguments to the
-   *    least upper bound algorithm now strictly reduces the number
-   *    of bound variables in scope in that argument position.
-   * 3. If the second type is a type parameter, do the symmetric operation
-   *    to #2.
-   *
-   * It's not immediately obvious why this is symmetric in the case that both
-   * of them are type parameters.  For #1, symmetry holds since subtype
-   * is antisymmetric.  For #2, it's clearly not symmetric if upper bounds of
-   * bottom are allowed.  Ignoring this (for various reasons, not least
-   * of which that there's no way to write it), there's an informal
-   * argument (that might even be right) that you will always either
-   * end up expanding both of them or else returning the same result no matter
-   * which order you expand them in.  A key observation is that
-   * identical(expand(type1), type2) => subtype(type1, type2)
-   * and hence the contra-positive.
-   *
-   * TODO(leafp): Think this through and figure out what's the right
-   * definition.  Be careful about termination.
-   *
-   * I suspect in general a reasonable algorithm is to expand the innermost
-   * type variable first.  Alternatively, you could probably choose to treat
-   * it as just an instance of the interface type upper bound problem, with
-   * the "inheritance" chain extended by the bounds placed on the variables.
-   */
-  @override
-  DartType _typeParameterLeastUpperBound(DartType type1, DartType type2) {
-    if (isSubtypeOf(type1, type2)) {
-      return type2;
-    }
-    if (isSubtypeOf(type2, type1)) {
-      return type1;
-    }
-    if (type1 is TypeParameterType) {
-      type1 = _typeParameterResolveToObjectBounds(type1);
-      return getLeastUpperBound(type1, type2);
-    }
-    // We should only be called when at least one of the types is a
-    // TypeParameterType
-    type2 = _typeParameterResolveToObjectBounds(type2);
-
-    return getLeastUpperBound(type1, type2);
-  }
-
   DartType _typeParameterResolveToObjectBounds(DartType type) {
     var element = type.element;
     type = type.resolveToBound(typeProvider.objectType);
@@ -1352,8 +1935,9 @@
 /// As currently designed, an instance of this class should only be used to
 /// infer a single call and discarded immediately afterwards.
 class GenericInferrer {
-  final Dart2TypeSystem _typeSystem;
+  final TypeSystemImpl _typeSystem;
   final TypeProvider typeProvider;
+  final bool isNonNullableByDefault;
   final Map<TypeParameterElement, List<_TypeConstraint>> constraints = {};
 
   /// Buffer recording constraints recorded while performing a recursive call to
@@ -1362,7 +1946,8 @@
   final _undoBuffer = <_TypeConstraint>[];
 
   GenericInferrer(this.typeProvider, this._typeSystem,
-      Iterable<TypeParameterElement> typeFormals) {
+      Iterable<TypeParameterElement> typeFormals,
+      {this.isNonNullableByDefault = false}) {
     for (var formal in typeFormals) {
       constraints[formal] = [];
     }
@@ -1424,13 +2009,11 @@
     // degradation for f-bounded type parameters.
     var inferredTypes = new List<DartType>.filled(
         typeFormals.length, UnknownInferredType.instance);
-    var _inferTypeParameter = downwardsInferPhase
-        ? _inferTypeParameterFromContext
-        : _inferTypeParameterFromAll;
 
     for (int i = 0; i < typeFormals.length; i++) {
-      TypeParameterElement typeParam = typeFormals[i];
-
+      // TODO (kallentu) : Clean up TypeParameterElementImpl casting once
+      // variance is added to the interface.
+      TypeParameterElementImpl typeParam = typeFormals[i];
       _TypeConstraint extendsClause;
       if (considerExtendsClause && typeParam.bound != null) {
         extendsClause = new _TypeConstraint.fromExtends(
@@ -1439,8 +2022,12 @@
                 .substituteType(typeParam.bound));
       }
 
-      inferredTypes[i] =
-          _inferTypeParameter(constraints[typeParam], extendsClause);
+      inferredTypes[i] = downwardsInferPhase || !typeParam.isLegacyCovariant
+          ? _inferTypeParameterFromContext(
+              constraints[typeParam], extendsClause,
+              isContravariant: typeParam.variance.isContravariant)
+          : _inferTypeParameterFromAll(constraints[typeParam], extendsClause,
+              isContravariant: typeParam.variance.isContravariant);
     }
 
     // If the downwards infer phase has failed, we'll catch this in the upwards
@@ -1581,8 +2168,12 @@
   /// * `int <: T`
   ///
   /// ... and no upper bound. Therefore the lower bound is the best choice.
+  ///
+  /// If [isContravariant] is `true`, then we are solving for a contravariant
+  /// type parameter which means we choose the upper bound rather than the
+  /// lower bound for normally covariant type parameters.
   DartType _chooseTypeFromConstraints(Iterable<_TypeConstraint> constraints,
-      {bool toKnownType: false}) {
+      {bool toKnownType: false, @required bool isContravariant}) {
     DartType lower = UnknownInferredType.instance;
     DartType upper = UnknownInferredType.instance;
     for (var constraint in constraints) {
@@ -1601,25 +2192,44 @@
       // will fail.
       upper = _getGreatestLowerBound(upper, constraint.upperBound);
       lower = _typeSystem.getLeastUpperBound(lower, constraint.lowerBound);
+      upper = _toLegacyType(upper);
+      lower = _toLegacyType(lower);
     }
 
     // Prefer the known bound, if any.
     // Otherwise take whatever bound has partial information, e.g. `Iterable<?>`
     //
-    // For both of those, prefer the lower bound (arbitrary heuristic).
-    if (UnknownInferredType.isKnown(lower)) {
+    // For both of those, prefer the lower bound (arbitrary heuristic) or upper
+    // bound if [isContravariant] is `true`
+    if (isContravariant) {
+      if (UnknownInferredType.isKnown(upper)) {
+        return upper;
+      }
+      if (UnknownInferredType.isKnown(lower)) {
+        return lower;
+      }
+      if (!identical(UnknownInferredType.instance, upper)) {
+        return toKnownType ? _typeSystem.upperBoundForType(upper) : upper;
+      }
+      if (!identical(UnknownInferredType.instance, lower)) {
+        return toKnownType ? _typeSystem.lowerBoundForType(lower) : lower;
+      }
+      return upper;
+    } else {
+      if (UnknownInferredType.isKnown(lower)) {
+        return lower;
+      }
+      if (UnknownInferredType.isKnown(upper)) {
+        return upper;
+      }
+      if (!identical(UnknownInferredType.instance, lower)) {
+        return toKnownType ? _typeSystem.lowerBoundForType(lower) : lower;
+      }
+      if (!identical(UnknownInferredType.instance, upper)) {
+        return toKnownType ? _typeSystem.upperBoundForType(upper) : upper;
+      }
       return lower;
     }
-    if (UnknownInferredType.isKnown(upper)) {
-      return upper;
-    }
-    if (!identical(UnknownInferredType.instance, lower)) {
-      return toKnownType ? _typeSystem.lowerBoundForType(lower) : lower;
-    }
-    if (!identical(UnknownInferredType.instance, upper)) {
-      return toKnownType ? _typeSystem.upperBoundForType(upper) : upper;
-    }
-    return lower;
   }
 
   String _formatError(TypeParameterElement typeParam, DartType inferred,
@@ -1693,11 +2303,13 @@
   }
 
   DartType _inferTypeParameterFromAll(
-      List<_TypeConstraint> constraints, _TypeConstraint extendsClause) {
+      List<_TypeConstraint> constraints, _TypeConstraint extendsClause,
+      {@required bool isContravariant}) {
     // See if we already fixed this type from downwards inference.
     // If so, then we aren't allowed to change it based on argument types.
     DartType t = _inferTypeParameterFromContext(
-        constraints.where((c) => c.isDownwards), extendsClause);
+        constraints.where((c) => c.isDownwards), extendsClause,
+        isContravariant: isContravariant);
     if (UnknownInferredType.isKnown(t)) {
       // Remove constraints that aren't downward ones; we'll ignore these for
       // error reporting, because inference already succeeded.
@@ -1709,13 +2321,16 @@
       constraints = constraints.toList()..add(extendsClause);
     }
 
-    var choice = _chooseTypeFromConstraints(constraints, toKnownType: true);
+    var choice = _chooseTypeFromConstraints(constraints,
+        toKnownType: true, isContravariant: isContravariant);
     return choice;
   }
 
   DartType _inferTypeParameterFromContext(
-      Iterable<_TypeConstraint> constraints, _TypeConstraint extendsClause) {
-    DartType t = _chooseTypeFromConstraints(constraints);
+      Iterable<_TypeConstraint> constraints, _TypeConstraint extendsClause,
+      {@required bool isContravariant}) {
+    DartType t = _chooseTypeFromConstraints(constraints,
+        isContravariant: isContravariant);
     if (UnknownInferredType.isUnknown(t)) {
       return t;
     }
@@ -1729,7 +2344,8 @@
     // If we consider the `T extends num` we conclude `<num>`, which works.
     if (extendsClause != null) {
       constraints = constraints.toList()..add(extendsClause);
-      return _chooseTypeFromConstraints(constraints);
+      return _chooseTypeFromConstraints(constraints,
+          isContravariant: isContravariant);
     }
     return t;
   }
@@ -1749,12 +2365,40 @@
     if (i1.element == i2.element) {
       List<DartType> tArgs1 = i1.typeArguments;
       List<DartType> tArgs2 = i2.typeArguments;
+      List<TypeParameterElement> tParams = i1.element.typeParameters;
       assert(tArgs1.length == tArgs2.length);
+      assert(tArgs1.length == tParams.length);
       for (int i = 0; i < tArgs1.length; i++) {
-        if (!_matchSubtypeOf(
-            tArgs1[i], tArgs2[i], new HashSet<Element>(), origin,
-            covariant: covariant)) {
-          return false;
+        TypeParameterElement typeParameterElement = tParams[i];
+
+        // TODO (kallentu) : Clean up TypeParameterElementImpl casting once
+        // variance is added to the interface.
+        Variance parameterVariance =
+            (typeParameterElement as TypeParameterElementImpl).variance;
+        if (parameterVariance.isCovariant) {
+          if (!_matchSubtypeOf(
+              tArgs1[i], tArgs2[i], new HashSet<Element>(), origin,
+              covariant: covariant)) {
+            return false;
+          }
+        } else if (parameterVariance.isContravariant) {
+          if (!_matchSubtypeOf(
+              tArgs2[i], tArgs1[i], new HashSet<Element>(), origin,
+              covariant: !covariant)) {
+            return false;
+          }
+        } else if (parameterVariance.isInvariant) {
+          if (!_matchSubtypeOf(
+                  tArgs1[i], tArgs2[i], new HashSet<Element>(), origin,
+                  covariant: covariant) ||
+              !_matchSubtypeOf(
+                  tArgs2[i], tArgs1[i], new HashSet<Element>(), origin,
+                  covariant: !covariant)) {
+            return false;
+          }
+        } else {
+          throw new StateError("Type parameter ${tParams[i]} has unknown "
+              "variance $parameterVariance for inference.");
         }
       }
       return true;
@@ -1974,6 +2618,13 @@
     }
   }
 
+  /// If in a legacy library, return the legacy version of the [type].
+  /// Otherwise, return the original type.
+  DartType _toLegacyType(DartType type) {
+    if (isNonNullableByDefault) return type;
+    return NullabilityEliminator.perform(type);
+  }
+
   static String _formatConstraints(Iterable<_TypeConstraint> constraints) {
     List<List<String>> lineParts =
         new Set<_TypeConstraintOrigin>.from(constraints.map((c) => c.origin))
@@ -2122,7 +2773,7 @@
 }
 
 class InterfaceLeastUpperBoundHelper {
-  final TypeSystem typeSystem;
+  final TypeSystemImpl typeSystem;
 
   InterfaceLeastUpperBoundHelper(this.typeSystem);
 
@@ -2173,18 +2824,15 @@
 
       var args = List<DartType>(args1.length);
       for (int i = 0; i < args1.length; i++) {
-        // TODO (kallentu) : Clean up TypeParameterElementImpl checks and
-        // casting once variance is added to the interface.
-        TypeParameterElement parameter = params[i];
-        Variance parameterVariance = Variance.covariant;
-        if (parameter is TypeParameterElementImpl) {
-          parameterVariance = parameter.variance;
-        }
-
-        if (parameterVariance.isContravariant) {
-          if (typeSystem is Dart2TypeSystem) {
-            args[i] = (typeSystem as Dart2TypeSystem)
-                .getGreatestLowerBound(args1[i], args2[i]);
+        // TODO (kallentu) : Clean up TypeParameterElementImpl casting once
+        // variance is added to the interface.
+        Variance parameterVariance =
+            (params[i] as TypeParameterElementImpl).variance;
+        if (parameterVariance.isCovariant) {
+          args[i] = typeSystem.getLeastUpperBound(args1[i], args2[i]);
+        } else if (parameterVariance.isContravariant) {
+          if (typeSystem is TypeSystemImpl) {
+            args[i] = typeSystem.getGreatestLowerBound(args1[i], args2[i]);
           } else {
             args[i] = typeSystem.getLeastUpperBound(args1[i], args2[i]);
           }
@@ -2201,7 +2849,8 @@
           //  parameters.
           args[i] = args1[i];
         } else {
-          args[i] = typeSystem.getLeastUpperBound(args1[i], args2[i]);
+          throw new StateError('Type parameter ${params[i]} has unknown '
+              'variance $parameterVariance for bounds calculation.');
         }
       }
 
@@ -2499,73 +3148,7 @@
   /**
    * Compute the least upper bound of two types.
    */
-  DartType getLeastUpperBound(DartType type1, DartType type2) {
-    // The least upper bound relation is reflexive.
-    if (identical(type1, type2)) {
-      return type1;
-    }
-
-    // For any type T, LUB(?, T) == T.
-    if (identical(type1, UnknownInferredType.instance)) {
-      return type2;
-    }
-    if (identical(type2, UnknownInferredType.instance)) {
-      return type1;
-    }
-
-    // For the purpose of LUB, we say some Tops are subtypes (less toppy) than
-    // the others. Return the most toppy.
-    // TODO(mfairhurst): switch legacy Top checks to true Top checks
-    if (_isLegacyTop(type1, orTrueTop: true) &&
-        _isLegacyTop(type2, orTrueTop: true)) {
-      return _getTopiness(type1) > _getTopiness(type2) ? type1 : type2;
-    }
-
-    // The least upper bound of top and any type T is top.
-    // The least upper bound of bottom and any type T is T.
-    // TODO(mfairhurst): switch legacy Top checks to true Top checks
-    // TODO(mfairhurst): switch legacy Bottom checks to true Bottom checks
-    if (_isLegacyTop(type1, orTrueTop: true) ||
-        _isLegacyBottom(type2, orTrueBottom: true)) {
-      return type1;
-    }
-    // TODO(mfairhurst): switch legacy Top checks to true Top checks
-    // TODO(mfairhurst): switch legacy Bottom checks to true Bottom checks
-    if (_isLegacyTop(type2, orTrueTop: true) ||
-        _isLegacyBottom(type1, orTrueBottom: true)) {
-      return type2;
-    }
-
-    if (type1 is TypeParameterType || type2 is TypeParameterType) {
-      return _typeParameterLeastUpperBound(type1, type2);
-    }
-
-    // In Dart 1, the least upper bound of a function type and an interface type
-    // T is the least upper bound of Function and T.
-    //
-    // In Dart 2, the result is `Function` iff T is `Function`, otherwise the
-    // result is `Object`.
-    if (type1 is FunctionType && type2 is InterfaceType) {
-      return type2.isDartCoreFunction ? type2 : typeProvider.objectType;
-    }
-    if (type2 is FunctionType && type1 is InterfaceType) {
-      return type1.isDartCoreFunction ? type1 : typeProvider.objectType;
-    }
-
-    // At this point type1 and type2 should both either be interface types or
-    // function types.
-    if (type1 is InterfaceType && type2 is InterfaceType) {
-      return _interfaceLeastUpperBound(type1, type2);
-    }
-
-    if (type1 is FunctionType && type2 is FunctionType) {
-      return _functionLeastUpperBound(type1, type2);
-    }
-
-    // Should never happen. As a defensive measure, return the dynamic type.
-    assert(false);
-    return typeProvider.dynamicType;
-  }
+  DartType getLeastUpperBound(DartType type1, DartType type2);
 
   /**
    * Given a [DartType] [type], instantiate it with its bounds.
@@ -2879,121 +3462,6 @@
   }
 
   /**
-   * Compute the least upper bound of function types [f] and [g].
-   *
-   * The spec rules for LUB on function types, informally, are pretty simple
-   * (though unsound):
-   *
-   * - If the functions don't have the same number of required parameters,
-   *   always return `Function`.
-   *
-   * - Discard any optional named or positional parameters the two types do not
-   *   have in common.
-   *
-   * - Compute the LUB of each corresponding pair of parameter and return types.
-   *   Return a function type with those types.
-   */
-  DartType _functionLeastUpperBound(FunctionType f, FunctionType g) {
-    var fTypeFormals = f.typeFormals;
-    var gTypeFormals = g.typeFormals;
-
-    // If F and G differ in their number of type parameters, then the
-    // least upper bound of F and G is Function.
-    if (fTypeFormals.length != gTypeFormals.length) {
-      return typeProvider.functionType;
-    }
-
-    // If F and G differ in bounds of their of type parameters, then the
-    // least upper bound of F and G is Function.
-    var freshTypeFormalTypes =
-        FunctionTypeImpl.relateTypeFormals(f, g, (t, s, _, __) => t == s);
-    if (freshTypeFormalTypes == null) {
-      return typeProvider.functionType;
-    }
-
-    var typeFormals = freshTypeFormalTypes
-        .map<TypeParameterElement>((t) => t.element)
-        .toList();
-
-    f = f.instantiate(freshTypeFormalTypes);
-    g = g.instantiate(freshTypeFormalTypes);
-
-    List<DartType> fRequired = f.normalParameterTypes;
-    List<DartType> gRequired = g.normalParameterTypes;
-
-    // We need some parameter names for in the synthesized function type, so
-    // arbitrarily use f's.
-    List<String> fRequiredNames = f.normalParameterNames;
-    List<String> fPositionalNames = f.optionalParameterNames;
-
-    // If F and G differ in their number of required parameters, then the
-    // least upper bound of F and G is Function.
-    if (fRequired.length != gRequired.length) {
-      return typeProvider.functionType;
-    }
-
-    // Calculate the LUB of each corresponding pair of parameters.
-    List<ParameterElement> parameters = [];
-
-    for (int i = 0; i < fRequired.length; i++) {
-      parameters.add(new ParameterElementImpl.synthetic(
-          fRequiredNames[i],
-          _functionParameterBound(fRequired[i], gRequired[i]),
-          ParameterKind.REQUIRED));
-    }
-
-    List<DartType> fPositional = f.optionalParameterTypes;
-    List<DartType> gPositional = g.optionalParameterTypes;
-
-    // Ignore any extra optional positional parameters if one has more than the
-    // other.
-    int length = math.min(fPositional.length, gPositional.length);
-    for (int i = 0; i < length; i++) {
-      parameters.add(new ParameterElementImpl.synthetic(
-          fPositionalNames[i],
-          _functionParameterBound(fPositional[i], gPositional[i]),
-          ParameterKind.POSITIONAL));
-    }
-
-    // TODO(brianwilkerson) Handle the fact that named parameters can now be
-    //  required.
-    Map<String, DartType> fNamed = f.namedParameterTypes;
-    Map<String, DartType> gNamed = g.namedParameterTypes;
-    for (String name in fNamed.keys.toSet()..retainAll(gNamed.keys)) {
-      parameters.add(new ParameterElementImpl.synthetic(
-          name,
-          _functionParameterBound(fNamed[name], gNamed[name]),
-          ParameterKind.NAMED));
-    }
-
-    // Calculate the LUB of the return type.
-    DartType returnType = getLeastUpperBound(f.returnType, g.returnType);
-
-    return FunctionTypeImpl(
-      typeFormals: typeFormals,
-      parameters: parameters,
-      returnType: returnType,
-      nullabilitySuffix: (f as TypeImpl).nullabilitySuffix,
-    );
-  }
-
-  /**
-   * Calculates the appropriate upper or lower bound of a pair of parameters
-   * for two function types whose least upper bound is being calculated.
-   *
-   * In spec mode, this uses least upper bound, which... doesn't really make
-   * much sense. Strong mode overrides this to use greatest lower bound.
-   */
-  DartType _functionParameterBound(DartType f, DartType g) =>
-      getLeastUpperBound(f, g);
-
-  /**
-   * Given two [InterfaceType]s [type1] and [type2] return their least upper
-   * bound in a type system specific manner.
-   */
-  DartType _interfaceLeastUpperBound(InterfaceType type1, InterfaceType type2);
-
-  /**
    * Starting from the given [type], search its class hierarchy for types of the
    * form Future<R>, and return a list of the resulting R's.
    */
@@ -3018,23 +3486,23 @@
     recurse(type);
     return result;
   }
+}
 
-  /**
-   * Given two [DartType]s [type1] and [type2] at least one of which is a
-   * [TypeParameterType], return their least upper bound in a type system
-   * specific manner.
-   */
-  DartType _typeParameterLeastUpperBound(DartType type1, DartType type2);
-
-  /**
-   * Create either a strong mode or regular type system based on context.
-   */
-  static TypeSystem create(AnalysisContext context) {
-    var options = context.analysisOptions as AnalysisOptionsImpl;
-    return new Dart2TypeSystem(context.typeProvider,
-        implicitCasts: options.implicitCasts,
-        strictInference: options.strictInference);
-  }
+/**
+ * The [public.TypeSystem] implementation.
+ */
+class TypeSystemImpl extends Dart2TypeSystem {
+  TypeSystemImpl({
+    @required bool implicitCasts,
+    @required bool isNonNullableByDefault,
+    @required bool strictInference,
+    @required TypeProvider typeProvider,
+  }) : super(
+          implicitCasts: implicitCasts,
+          isNonNullableByDefault: isNonNullableByDefault,
+          strictInference: strictInference,
+          typeProvider: typeProvider,
+        );
 }
 
 /// A type that is being inferred but is not currently known.
@@ -3062,8 +3530,7 @@
   bool operator ==(Object object) => identical(object, this);
 
   @override
-  void appendTo(StringBuffer buffer, Set<TypeImpl> types,
-      {bool withNullability = false}) {
+  void appendTo(StringBuffer buffer, {bool withNullability = false}) {
     buffer.write('?');
   }
 
@@ -3160,7 +3627,7 @@
 
   bool get isDownwards => origin is! _TypeConstraintFromArgument;
 
-  bool isSatisifedBy(TypeSystem ts, DartType type) =>
+  bool isSatisifedBy(TypeSystemImpl ts, DartType type) =>
       ts.isSubtypeOf(lowerBound, type) && ts.isSubtypeOf(type, upperBound);
 
   /// Converts this constraint to a message suitable for a type inference error.
diff --git a/pkg/analyzer/lib/src/ignore_comments/ignore_info.dart b/pkg/analyzer/lib/src/ignore_comments/ignore_info.dart
index 2596ac9..f2fb192 100644
--- a/pkg/analyzer/lib/src/ignore_comments/ignore_info.dart
+++ b/pkg/analyzer/lib/src/ignore_comments/ignore_info.dart
@@ -36,26 +36,15 @@
   final Set<String> _ignoreForFileSet = new HashSet<String>();
 
   /// Whether this info object defines any ignores.
-  bool get hasIgnores => ignores.isNotEmpty || _ignoreForFileSet.isNotEmpty;
-
-  /// Iterable of error codes ignored for the whole file.
-  Iterable<String> get ignoreForFiles => _ignoreForFileSet;
-
-  /// Map of line numbers to associated ignored error codes.
-  Map<int, Iterable<String>> get ignores => _ignoreMap;
-
-  /// Ignore this [errorCode] at [line].
-  void add(int line, String errorCode) {
-    _ignoreMap.putIfAbsent(line, () => new List<String>()).add(errorCode);
-  }
+  bool get hasIgnores => _ignoreMap.isNotEmpty || _ignoreForFileSet.isNotEmpty;
 
   /// Ignore these [errorCodes] at [line].
-  void addAll(int line, Iterable<String> errorCodes) {
+  void _addAll(int line, Iterable<String> errorCodes) {
     _ignoreMap.putIfAbsent(line, () => new List<String>()).addAll(errorCodes);
   }
 
   /// Ignore these [errorCodes] in the whole file.
-  void addAllForFile(Iterable<String> errorCodes) {
+  void _addAllForFile(Iterable<String> errorCodes) {
     _ignoreForFileSet.addAll(errorCodes);
   }
 
@@ -87,10 +76,10 @@
 
       if (beforeMatch.trim().isEmpty) {
         // The comment is on its own line, so it refers to the next line.
-        ignoreInfo.addAll(lineNumber + 1, codes);
+        ignoreInfo._addAll(lineNumber + 1, codes);
       } else {
         // The comment sits next to code, so it refers to its own line.
-        ignoreInfo.addAll(lineNumber, codes);
+        ignoreInfo._addAll(lineNumber, codes);
       }
     }
     for (Match match in fileMatches) {
@@ -98,7 +87,7 @@
           .group(1)
           .split(',')
           .map((String code) => code.trim().toLowerCase());
-      ignoreInfo.addAllForFile(codes);
+      ignoreInfo._addAllForFile(codes);
     }
     return ignoreInfo;
   }
diff --git a/pkg/analyzer/lib/src/lint/linter.dart b/pkg/analyzer/lib/src/lint/linter.dart
index 6e51f55..319b9e9 100644
--- a/pkg/analyzer/lib/src/lint/linter.dart
+++ b/pkg/analyzer/lib/src/lint/linter.dart
@@ -8,19 +8,23 @@
 import 'package:analyzer/dart/analysis/declared_variables.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/dart/constant/value.dart';
 import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type_system.dart';
 import 'package:analyzer/error/error.dart';
 import 'package:analyzer/error/listener.dart';
 import 'package:analyzer/file_system/file_system.dart' as file_system;
 import 'package:analyzer/src/dart/ast/ast.dart';
 import 'package:analyzer/src/dart/ast/token.dart';
+import 'package:analyzer/src/dart/constant/evaluation.dart';
 import 'package:analyzer/src/dart/constant/potentially_constant.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
 import 'package:analyzer/src/dart/error/lint_codes.dart';
 import 'package:analyzer/src/generated/engine.dart'
     show AnalysisErrorInfo, AnalysisErrorInfoImpl, AnalysisOptions;
-import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/resolver.dart'
+    show ConstantVerifier, TypeProvider;
 import 'package:analyzer/src/generated/source.dart' show LineInfo;
 import 'package:analyzer/src/generated/source_io.dart';
 import 'package:analyzer/src/lint/analysis.dart';
@@ -201,6 +205,17 @@
   String _emph(msg) => bold ? '<strong>$msg</strong>' : msg;
 }
 
+/// The result of attempting to evaluate an expression.
+class LinterConstantEvaluationResult {
+  /// The value of the expression, or `null` if has [errors].
+  final DartObject value;
+
+  /// The errors reported during the evaluation.
+  final List<AnalysisError> errors;
+
+  LinterConstantEvaluationResult(this.value, this.errors);
+}
+
 /// Provides access to information needed by lint rules that is not available
 /// from AST nodes or the element model.
 abstract class LinterContext {
@@ -239,6 +254,9 @@
   /// Note that this method can cause constant evaluation to occur, which can be
   /// computationally expensive.
   bool canBeConstConstructor(ConstructorDeclaration node);
+
+  /// Return the result of evaluating the given expression.
+  LinterConstantEvaluationResult evaluateConstant(Expression node);
 }
 
 /// Implementation of [LinterContext]
@@ -323,6 +341,23 @@
     }
   }
 
+  @override
+  LinterConstantEvaluationResult evaluateConstant(Expression node) {
+    var source = currentUnit.unit.declaredElement.source;
+    var errorListener = RecordingErrorListener();
+    var visitor = ConstantVisitor(
+      ConstantEvaluationEngine(
+        typeProvider,
+        declaredVariables,
+        typeSystem: typeSystem,
+      ),
+      ErrorReporter(errorListener, source),
+    );
+
+    var value = node.accept(visitor);
+    return LinterConstantEvaluationResult(value, errorListener.errors);
+  }
+
   /// Return `true` if [ConstantVerifier] reports an error for the [node].
   bool _hasConstantVerifierError(AstNode node) {
     var unitElement = currentUnit.unit.declaredElement;
diff --git a/pkg/analyzer/lib/src/services/available_declarations.dart b/pkg/analyzer/lib/src/services/available_declarations.dart
index 180e833..f1a916a 100644
--- a/pkg/analyzer/lib/src/services/available_declarations.dart
+++ b/pkg/analyzer/lib/src/services/available_declarations.dart
@@ -198,29 +198,34 @@
       _addKnownLibraries(dependencyLibraries);
     }
 
-    _Package package;
-    for (var candidatePackage in _packages) {
-      if (candidatePackage.contains(path)) {
-        package = candidatePackage;
-        break;
-      }
-    }
-
     var contextPathList = <String>[];
-    if (package != null) {
-      var containingFolder = package.folderInRootContaining(path);
-      if (containingFolder != null) {
-        for (var contextPath in _contextPathList) {
-          // `lib/` can see only libraries in `lib/`.
-          // `test/` can see libraries in `lib/` and in `test/`.
-          if (package.containsInLib(contextPath) ||
-              containingFolder.contains(contextPath)) {
-            contextPathList.add(contextPath);
-          }
+    if (!_analysisContext.workspace.isBazel) {
+      _Package package;
+      for (var candidatePackage in _packages) {
+        if (candidatePackage.contains(path)) {
+          package = candidatePackage;
+          break;
         }
       }
+
+      if (package != null) {
+        var containingFolder = package.folderInRootContaining(path);
+        if (containingFolder != null) {
+          for (var contextPath in _contextPathList) {
+            // `lib/` can see only libraries in `lib/`.
+            // `test/` can see libraries in `lib/` and in `test/`.
+            if (package.containsInLib(contextPath) ||
+                containingFolder.contains(contextPath)) {
+              contextPathList.add(contextPath);
+            }
+          }
+        }
+      } else {
+        // Not in a package, include all libraries of the context.
+        contextPathList = _contextPathList;
+      }
     } else {
-      // Not in a package, include all libraries of the context.
+      // In bazel workspaces, consider declarations from the entire context
       contextPathList = _contextPathList;
     }
 
diff --git a/pkg/analyzer/lib/src/summary/format.dart b/pkg/analyzer/lib/src/summary/format.dart
index f702e50..77fd089 100644
--- a/pkg/analyzer/lib/src/summary/format.dart
+++ b/pkg/analyzer/lib/src/summary/format.dart
@@ -1834,7 +1834,6 @@
   List<String> _definedTopLevelNames;
   List<String> _referencedNames;
   List<String> _subtypedNames;
-  UnlinkedUnitBuilder _unit;
   UnlinkedUnit2Builder _unit2;
 
   @override
@@ -1872,14 +1871,6 @@
   }
 
   @override
-  UnlinkedUnitBuilder get unit => _unit;
-
-  /// Unlinked information for the unit.
-  set unit(UnlinkedUnitBuilder value) {
-    this._unit = value;
-  }
-
-  @override
   UnlinkedUnit2Builder get unit2 => _unit2;
 
   /// Unlinked information for the unit.
@@ -1892,18 +1883,15 @@
       List<String> definedTopLevelNames,
       List<String> referencedNames,
       List<String> subtypedNames,
-      UnlinkedUnitBuilder unit,
       UnlinkedUnit2Builder unit2})
       : _definedClassMemberNames = definedClassMemberNames,
         _definedTopLevelNames = definedTopLevelNames,
         _referencedNames = referencedNames,
         _subtypedNames = subtypedNames,
-        _unit = unit,
         _unit2 = unit2;
 
   /// Flush [informative] data recursively.
   void flushInformative() {
-    _unit?.flushInformative();
     _unit2?.flushInformative();
   }
 
@@ -1917,8 +1905,6 @@
         signature.addString(x);
       }
     }
-    signature.addBool(this._unit != null);
-    this._unit?.collectApiSignature(signature);
     if (this._definedTopLevelNames == null) {
       signature.addInt(0);
     } else {
@@ -1957,7 +1943,6 @@
     fb.Offset offset_definedTopLevelNames;
     fb.Offset offset_referencedNames;
     fb.Offset offset_subtypedNames;
-    fb.Offset offset_unit;
     fb.Offset offset_unit2;
     if (!(_definedClassMemberNames == null ||
         _definedClassMemberNames.isEmpty)) {
@@ -1978,30 +1963,24 @@
       offset_subtypedNames = fbBuilder.writeList(
           _subtypedNames.map((b) => fbBuilder.writeString(b)).toList());
     }
-    if (_unit != null) {
-      offset_unit = _unit.finish(fbBuilder);
-    }
     if (_unit2 != null) {
       offset_unit2 = _unit2.finish(fbBuilder);
     }
     fbBuilder.startTable();
     if (offset_definedClassMemberNames != null) {
-      fbBuilder.addOffset(3, offset_definedClassMemberNames);
+      fbBuilder.addOffset(2, offset_definedClassMemberNames);
     }
     if (offset_definedTopLevelNames != null) {
-      fbBuilder.addOffset(2, offset_definedTopLevelNames);
+      fbBuilder.addOffset(1, offset_definedTopLevelNames);
     }
     if (offset_referencedNames != null) {
       fbBuilder.addOffset(0, offset_referencedNames);
     }
     if (offset_subtypedNames != null) {
-      fbBuilder.addOffset(4, offset_subtypedNames);
-    }
-    if (offset_unit != null) {
-      fbBuilder.addOffset(1, offset_unit);
+      fbBuilder.addOffset(3, offset_subtypedNames);
     }
     if (offset_unit2 != null) {
-      fbBuilder.addOffset(5, offset_unit2);
+      fbBuilder.addOffset(4, offset_unit2);
     }
     return fbBuilder.endTable();
   }
@@ -2035,14 +2014,13 @@
   List<String> _definedTopLevelNames;
   List<String> _referencedNames;
   List<String> _subtypedNames;
-  idl.UnlinkedUnit _unit;
   idl.UnlinkedUnit2 _unit2;
 
   @override
   List<String> get definedClassMemberNames {
     _definedClassMemberNames ??=
         const fb.ListReader<String>(const fb.StringReader())
-            .vTableGet(_bc, _bcOffset, 3, const <String>[]);
+            .vTableGet(_bc, _bcOffset, 2, const <String>[]);
     return _definedClassMemberNames;
   }
 
@@ -2050,7 +2028,7 @@
   List<String> get definedTopLevelNames {
     _definedTopLevelNames ??=
         const fb.ListReader<String>(const fb.StringReader())
-            .vTableGet(_bc, _bcOffset, 2, const <String>[]);
+            .vTableGet(_bc, _bcOffset, 1, const <String>[]);
     return _definedTopLevelNames;
   }
 
@@ -2064,19 +2042,13 @@
   @override
   List<String> get subtypedNames {
     _subtypedNames ??= const fb.ListReader<String>(const fb.StringReader())
-        .vTableGet(_bc, _bcOffset, 4, const <String>[]);
+        .vTableGet(_bc, _bcOffset, 3, const <String>[]);
     return _subtypedNames;
   }
 
   @override
-  idl.UnlinkedUnit get unit {
-    _unit ??= const _UnlinkedUnitReader().vTableGet(_bc, _bcOffset, 1, null);
-    return _unit;
-  }
-
-  @override
   idl.UnlinkedUnit2 get unit2 {
-    _unit2 ??= const _UnlinkedUnit2Reader().vTableGet(_bc, _bcOffset, 5, null);
+    _unit2 ??= const _UnlinkedUnit2Reader().vTableGet(_bc, _bcOffset, 4, null);
     return _unit2;
   }
 }
@@ -2093,7 +2065,6 @@
     if (referencedNames.isNotEmpty)
       _result["referencedNames"] = referencedNames;
     if (subtypedNames.isNotEmpty) _result["subtypedNames"] = subtypedNames;
-    if (unit != null) _result["unit"] = unit.toJson();
     if (unit2 != null) _result["unit2"] = unit2.toJson();
     return _result;
   }
@@ -2104,7 +2075,6 @@
         "definedTopLevelNames": definedTopLevelNames,
         "referencedNames": referencedNames,
         "subtypedNames": subtypedNames,
-        "unit": unit,
         "unit2": unit2,
       };
 
@@ -3675,80 +3645,6 @@
   String toString() => convert.json.encode(toJson());
 }
 
-class LinkedLibraryBuilder extends Object
-    with _LinkedLibraryMixin
-    implements idl.LinkedLibrary {
-  int _placeholder;
-
-  @override
-  int get placeholder => _placeholder ??= 0;
-
-  set placeholder(int value) {
-    assert(value == null || value >= 0);
-    this._placeholder = value;
-  }
-
-  LinkedLibraryBuilder({int placeholder}) : _placeholder = placeholder;
-
-  /// Flush [informative] data recursively.
-  void flushInformative() {}
-
-  /// Accumulate non-[informative] data into [signature].
-  void collectApiSignature(api_sig.ApiSignature signature) {
-    signature.addInt(this._placeholder ?? 0);
-  }
-
-  fb.Offset finish(fb.Builder fbBuilder) {
-    fbBuilder.startTable();
-    if (_placeholder != null && _placeholder != 0) {
-      fbBuilder.addUint32(0, _placeholder);
-    }
-    return fbBuilder.endTable();
-  }
-}
-
-class _LinkedLibraryReader extends fb.TableReader<_LinkedLibraryImpl> {
-  const _LinkedLibraryReader();
-
-  @override
-  _LinkedLibraryImpl createObject(fb.BufferContext bc, int offset) =>
-      new _LinkedLibraryImpl(bc, offset);
-}
-
-class _LinkedLibraryImpl extends Object
-    with _LinkedLibraryMixin
-    implements idl.LinkedLibrary {
-  final fb.BufferContext _bc;
-  final int _bcOffset;
-
-  _LinkedLibraryImpl(this._bc, this._bcOffset);
-
-  int _placeholder;
-
-  @override
-  int get placeholder {
-    _placeholder ??= const fb.Uint32Reader().vTableGet(_bc, _bcOffset, 0, 0);
-    return _placeholder;
-  }
-}
-
-abstract class _LinkedLibraryMixin implements idl.LinkedLibrary {
-  @override
-  Map<String, Object> toJson() {
-    Map<String, Object> _result = <String, Object>{};
-    if (placeholder != 0) _result["placeholder"] = placeholder;
-    return _result;
-  }
-
-  @override
-  Map<String, Object> toMap() => {
-        "placeholder": placeholder,
-      };
-
-  @override
-  String toString() => convert.json.encode(toJson());
-}
-
 class LinkedNodeBuilder extends Object
     with _LinkedNodeMixin
     implements idl.LinkedNode {
@@ -6110,6 +6006,12 @@
     return _variantField_28 ??= idl.UnlinkedTokenType.NOTHING;
   }
 
+  @override
+  idl.UnlinkedTokenType get typeParameter_variance {
+    assert(kind == idl.LinkedNodeKind.typeParameter);
+    return _variantField_28 ??= idl.UnlinkedTokenType.NOTHING;
+  }
+
   set assignmentExpression_operator(idl.UnlinkedTokenType value) {
     assert(kind == idl.LinkedNodeKind.assignmentExpression);
     _variantField_28 = value;
@@ -6135,6 +6037,11 @@
     _variantField_28 = value;
   }
 
+  set typeParameter_variance(idl.UnlinkedTokenType value) {
+    assert(kind == idl.LinkedNodeKind.typeParameter);
+    _variantField_28 = value;
+  }
+
   @override
   bool get booleanLiteral_value {
     assert(kind == idl.LinkedNodeKind.booleanLiteral);
@@ -7881,11 +7788,13 @@
   LinkedNodeBuilder.typeParameter({
     List<LinkedNodeBuilder> annotatedNode_metadata,
     LinkedNodeBuilder typeParameter_bound,
+    idl.UnlinkedTokenType typeParameter_variance,
     int informativeId,
     LinkedNodeTypeBuilder typeParameter_defaultType,
   })  : _kind = idl.LinkedNodeKind.typeParameter,
         _variantField_4 = annotatedNode_metadata,
         _variantField_6 = typeParameter_bound,
+        _variantField_28 = typeParameter_variance,
         _variantField_36 = informativeId,
         _variantField_23 = typeParameter_defaultType;
 
@@ -9917,6 +9826,9 @@
       signature.addInt(this.flags ?? 0);
       signature.addBool(this.typeParameter_defaultType != null);
       this.typeParameter_defaultType?.collectApiSignature(signature);
+      signature.addInt(this.typeParameter_variance == null
+          ? 0
+          : this.typeParameter_variance.index);
       signature.addString(this.name ?? '');
     } else if (kind == idl.LinkedNodeKind.typeParameterList) {
       signature.addInt(this.kind == null ? 0 : this.kind.index);
@@ -12008,6 +11920,14 @@
   }
 
   @override
+  idl.UnlinkedTokenType get typeParameter_variance {
+    assert(kind == idl.LinkedNodeKind.typeParameter);
+    _variantField_28 ??= const _UnlinkedTokenTypeReader()
+        .vTableGet(_bc, _bcOffset, 28, idl.UnlinkedTokenType.NOTHING);
+    return _variantField_28;
+  }
+
+  @override
   bool get booleanLiteral_value {
     assert(kind == idl.LinkedNodeKind.booleanLiteral);
     _variantField_27 ??=
@@ -13636,6 +13556,9 @@
             annotatedNode_metadata.map((_value) => _value.toJson()).toList();
       if (typeParameter_bound != null)
         _result["typeParameter_bound"] = typeParameter_bound.toJson();
+      if (typeParameter_variance != idl.UnlinkedTokenType.NOTHING)
+        _result["typeParameter_variance"] =
+            typeParameter_variance.toString().split('.')[1];
       if (informativeId != 0) _result["informativeId"] = informativeId;
       if (typeParameter_defaultType != null)
         _result["typeParameter_defaultType"] =
@@ -14887,6 +14810,7 @@
       return {
         "annotatedNode_metadata": annotatedNode_metadata,
         "typeParameter_bound": typeParameter_bound,
+        "typeParameter_variance": typeParameter_variance,
         "flags": flags,
         "informativeId": informativeId,
         "kind": kind,
@@ -16256,7 +16180,6 @@
   bool _isSynthetic;
   LinkedNodeBuilder _node;
   String _partUriStr;
-  UnlinkedTokensBuilder _tokens;
   String _uriStr;
 
   @override
@@ -16290,13 +16213,6 @@
   }
 
   @override
-  UnlinkedTokensBuilder get tokens => _tokens;
-
-  set tokens(UnlinkedTokensBuilder value) {
-    this._tokens = value;
-  }
-
-  @override
   String get uriStr => _uriStr ??= '';
 
   /// The absolute URI.
@@ -16309,26 +16225,21 @@
       bool isSynthetic,
       LinkedNodeBuilder node,
       String partUriStr,
-      UnlinkedTokensBuilder tokens,
       String uriStr})
       : _isNNBD = isNNBD,
         _isSynthetic = isSynthetic,
         _node = node,
         _partUriStr = partUriStr,
-        _tokens = tokens,
         _uriStr = uriStr;
 
   /// Flush [informative] data recursively.
   void flushInformative() {
     _node?.flushInformative();
-    _tokens?.flushInformative();
   }
 
   /// Accumulate non-[informative] data into [signature].
   void collectApiSignature(api_sig.ApiSignature signature) {
     signature.addString(this._uriStr ?? '');
-    signature.addBool(this._tokens != null);
-    this._tokens?.collectApiSignature(signature);
     signature.addBool(this._node != null);
     this._node?.collectApiSignature(signature);
     signature.addBool(this._isSynthetic == true);
@@ -16339,7 +16250,6 @@
   fb.Offset finish(fb.Builder fbBuilder) {
     fb.Offset offset_node;
     fb.Offset offset_partUriStr;
-    fb.Offset offset_tokens;
     fb.Offset offset_uriStr;
     if (_node != null) {
       offset_node = _node.finish(fbBuilder);
@@ -16347,27 +16257,21 @@
     if (_partUriStr != null) {
       offset_partUriStr = fbBuilder.writeString(_partUriStr);
     }
-    if (_tokens != null) {
-      offset_tokens = _tokens.finish(fbBuilder);
-    }
     if (_uriStr != null) {
       offset_uriStr = fbBuilder.writeString(_uriStr);
     }
     fbBuilder.startTable();
     if (_isNNBD == true) {
-      fbBuilder.addBool(4, true);
-    }
-    if (_isSynthetic == true) {
       fbBuilder.addBool(3, true);
     }
+    if (_isSynthetic == true) {
+      fbBuilder.addBool(2, true);
+    }
     if (offset_node != null) {
-      fbBuilder.addOffset(2, offset_node);
+      fbBuilder.addOffset(1, offset_node);
     }
     if (offset_partUriStr != null) {
-      fbBuilder.addOffset(5, offset_partUriStr);
-    }
-    if (offset_tokens != null) {
-      fbBuilder.addOffset(1, offset_tokens);
+      fbBuilder.addOffset(4, offset_partUriStr);
     }
     if (offset_uriStr != null) {
       fbBuilder.addOffset(0, offset_uriStr);
@@ -16396,41 +16300,33 @@
   bool _isSynthetic;
   idl.LinkedNode _node;
   String _partUriStr;
-  idl.UnlinkedTokens _tokens;
   String _uriStr;
 
   @override
   bool get isNNBD {
-    _isNNBD ??= const fb.BoolReader().vTableGet(_bc, _bcOffset, 4, false);
+    _isNNBD ??= const fb.BoolReader().vTableGet(_bc, _bcOffset, 3, false);
     return _isNNBD;
   }
 
   @override
   bool get isSynthetic {
-    _isSynthetic ??= const fb.BoolReader().vTableGet(_bc, _bcOffset, 3, false);
+    _isSynthetic ??= const fb.BoolReader().vTableGet(_bc, _bcOffset, 2, false);
     return _isSynthetic;
   }
 
   @override
   idl.LinkedNode get node {
-    _node ??= const _LinkedNodeReader().vTableGet(_bc, _bcOffset, 2, null);
+    _node ??= const _LinkedNodeReader().vTableGet(_bc, _bcOffset, 1, null);
     return _node;
   }
 
   @override
   String get partUriStr {
-    _partUriStr ??= const fb.StringReader().vTableGet(_bc, _bcOffset, 5, '');
+    _partUriStr ??= const fb.StringReader().vTableGet(_bc, _bcOffset, 4, '');
     return _partUriStr;
   }
 
   @override
-  idl.UnlinkedTokens get tokens {
-    _tokens ??=
-        const _UnlinkedTokensReader().vTableGet(_bc, _bcOffset, 1, null);
-    return _tokens;
-  }
-
-  @override
   String get uriStr {
     _uriStr ??= const fb.StringReader().vTableGet(_bc, _bcOffset, 0, '');
     return _uriStr;
@@ -16445,7 +16341,6 @@
     if (isSynthetic != false) _result["isSynthetic"] = isSynthetic;
     if (node != null) _result["node"] = node.toJson();
     if (partUriStr != '') _result["partUriStr"] = partUriStr;
-    if (tokens != null) _result["tokens"] = tokens.toJson();
     if (uriStr != '') _result["uriStr"] = uriStr;
     return _result;
   }
@@ -16456,7 +16351,6 @@
         "isSynthetic": isSynthetic,
         "node": node,
         "partUriStr": partUriStr,
-        "tokens": tokens,
         "uriStr": uriStr,
       };
 
@@ -16468,12 +16362,6 @@
     with _PackageBundleMixin
     implements idl.PackageBundle {
   LinkedNodeBundleBuilder _bundle2;
-  int _majorVersion;
-  int _minorVersion;
-
-  @override
-  Null get apiSignature =>
-      throw new UnimplementedError('attempt to access deprecated field');
 
   @override
   LinkedNodeBundleBuilder get bundle2 => _bundle2;
@@ -16483,55 +16371,7 @@
     this._bundle2 = value;
   }
 
-  @override
-  Null get dependencies =>
-      throw new UnimplementedError('attempt to access deprecated field');
-
-  @override
-  Null get linkedLibraries =>
-      throw new UnimplementedError('attempt to access deprecated field');
-
-  @override
-  Null get linkedLibraryUris =>
-      throw new UnimplementedError('attempt to access deprecated field');
-
-  @override
-  int get majorVersion => _majorVersion ??= 0;
-
-  /// Major version of the summary format.  See
-  /// [PackageBundleAssembler.currentMajorVersion].
-  set majorVersion(int value) {
-    assert(value == null || value >= 0);
-    this._majorVersion = value;
-  }
-
-  @override
-  int get minorVersion => _minorVersion ??= 0;
-
-  /// Minor version of the summary format.  See
-  /// [PackageBundleAssembler.currentMinorVersion].
-  set minorVersion(int value) {
-    assert(value == null || value >= 0);
-    this._minorVersion = value;
-  }
-
-  @override
-  Null get unlinkedUnitHashes =>
-      throw new UnimplementedError('attempt to access deprecated field');
-
-  @override
-  Null get unlinkedUnits =>
-      throw new UnimplementedError('attempt to access deprecated field');
-
-  @override
-  Null get unlinkedUnitUris =>
-      throw new UnimplementedError('attempt to access deprecated field');
-
-  PackageBundleBuilder(
-      {LinkedNodeBundleBuilder bundle2, int majorVersion, int minorVersion})
-      : _bundle2 = bundle2,
-        _majorVersion = majorVersion,
-        _minorVersion = minorVersion;
+  PackageBundleBuilder({LinkedNodeBundleBuilder bundle2}) : _bundle2 = bundle2;
 
   /// Flush [informative] data recursively.
   void flushInformative() {
@@ -16540,8 +16380,6 @@
 
   /// Accumulate non-[informative] data into [signature].
   void collectApiSignature(api_sig.ApiSignature signature) {
-    signature.addInt(this._majorVersion ?? 0);
-    signature.addInt(this._minorVersion ?? 0);
     signature.addBool(this._bundle2 != null);
     this._bundle2?.collectApiSignature(signature);
   }
@@ -16558,13 +16396,7 @@
     }
     fbBuilder.startTable();
     if (offset_bundle2 != null) {
-      fbBuilder.addOffset(9, offset_bundle2);
-    }
-    if (_majorVersion != null && _majorVersion != 0) {
-      fbBuilder.addUint32(5, _majorVersion);
-    }
-    if (_minorVersion != null && _minorVersion != 0) {
-      fbBuilder.addUint32(6, _minorVersion);
+      fbBuilder.addOffset(0, offset_bundle2);
     }
     return fbBuilder.endTable();
   }
@@ -16592,55 +16424,13 @@
   _PackageBundleImpl(this._bc, this._bcOffset);
 
   idl.LinkedNodeBundle _bundle2;
-  int _majorVersion;
-  int _minorVersion;
-
-  @override
-  Null get apiSignature =>
-      throw new UnimplementedError('attempt to access deprecated field');
 
   @override
   idl.LinkedNodeBundle get bundle2 {
     _bundle2 ??=
-        const _LinkedNodeBundleReader().vTableGet(_bc, _bcOffset, 9, null);
+        const _LinkedNodeBundleReader().vTableGet(_bc, _bcOffset, 0, null);
     return _bundle2;
   }
-
-  @override
-  Null get dependencies =>
-      throw new UnimplementedError('attempt to access deprecated field');
-
-  @override
-  Null get linkedLibraries =>
-      throw new UnimplementedError('attempt to access deprecated field');
-
-  @override
-  Null get linkedLibraryUris =>
-      throw new UnimplementedError('attempt to access deprecated field');
-
-  @override
-  int get majorVersion {
-    _majorVersion ??= const fb.Uint32Reader().vTableGet(_bc, _bcOffset, 5, 0);
-    return _majorVersion;
-  }
-
-  @override
-  int get minorVersion {
-    _minorVersion ??= const fb.Uint32Reader().vTableGet(_bc, _bcOffset, 6, 0);
-    return _minorVersion;
-  }
-
-  @override
-  Null get unlinkedUnitHashes =>
-      throw new UnimplementedError('attempt to access deprecated field');
-
-  @override
-  Null get unlinkedUnits =>
-      throw new UnimplementedError('attempt to access deprecated field');
-
-  @override
-  Null get unlinkedUnitUris =>
-      throw new UnimplementedError('attempt to access deprecated field');
 }
 
 abstract class _PackageBundleMixin implements idl.PackageBundle {
@@ -16648,92 +16438,12 @@
   Map<String, Object> toJson() {
     Map<String, Object> _result = <String, Object>{};
     if (bundle2 != null) _result["bundle2"] = bundle2.toJson();
-    if (majorVersion != 0) _result["majorVersion"] = majorVersion;
-    if (minorVersion != 0) _result["minorVersion"] = minorVersion;
     return _result;
   }
 
   @override
   Map<String, Object> toMap() => {
         "bundle2": bundle2,
-        "majorVersion": majorVersion,
-        "minorVersion": minorVersion,
-      };
-
-  @override
-  String toString() => convert.json.encode(toJson());
-}
-
-class PackageDependencyInfoBuilder extends Object
-    with _PackageDependencyInfoMixin
-    implements idl.PackageDependencyInfo {
-  int _placeholder;
-
-  @override
-  int get placeholder => _placeholder ??= 0;
-
-  set placeholder(int value) {
-    assert(value == null || value >= 0);
-    this._placeholder = value;
-  }
-
-  PackageDependencyInfoBuilder({int placeholder}) : _placeholder = placeholder;
-
-  /// Flush [informative] data recursively.
-  void flushInformative() {}
-
-  /// Accumulate non-[informative] data into [signature].
-  void collectApiSignature(api_sig.ApiSignature signature) {
-    signature.addInt(this._placeholder ?? 0);
-  }
-
-  fb.Offset finish(fb.Builder fbBuilder) {
-    fbBuilder.startTable();
-    if (_placeholder != null && _placeholder != 0) {
-      fbBuilder.addUint32(0, _placeholder);
-    }
-    return fbBuilder.endTable();
-  }
-}
-
-class _PackageDependencyInfoReader
-    extends fb.TableReader<_PackageDependencyInfoImpl> {
-  const _PackageDependencyInfoReader();
-
-  @override
-  _PackageDependencyInfoImpl createObject(fb.BufferContext bc, int offset) =>
-      new _PackageDependencyInfoImpl(bc, offset);
-}
-
-class _PackageDependencyInfoImpl extends Object
-    with _PackageDependencyInfoMixin
-    implements idl.PackageDependencyInfo {
-  final fb.BufferContext _bc;
-  final int _bcOffset;
-
-  _PackageDependencyInfoImpl(this._bc, this._bcOffset);
-
-  int _placeholder;
-
-  @override
-  int get placeholder {
-    _placeholder ??= const fb.Uint32Reader().vTableGet(_bc, _bcOffset, 0, 0);
-    return _placeholder;
-  }
-}
-
-abstract class _PackageDependencyInfoMixin
-    implements idl.PackageDependencyInfo {
-  @override
-  Map<String, Object> toJson() {
-    Map<String, Object> _result = <String, Object>{};
-    if (placeholder != 0) _result["placeholder"] = placeholder;
-    return _result;
-  }
-
-  @override
-  Map<String, Object> toMap() => {
-        "placeholder": placeholder,
       };
 
   @override
@@ -18347,154 +18057,6 @@
   String toString() => convert.json.encode(toJson());
 }
 
-class UnlinkedTokensBuilder extends Object
-    with _UnlinkedTokensMixin
-    implements idl.UnlinkedTokens {
-  int _placeholder;
-
-  @override
-  int get placeholder => _placeholder ??= 0;
-
-  set placeholder(int value) {
-    assert(value == null || value >= 0);
-    this._placeholder = value;
-  }
-
-  UnlinkedTokensBuilder({int placeholder}) : _placeholder = placeholder;
-
-  /// Flush [informative] data recursively.
-  void flushInformative() {}
-
-  /// Accumulate non-[informative] data into [signature].
-  void collectApiSignature(api_sig.ApiSignature signature) {
-    signature.addInt(this._placeholder ?? 0);
-  }
-
-  fb.Offset finish(fb.Builder fbBuilder) {
-    fbBuilder.startTable();
-    if (_placeholder != null && _placeholder != 0) {
-      fbBuilder.addUint32(0, _placeholder);
-    }
-    return fbBuilder.endTable();
-  }
-}
-
-class _UnlinkedTokensReader extends fb.TableReader<_UnlinkedTokensImpl> {
-  const _UnlinkedTokensReader();
-
-  @override
-  _UnlinkedTokensImpl createObject(fb.BufferContext bc, int offset) =>
-      new _UnlinkedTokensImpl(bc, offset);
-}
-
-class _UnlinkedTokensImpl extends Object
-    with _UnlinkedTokensMixin
-    implements idl.UnlinkedTokens {
-  final fb.BufferContext _bc;
-  final int _bcOffset;
-
-  _UnlinkedTokensImpl(this._bc, this._bcOffset);
-
-  int _placeholder;
-
-  @override
-  int get placeholder {
-    _placeholder ??= const fb.Uint32Reader().vTableGet(_bc, _bcOffset, 0, 0);
-    return _placeholder;
-  }
-}
-
-abstract class _UnlinkedTokensMixin implements idl.UnlinkedTokens {
-  @override
-  Map<String, Object> toJson() {
-    Map<String, Object> _result = <String, Object>{};
-    if (placeholder != 0) _result["placeholder"] = placeholder;
-    return _result;
-  }
-
-  @override
-  Map<String, Object> toMap() => {
-        "placeholder": placeholder,
-      };
-
-  @override
-  String toString() => convert.json.encode(toJson());
-}
-
-class UnlinkedUnitBuilder extends Object
-    with _UnlinkedUnitMixin
-    implements idl.UnlinkedUnit {
-  int _placeholder;
-
-  @override
-  int get placeholder => _placeholder ??= 0;
-
-  set placeholder(int value) {
-    assert(value == null || value >= 0);
-    this._placeholder = value;
-  }
-
-  UnlinkedUnitBuilder({int placeholder}) : _placeholder = placeholder;
-
-  /// Flush [informative] data recursively.
-  void flushInformative() {}
-
-  /// Accumulate non-[informative] data into [signature].
-  void collectApiSignature(api_sig.ApiSignature signature) {
-    signature.addInt(this._placeholder ?? 0);
-  }
-
-  fb.Offset finish(fb.Builder fbBuilder) {
-    fbBuilder.startTable();
-    if (_placeholder != null && _placeholder != 0) {
-      fbBuilder.addUint32(0, _placeholder);
-    }
-    return fbBuilder.endTable();
-  }
-}
-
-class _UnlinkedUnitReader extends fb.TableReader<_UnlinkedUnitImpl> {
-  const _UnlinkedUnitReader();
-
-  @override
-  _UnlinkedUnitImpl createObject(fb.BufferContext bc, int offset) =>
-      new _UnlinkedUnitImpl(bc, offset);
-}
-
-class _UnlinkedUnitImpl extends Object
-    with _UnlinkedUnitMixin
-    implements idl.UnlinkedUnit {
-  final fb.BufferContext _bc;
-  final int _bcOffset;
-
-  _UnlinkedUnitImpl(this._bc, this._bcOffset);
-
-  int _placeholder;
-
-  @override
-  int get placeholder {
-    _placeholder ??= const fb.Uint32Reader().vTableGet(_bc, _bcOffset, 0, 0);
-    return _placeholder;
-  }
-}
-
-abstract class _UnlinkedUnitMixin implements idl.UnlinkedUnit {
-  @override
-  Map<String, Object> toJson() {
-    Map<String, Object> _result = <String, Object>{};
-    if (placeholder != 0) _result["placeholder"] = placeholder;
-    return _result;
-  }
-
-  @override
-  Map<String, Object> toMap() => {
-        "placeholder": placeholder,
-      };
-
-  @override
-  String toString() => convert.json.encode(toJson());
-}
-
 class UnlinkedUnit2Builder extends Object
     with _UnlinkedUnit2Mixin
     implements idl.UnlinkedUnit2 {
diff --git a/pkg/analyzer/lib/src/summary/format.fbs b/pkg/analyzer/lib/src/summary/format.fbs
index f65b42b..be47572 100644
--- a/pkg/analyzer/lib/src/summary/format.fbs
+++ b/pkg/analyzer/lib/src/summary/format.fbs
@@ -442,7 +442,7 @@
   overrideConflictParameterType
 }
 
-/// TODO(scheglov) document
+/// Enum of token types, corresponding to AST token types.
 enum UnlinkedTokenType : byte {
   NOTHING,
 
@@ -724,7 +724,11 @@
 
   WITH,
 
-  YIELD
+  YIELD,
+
+  INOUT,
+
+  OUT
 }
 
 /// Information about the context of an exception in analysis driver.
@@ -890,23 +894,20 @@
 /// Information about an unlinked unit.
 table AnalysisDriverUnlinkedUnit {
   /// List of class member names defined by the unit.
-  definedClassMemberNames:[string] (id: 3);
+  definedClassMemberNames:[string] (id: 2);
 
   /// List of top-level names defined by the unit.
-  definedTopLevelNames:[string] (id: 2);
+  definedTopLevelNames:[string] (id: 1);
 
   /// List of external names referenced by the unit.
   referencedNames:[string] (id: 0);
 
   /// List of names which are used in `extends`, `with` or `implements` clauses
   /// in the file. Import prefixes and type arguments are not included.
-  subtypedNames:[string] (id: 4);
+  subtypedNames:[string] (id: 3);
 
   /// Unlinked information for the unit.
-  unit:UnlinkedUnit (id: 1);
-
-  /// Unlinked information for the unit.
-  unit2:UnlinkedUnit2 (id: 5);
+  unit2:UnlinkedUnit2 (id: 4);
 }
 
 /// Information about a single declaration.
@@ -1033,11 +1034,6 @@
   templateValues:[string] (id: 1);
 }
 
-/// TODO(scheglov) Remove it.
-table LinkedLibrary {
-  placeholder:uint (id: 0);
-}
-
 /// Information about a linked AST node.
 table LinkedNode {
   /// The explicit or inferred return type of a function typed node.
@@ -1205,17 +1201,15 @@
 
 /// Information about a single library in a [LinkedNodeLibrary].
 table LinkedNodeUnit {
-  isNNBD:bool (id: 4);
+  isNNBD:bool (id: 3);
 
-  isSynthetic:bool (id: 3);
+  isSynthetic:bool (id: 2);
 
-  node:LinkedNode (id: 2);
+  node:LinkedNode (id: 1);
 
   /// If the unit is a part, the URI specified in the `part` directive.
   /// Otherwise empty.
-  partUriStr:string (id: 5);
-
-  tokens:UnlinkedTokens (id: 1);
+  partUriStr:string (id: 4);
 
   /// The absolute URI.
   uriStr:string (id: 0);
@@ -1223,46 +1217,8 @@
 
 /// Summary information about a package.
 table PackageBundle {
-  /// MD5 hash of the non-informative fields of the [PackageBundle] (not
-  /// including this one).  This can be used to identify when the API of a
-  /// package may have changed.
-  apiSignature:string (id: 7, deprecated);
-
   /// The version 2 of the summary.
-  bundle2:LinkedNodeBundle (id: 9);
-
-  /// Information about the packages this package depends on, if known.
-  dependencies:[PackageDependencyInfo] (id: 8, deprecated);
-
-  /// Linked libraries.
-  linkedLibraries:[LinkedLibrary] (id: 0, deprecated);
-
-  /// The list of URIs of items in [linkedLibraries], e.g. `dart:core` or
-  /// `package:foo/bar.dart`.
-  linkedLibraryUris:[string] (id: 1, deprecated);
-
-  /// Major version of the summary format.  See
-  /// [PackageBundleAssembler.currentMajorVersion].
-  majorVersion:uint (id: 5);
-
-  /// Minor version of the summary format.  See
-  /// [PackageBundleAssembler.currentMinorVersion].
-  minorVersion:uint (id: 6);
-
-  /// List of MD5 hashes of the files listed in [unlinkedUnitUris].  Each hash
-  /// is encoded as a hexadecimal string using lower case letters.
-  unlinkedUnitHashes:[string] (id: 4, deprecated);
-
-  /// Unlinked information for the compilation units constituting the package.
-  unlinkedUnits:[UnlinkedUnit] (id: 2, deprecated);
-
-  /// The list of URIs of items in [unlinkedUnits], e.g. `dart:core/bool.dart`.
-  unlinkedUnitUris:[string] (id: 3, deprecated);
-}
-
-/// TODO(scheglov) Remove it.
-table PackageDependencyInfo {
-  placeholder:uint (id: 0);
+  bundle2:LinkedNodeBundle (id: 0);
 }
 
 /// Summary information about a top-level type inference error.
@@ -1307,16 +1263,6 @@
   kind:LinkedNodeKind (id: 0);
 }
 
-/// TODO(scheglov) Remove it.
-table UnlinkedTokens {
-  placeholder:uint (id: 0);
-}
-
-/// TODO(scheglov) Remove it.
-table UnlinkedUnit {
-  placeholder:uint (id: 0);
-}
-
 /// Unlinked summary information about a compilation unit.
 table UnlinkedUnit2 {
   /// The MD5 hash signature of the API portion of this unit. It depends on all
diff --git a/pkg/analyzer/lib/src/summary/idl.dart b/pkg/analyzer/lib/src/summary/idl.dart
index d6a9a31..a7259a1 100644
--- a/pkg/analyzer/lib/src/summary/idl.dart
+++ b/pkg/analyzer/lib/src/summary/idl.dart
@@ -229,11 +229,11 @@
       generated.readAnalysisDriverUnlinkedUnit(buffer);
 
   /// List of class member names defined by the unit.
-  @Id(3)
+  @Id(2)
   List<String> get definedClassMemberNames;
 
   /// List of top-level names defined by the unit.
-  @Id(2)
+  @Id(1)
   List<String> get definedTopLevelNames;
 
   /// List of external names referenced by the unit.
@@ -242,15 +242,11 @@
 
   /// List of names which are used in `extends`, `with` or `implements` clauses
   /// in the file. Import prefixes and type arguments are not included.
-  @Id(4)
+  @Id(3)
   List<String> get subtypedNames;
 
   /// Unlinked information for the unit.
-  @Id(1)
-  UnlinkedUnit get unit;
-
-  /// Unlinked information for the unit.
-  @Id(5)
+  @Id(4)
   UnlinkedUnit2 get unit2;
 }
 
@@ -552,12 +548,6 @@
   unit
 }
 
-/// TODO(scheglov) Remove it.
-abstract class LinkedLibrary extends base.SummaryClass {
-  @Id(0)
-  int get placeholder;
-}
-
 /// Information about a linked AST node.
 @Variant('kind')
 abstract class LinkedNode extends base.SummaryClass {
@@ -1456,6 +1446,9 @@
   @VariantId(23, variant: LinkedNodeKind.typeParameter)
   LinkedNodeType get typeParameter_defaultType;
 
+  @VariantId(28, variant: LinkedNodeKind.typeParameter)
+  UnlinkedTokenType get typeParameter_variance;
+
   @VariantId(2, variant: LinkedNodeKind.typeParameterList)
   List<LinkedNode> get typeParameterList_typeParameters;
 
@@ -1516,7 +1509,6 @@
 abstract class LinkedNodeBundle extends base.SummaryClass {
   factory LinkedNodeBundle.fromBuffer(List<int> buffer) =>
       generated.readLinkedNodeBundle(buffer);
-
   @Id(1)
   List<LinkedNodeLibrary> get libraries;
 
@@ -1770,23 +1762,20 @@
 
 /// Information about a single library in a [LinkedNodeLibrary].
 abstract class LinkedNodeUnit extends base.SummaryClass {
-  @Id(4)
+  @Id(3)
   bool get isNNBD;
 
-  @Id(3)
+  @Id(2)
   bool get isSynthetic;
 
-  @Id(2)
+  @Id(1)
   LinkedNode get node;
 
   /// If the unit is a part, the URI specified in the `part` directive.
   /// Otherwise empty.
-  @Id(5)
+  @Id(4)
   String get partUriStr;
 
-  @Id(1)
-  UnlinkedTokens get tokens;
-
   /// The absolute URI.
   @Id(0)
   String get uriStr;
@@ -1798,66 +1787,9 @@
   factory PackageBundle.fromBuffer(List<int> buffer) =>
       generated.readPackageBundle(buffer);
 
-  /// MD5 hash of the non-informative fields of the [PackageBundle] (not
-  /// including this one).  This can be used to identify when the API of a
-  /// package may have changed.
-  @Id(7)
-  @deprecated
-  String get apiSignature;
-
   /// The version 2 of the summary.
-  @Id(9)
+  @Id(0)
   LinkedNodeBundle get bundle2;
-
-  /// Information about the packages this package depends on, if known.
-  @Id(8)
-  @informative
-  @deprecated
-  List<PackageDependencyInfo> get dependencies;
-
-  /// Linked libraries.
-  @Id(0)
-  @deprecated
-  List<LinkedLibrary> get linkedLibraries;
-
-  /// The list of URIs of items in [linkedLibraries], e.g. `dart:core` or
-  /// `package:foo/bar.dart`.
-  @Id(1)
-  @deprecated
-  List<String> get linkedLibraryUris;
-
-  /// Major version of the summary format.  See
-  /// [PackageBundleAssembler.currentMajorVersion].
-  @Id(5)
-  int get majorVersion;
-
-  /// Minor version of the summary format.  See
-  /// [PackageBundleAssembler.currentMinorVersion].
-  @Id(6)
-  int get minorVersion;
-
-  /// List of MD5 hashes of the files listed in [unlinkedUnitUris].  Each hash
-  /// is encoded as a hexadecimal string using lower case letters.
-  @Id(4)
-  @deprecated
-  @informative
-  List<String> get unlinkedUnitHashes;
-
-  /// Unlinked information for the compilation units constituting the package.
-  @Id(2)
-  @deprecated
-  List<UnlinkedUnit> get unlinkedUnits;
-
-  /// The list of URIs of items in [unlinkedUnits], e.g. `dart:core/bool.dart`.
-  @Id(3)
-  @deprecated
-  List<String> get unlinkedUnitUris;
-}
-
-/// TODO(scheglov) Remove it.
-abstract class PackageDependencyInfo extends base.SummaryClass {
-  @Id(0)
-  int get placeholder;
 }
 
 /// Summary information about a top-level type inference error.
@@ -2015,13 +1947,7 @@
   int get nameOffset;
 }
 
-/// TODO(scheglov) Remove it.
-abstract class UnlinkedTokens extends base.SummaryClass {
-  @Id(0)
-  int get placeholder;
-}
-
-/// TODO(scheglov) document
+/// Enum of token types, corresponding to AST token types.
 enum UnlinkedTokenType {
   NOTHING,
   ABSTRACT,
@@ -2164,12 +2090,8 @@
   WHILE,
   WITH,
   YIELD,
-}
-
-/// TODO(scheglov) Remove it.
-abstract class UnlinkedUnit extends base.SummaryClass {
-  @Id(0)
-  int get placeholder;
+  INOUT,
+  OUT,
 }
 
 /// Unlinked summary information about a compilation unit.
diff --git a/pkg/analyzer/lib/src/summary/summarize_elements.dart b/pkg/analyzer/lib/src/summary/summarize_elements.dart
index 95911cd..1228ab8 100644
--- a/pkg/analyzer/lib/src/summary/summarize_elements.dart
+++ b/pkg/analyzer/lib/src/summary/summarize_elements.dart
@@ -3,40 +3,19 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/src/summary/format.dart';
-import 'package:analyzer/src/summary/idl.dart';
 
 /**
  * Object that gathers information uses it to assemble a new
  * [PackageBundleBuilder].
  */
 class PackageBundleAssembler {
-  /**
-   * Value that will be stored in [PackageBundle.majorVersion] for any summaries
-   * created by this code.  When making a breaking change to the summary format,
-   * this value should be incremented by 1 and [currentMinorVersion] should be
-   * reset to zero.
-   */
-  static const int currentMajorVersion = 1;
-
-  /**
-   * Value that will be stored in [PackageBundle.minorVersion] for any summaries
-   * created by this code.  When making a non-breaking change to the summary
-   * format that clients might need to be aware of (such as adding a kind of
-   * data that was previously not summarized), this value should be incremented
-   * by 1.
-   */
-  static const int currentMinorVersion = 1;
-
   LinkedNodeBundleBuilder _bundle2;
 
   /**
    * Assemble a new [PackageBundleBuilder] using the gathered information.
    */
   PackageBundleBuilder assemble() {
-    return new PackageBundleBuilder(
-        majorVersion: currentMajorVersion,
-        minorVersion: currentMinorVersion,
-        bundle2: _bundle2);
+    return new PackageBundleBuilder(bundle2: _bundle2);
   }
 
   void setBundle2(LinkedNodeBundleBuilder bundle2) {
diff --git a/pkg/analyzer/lib/src/summary/summary_sdk.dart b/pkg/analyzer/lib/src/summary/summary_sdk.dart
index 9cf52b7..f5be007 100644
--- a/pkg/analyzer/lib/src/summary/summary_sdk.dart
+++ b/pkg/analyzer/lib/src/summary/summary_sdk.dart
@@ -51,11 +51,13 @@
   @override
   AnalysisContext get context {
     if (_analysisContext == null) {
-      AnalysisOptionsImpl analysisOptions = new AnalysisOptionsImpl();
-      _analysisContext = new SdkAnalysisContext(analysisOptions);
-      SourceFactory factory = new SourceFactory(
-          [new DartUriResolver(this)], null, resourceProvider);
-      _analysisContext.sourceFactory = factory;
+      var analysisOptions = AnalysisOptionsImpl();
+      var factory = SourceFactory(
+        [DartUriResolver(this)],
+        null,
+        resourceProvider,
+      );
+      _analysisContext = new SdkAnalysisContext(analysisOptions, factory);
     }
     return _analysisContext;
   }
diff --git a/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart b/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
index 5677f4b9..9774971 100644
--- a/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
+++ b/pkg/analyzer/lib/src/summary2/ast_binary_reader.dart
@@ -8,6 +8,7 @@
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/dart/ast/ast.dart';
+import 'package:analyzer/src/dart/ast/ast_factory.dart';
 import 'package:analyzer/src/dart/element/member.dart';
 import 'package:analyzer/src/dart/element/type_algebra.dart';
 import 'package:analyzer/src/generated/testing/ast_test_factory.dart';
@@ -93,6 +94,13 @@
     return def;
   }
 
+  Token _varianceKeyword(LinkedNode data) {
+    if (data.typeParameter_variance != UnlinkedTokenType.NOTHING) {
+      return _Tokens.fromType(data.typeParameter_variance);
+    }
+    return null;
+  }
+
   Element _elementOfComponents(
     int rawElementIndex,
     LinkedNodeTypeSubstitution substitutionNode,
@@ -1572,13 +1580,15 @@
   }
 
   TypeParameter _read_typeParameter(LinkedNode data) {
-    var node = astFactory.typeParameter(
-      _readDocumentationComment(data),
-      _readNodeListLazy(data.annotatedNode_metadata),
-      _declaredIdentifier(data),
-      _Tokens.EXTENDS,
-      _readNodeLazy(data.typeParameter_bound),
-    );
+    // TODO (kallentu) : Clean up AstFactoryImpl casting once variance is
+    // added to the interface.
+    var node = (astFactory as AstFactoryImpl).typeParameter2(
+        comment: _readDocumentationComment(data),
+        metadata: _readNodeListLazy(data.annotatedNode_metadata),
+        name: _declaredIdentifier(data),
+        extendsKeyword: _Tokens.EXTENDS,
+        bound: _readNodeLazy(data.typeParameter_bound),
+        varianceKeyword: _varianceKeyword(data));
     LazyTypeParameter.setData(node, data);
     return node;
   }
diff --git a/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart b/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart
index a1cb51c..37aa5f7 100644
--- a/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart
+++ b/pkg/analyzer/lib/src/summary2/ast_binary_writer.dart
@@ -1354,6 +1354,7 @@
     var builder = LinkedNodeBuilder.typeParameter(
       typeParameter_bound: node.bound?.accept(this),
       typeParameter_defaultType: _writeType(LazyAst.getDefaultType(node)),
+      typeParameter_variance: _getVarianceToken(node),
       informativeId: getInformativeId(node),
     );
     builder.name = node.name.name;
@@ -1678,6 +1679,15 @@
     return _linkingContext.writeType(type);
   }
 
+  UnlinkedTokenType _getVarianceToken(TypeParameter parameter) {
+    // TODO (kallentu) : Clean up TypeParameterImpl casting once variance is
+    // added to the interface.
+    var parameterImpl = parameter as TypeParameterImpl;
+    return parameterImpl.varianceKeyword != null
+        ? TokensWriter.astToBinaryTokenType(parameterImpl.varianceKeyword.type)
+        : null;
+  }
+
   /// Return `true` if the expression might be successfully serialized.
   ///
   /// This does not mean that the expression is constant, it just means that
diff --git a/pkg/analyzer/lib/src/summary2/ast_resolver.dart b/pkg/analyzer/lib/src/summary2/ast_resolver.dart
index fc4908c..54a07fc 100644
--- a/pkg/analyzer/lib/src/summary2/ast_resolver.dart
+++ b/pkg/analyzer/lib/src/summary2/ast_resolver.dart
@@ -5,6 +5,7 @@
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/error/listener.dart';
+import 'package:analyzer/src/dart/resolver/flow_analysis_visitor.dart';
 import 'package:analyzer/src/dart/resolver/resolution_visitor.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/summary2/link.dart';
@@ -15,7 +16,17 @@
   final CompilationUnitElement _unitElement;
   final Scope _nameScope;
 
-  AstResolver(this._linker, this._unitElement, this._nameScope);
+  /// This field is set if the library is non-nullable by default.
+  FlowAnalysisHelper flowAnalysis;
+
+  AstResolver(this._linker, this._unitElement, this._nameScope) {
+    if (_unitElement.library.isNonNullableByDefault) {
+      flowAnalysis = FlowAnalysisHelper(
+        _unitElement.library.typeSystem,
+        false,
+      );
+    }
+  }
 
   void resolve(
     AstNode node,
@@ -56,6 +67,7 @@
       nameScope: _nameScope,
       propagateTypes: false,
       reportConstEvaluationErrors: false,
+      flowAnalysisHelper: flowAnalysis,
     );
     resolverVisitor.prepareEnclosingDeclarations(
       enclosingClassElement: enclosingClassElement,
diff --git a/pkg/analyzer/lib/src/summary2/ast_text_printer.dart b/pkg/analyzer/lib/src/summary2/ast_text_printer.dart
index 426c86f..6b19881 100644
--- a/pkg/analyzer/lib/src/summary2/ast_text_printer.dart
+++ b/pkg/analyzer/lib/src/summary2/ast_text_printer.dart
@@ -6,6 +6,7 @@
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/source/line_info.dart';
+import 'package:analyzer/src/dart/ast/ast.dart';
 
 /// AST visitor that prints tokens into their original positions.
 class AstTextPrinter extends ThrowingAstVisitor<void> {
@@ -931,6 +932,9 @@
   @override
   void visitTypeParameter(TypeParameter node) {
     _declaration(node);
+    // TODO (kallentu) : Clean up TypeParameterImpl casting once variance is
+    // added to the interface.
+    _token((node as TypeParameterImpl).varianceKeyword);
     node.name?.accept(this);
     _token(node.extendsKeyword);
     node.bound?.accept(this);
diff --git a/pkg/analyzer/lib/src/summary2/default_types_builder.dart b/pkg/analyzer/lib/src/summary2/default_types_builder.dart
index 18a4fcb3..888b899 100644
--- a/pkg/analyzer/lib/src/summary2/default_types_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/default_types_builder.dart
@@ -16,7 +16,7 @@
 import 'package:kernel/util/graph.dart' show Graph, computeStrongComponents;
 
 class DefaultTypesBuilder {
-  final Dart2TypeSystem typeSystem;
+  final TypeSystemImpl typeSystem;
 
   DefaultTypesBuilder(this.typeSystem);
 
diff --git a/pkg/analyzer/lib/src/summary2/link.dart b/pkg/analyzer/lib/src/summary2/link.dart
index 8e91cf7..7ad79b3 100644
--- a/pkg/analyzer/lib/src/summary2/link.dart
+++ b/pkg/analyzer/lib/src/summary2/link.dart
@@ -6,7 +6,6 @@
 import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/ast/ast.dart' show CompilationUnit;
 import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
-import 'package:analyzer/src/dart/element/type_provider.dart';
 import 'package:analyzer/src/generated/constant.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/resolver.dart';
@@ -71,7 +70,7 @@
 
   TypeProvider get typeProvider => analysisContext.typeProvider;
 
-  Dart2TypeSystem get typeSystem => analysisContext.typeSystem;
+  TypeSystemImpl get typeSystem => analysisContext.typeSystem;
 
   void link(List<LinkInputLibrary> inputLibraries) {
     for (var inputLibrary in inputLibraries) {
@@ -206,15 +205,15 @@
 
   void _createTypeSystem() {
     if (typeProvider != null) {
-      inheritance = InheritanceManager3(typeSystem);
+      inheritance = InheritanceManager3();
       return;
     }
 
     var coreLib = elementFactory.libraryOfUri('dart:core');
     var asyncLib = elementFactory.libraryOfUri('dart:async');
-    analysisContext.typeProvider = TypeProviderImpl(coreLib, asyncLib);
+    elementFactory.createTypeProviders(coreLib, asyncLib);
 
-    inheritance = InheritanceManager3(typeSystem);
+    inheritance = InheritanceManager3();
   }
 
   void _performTopLevelInference() {
diff --git a/pkg/analyzer/lib/src/summary2/linked_element_factory.dart b/pkg/analyzer/lib/src/summary2/linked_element_factory.dart
index ff48204..c07abb7 100644
--- a/pkg/analyzer/lib/src/summary2/linked_element_factory.dart
+++ b/pkg/analyzer/lib/src/summary2/linked_element_factory.dart
@@ -5,9 +5,10 @@
 import 'package:analyzer/dart/analysis/session.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/context/context.dart';
 import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/type_provider.dart';
 import 'package:analyzer/src/dart/resolver/scope.dart';
-import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
 import 'package:analyzer/src/summary/idl.dart';
 import 'package:analyzer/src/summary2/core_types.dart';
 import 'package:analyzer/src/summary2/lazy_ast.dart';
@@ -16,7 +17,7 @@
 import 'package:analyzer/src/summary2/reference.dart';
 
 class LinkedElementFactory {
-  final AnalysisContext analysisContext;
+  final AnalysisContextImpl analysisContext;
   final AnalysisSession analysisSession;
   final Reference rootReference;
   final Map<String, LinkedLibraryContext> libraryMap = {};
@@ -61,6 +62,36 @@
     return Namespace(exportedNames);
   }
 
+  void createTypeProviders(
+    LibraryElementImpl dartCore,
+    LibraryElementImpl dartAsync,
+  ) {
+    analysisContext.setTypeProviders(
+      legacy: TypeProviderImpl(
+        coreLibrary: dartCore,
+        asyncLibrary: dartAsync,
+        isNonNullableByDefault: false,
+      ),
+      nonNullableByDefault: TypeProviderImpl(
+        coreLibrary: dartCore,
+        asyncLibrary: dartAsync,
+        isNonNullableByDefault: true,
+      ),
+    );
+
+    // During linking we create libraries when typeProvider is not ready.
+    // Update these libraries now, when typeProvider is ready.
+    for (var reference in rootReference.children) {
+      var libraryElement = reference.element as LibraryElementImpl;
+      if (libraryElement != null && libraryElement.typeProvider == null) {
+        _setLibraryTypeSystem(libraryElement);
+      }
+    }
+
+    dartCore.createLoadLibraryFunction(dartCore.typeProvider);
+    dartAsync.createLoadLibraryFunction(dartAsync.typeProvider);
+  }
+
   Element elementOfReference(Reference reference) {
     if (reference.element != null) {
       return reference.element;
@@ -129,6 +160,23 @@
       }
     }
   }
+
+  void _setLibraryTypeSystem(LibraryElementImpl libraryElement) {
+    // During linking we create libraries when typeProvider is not ready.
+    // And if we link dart:core and dart:async, we cannot create it.
+    // We will set typeProvider later, during [createTypeProviders].
+    if (analysisContext.typeProviderLegacy == null) {
+      return;
+    }
+
+    var isNonNullable = libraryElement.isNonNullableByDefault;
+    libraryElement.typeProvider = isNonNullable
+        ? analysisContext.typeProviderNonNullableByDefault
+        : analysisContext.typeProviderLegacy;
+    libraryElement.typeSystem = isNonNullable
+        ? analysisContext.typeSystemNonNullableByDefault
+        : analysisContext.typeSystemLegacy;
+  }
 }
 
 class _ElementRequest {
@@ -240,24 +288,18 @@
       ElementImpl enclosing, Reference reference) {
     if (enclosing is ClassElementImpl) {
       enclosing.accessors;
-      // Requesting accessors sets elements for accessors and fields.
-      assert(reference.element != null);
-      return reference.element;
-    }
-    if (enclosing is CompilationUnitElementImpl) {
+    } else if (enclosing is CompilationUnitElementImpl) {
       enclosing.accessors;
-      // Requesting accessors sets elements for accessors and variables.
-      assert(reference.element != null);
-      return reference.element;
-    }
-    if (enclosing is EnumElementImpl) {
+    } else if (enclosing is EnumElementImpl) {
       enclosing.accessors;
-      // Requesting accessors sets elements for accessors and variables.
-      assert(reference.element != null);
-      return reference.element;
+    } else if (enclosing is ExtensionElementImpl) {
+      enclosing.accessors;
+    } else {
+      throw StateError('${enclosing.runtimeType}');
     }
-    // Only classes and units have accessors.
-    throw StateError('${enclosing.runtimeType}');
+    // Requesting accessors sets elements for accessors and variables.
+    assert(reference.element != null);
+    return reference.element;
   }
 
   ClassElementImpl _class(
@@ -309,6 +351,7 @@
       reference,
       definingUnitContext.unit_withDeclarations,
     );
+    elementFactory._setLibraryTypeSystem(libraryElement);
 
     var units = <CompilationUnitElementImpl>[];
     var unitContainerRef = reference.getChild('@unit');
diff --git a/pkg/analyzer/lib/src/summary2/linked_unit_context.dart b/pkg/analyzer/lib/src/summary2/linked_unit_context.dart
index 8a60db6..890ad24f 100644
--- a/pkg/analyzer/lib/src/summary2/linked_unit_context.dart
+++ b/pkg/analyzer/lib/src/summary2/linked_unit_context.dart
@@ -5,6 +5,7 @@
 import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/standard_ast_factory.dart';
+import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/nullability_suffix.dart';
 import 'package:analyzer/dart/element/type.dart';
@@ -646,6 +647,12 @@
     return node.bound;
   }
 
+  Token getTypeParameterVariance(TypeParameter node) {
+    // TODO (kallentu) : Clean up TypeParameterImpl casting once variance is
+    // added to the interface.
+    return (node as TypeParameterImpl).varianceKeyword;
+  }
+
   TypeParameterList getTypeParameters2(AstNode node) {
     if (node is ClassDeclaration) {
       return node.typeParameters;
diff --git a/pkg/analyzer/lib/src/summary2/tokens_context.dart b/pkg/analyzer/lib/src/summary2/tokens_context.dart
index bae4d3bc..ab8ad17 100644
--- a/pkg/analyzer/lib/src/summary2/tokens_context.dart
+++ b/pkg/analyzer/lib/src/summary2/tokens_context.dart
@@ -147,6 +147,8 @@
         return TokenType.INDEX;
       case UnlinkedTokenType.INDEX_EQ:
         return TokenType.INDEX_EQ;
+      case UnlinkedTokenType.INOUT:
+        return Keyword.INOUT;
       case UnlinkedTokenType.INT:
         return TokenType.INT;
       case UnlinkedTokenType.INTERFACE:
@@ -193,6 +195,8 @@
         return TokenType.OPEN_SQUARE_BRACKET;
       case UnlinkedTokenType.OPERATOR:
         return Keyword.OPERATOR;
+      case UnlinkedTokenType.OUT:
+        return Keyword.OUT;
       case UnlinkedTokenType.PART:
         return Keyword.PART;
       case UnlinkedTokenType.PATCH:
diff --git a/pkg/analyzer/lib/src/summary2/tokens_writer.dart b/pkg/analyzer/lib/src/summary2/tokens_writer.dart
index 859e2ef..3e8bc74 100644
--- a/pkg/analyzer/lib/src/summary2/tokens_writer.dart
+++ b/pkg/analyzer/lib/src/summary2/tokens_writer.dart
@@ -145,6 +145,8 @@
       return UnlinkedTokenType.INDEX;
     } else if (type == TokenType.INDEX_EQ) {
       return UnlinkedTokenType.INDEX_EQ;
+    } else if (type == Keyword.INOUT) {
+      return UnlinkedTokenType.INOUT;
     } else if (type == TokenType.INT) {
       return UnlinkedTokenType.INT;
     } else if (type == Keyword.INTERFACE) {
@@ -191,6 +193,8 @@
       return UnlinkedTokenType.OPEN_SQUARE_BRACKET;
     } else if (type == Keyword.OPERATOR) {
       return UnlinkedTokenType.OPERATOR;
+    } else if (type == Keyword.OUT) {
+      return UnlinkedTokenType.OUT;
     } else if (type == Keyword.PART) {
       return UnlinkedTokenType.PART;
     } else if (type == Keyword.PATCH) {
diff --git a/pkg/analyzer/lib/src/summary2/top_level_inference.dart b/pkg/analyzer/lib/src/summary2/top_level_inference.dart
index 4914569..4abdf96 100644
--- a/pkg/analyzer/lib/src/summary2/top_level_inference.dart
+++ b/pkg/analyzer/lib/src/summary2/top_level_inference.dart
@@ -456,6 +456,7 @@
 
   void _resolveInitializer() {
     var astResolver = AstResolver(_walker._linker, _unitElement, _scope);
+    astResolver.flowAnalysis?.topLevelDeclaration_enter(_node, null, null);
     astResolver.resolve(_node.initializer, () => _node.initializer);
   }
 }
diff --git a/pkg/analyzer/lib/src/summary2/types_builder.dart b/pkg/analyzer/lib/src/summary2/types_builder.dart
index bc7fe97..54ec8cf 100644
--- a/pkg/analyzer/lib/src/summary2/types_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/types_builder.dart
@@ -28,7 +28,7 @@
 }
 
 class TypesBuilder {
-  final Dart2TypeSystem typeSystem;
+  final TypeSystemImpl typeSystem;
 
   TypesBuilder(this.typeSystem);
 
@@ -174,12 +174,6 @@
     LazyAst.setType(node, type);
   }
 
-  NullabilitySuffix _noneOrStarSuffix(AstNode node) {
-    return _nonNullableEnabled(node)
-        ? NullabilitySuffix.none
-        : NullabilitySuffix.star;
-  }
-
   bool _nonNullableEnabled(AstNode node) {
     var unit = node.thisOrAncestorOfType<CompilationUnit>();
     return unit.featureSet.isEnabled(Feature.non_nullable);
@@ -207,7 +201,7 @@
 
 /// Performs mixins inference in a [ClassDeclaration].
 class _MixinInference {
-  final Dart2TypeSystem typeSystem;
+  final TypeSystemImpl typeSystem;
   final FeatureSet featureSet;
   final InterfaceType classType;
 
@@ -347,7 +341,7 @@
 
 /// Performs mixin inference for all declarations.
 class _MixinsInference {
-  final Dart2TypeSystem typeSystem;
+  final TypeSystemImpl typeSystem;
 
   _MixinsInference(this.typeSystem);
 
diff --git a/pkg/analyzer/lib/src/task/strong/checker.dart b/pkg/analyzer/lib/src/task/strong/checker.dart
index 2f88f6f..4be1702 100644
--- a/pkg/analyzer/lib/src/task/strong/checker.dart
+++ b/pkg/analyzer/lib/src/task/strong/checker.dart
@@ -35,7 +35,7 @@
 /// Given an [expression] and a corresponding [typeSystem] and [typeProvider],
 /// gets the known static type of the expression.
 DartType getExpressionType(
-    Expression expression, TypeSystem typeSystem, TypeProvider typeProvider,
+    Expression expression, TypeSystemImpl typeSystem, TypeProvider typeProvider,
     {bool read: false}) {
   DartType type;
   if (read) {
@@ -118,7 +118,7 @@
 
 /// Checks the body of functions and properties.
 class CodeChecker extends RecursiveAstVisitor {
-  final Dart2TypeSystem rules;
+  final TypeSystemImpl rules;
   final TypeProvider typeProvider;
   final InheritanceManager3 inheritance;
   final AnalysisErrorListener reporter;
@@ -131,8 +131,8 @@
   bool _hasImplicitCasts;
   HashSet<ExecutableElement> _covariantPrivateMembers;
 
-  CodeChecker(TypeProvider typeProvider, Dart2TypeSystem rules,
-      this.inheritance, AnalysisErrorListener reporter, this._options)
+  CodeChecker(TypeProvider typeProvider, TypeSystemImpl rules, this.inheritance,
+      AnalysisErrorListener reporter, this._options)
       : typeProvider = typeProvider,
         rules = rules,
         reporter = reporter {
@@ -1408,7 +1408,7 @@
 /// check overrides between classes and superclasses, interfaces, and mixin
 /// applications.
 class _OverrideChecker {
-  final Dart2TypeSystem rules;
+  final TypeSystemImpl rules;
 
   _OverrideChecker(CodeChecker checker) : rules = checker.rules;
 
diff --git a/pkg/analyzer/lib/src/test_utilities/find_element.dart b/pkg/analyzer/lib/src/test_utilities/find_element.dart
index de58249..d707a19eb 100644
--- a/pkg/analyzer/lib/src/test_utilities/find_element.dart
+++ b/pkg/analyzer/lib/src/test_utilities/find_element.dart
@@ -7,66 +7,14 @@
 import 'package:analyzer/src/test_utilities/function_ast_visitor.dart';
 
 /// Helper for finding elements declared in the resolved [unit].
-class FindElement {
+class FindElement extends _FindElementBase {
   final CompilationUnit unit;
 
   FindElement(this.unit);
 
+  @override
   CompilationUnitElement get unitElement => unit.declaredElement;
 
-  ClassElement class_(String name) {
-    for (var class_ in unitElement.types) {
-      if (class_.name == name) {
-        return class_;
-      }
-    }
-    throw StateError('Not found: $name');
-  }
-
-  ClassElement classOrMixin(String name) {
-    for (var class_ in unitElement.types) {
-      if (class_.name == name) {
-        return class_;
-      }
-    }
-    for (var mixin in unitElement.mixins) {
-      if (mixin.name == name) {
-        return mixin;
-      }
-    }
-    throw StateError('Not found: $name');
-  }
-
-  ConstructorElement constructor(String name, {String of}) {
-    assert(name != '');
-    ConstructorElement result;
-    for (var class_ in unitElement.types) {
-      if (of == null || class_.name == of) {
-        for (var constructor in class_.constructors) {
-          if (constructor.name == name) {
-            if (result != null) {
-              throw StateError('Not unique: $name');
-            }
-            result = constructor;
-          }
-        }
-      }
-    }
-    if (result != null) {
-      return result;
-    }
-    throw StateError('Not found: $name');
-  }
-
-  ClassElement enum_(String name) {
-    for (var enum_ in unitElement.enums) {
-      if (enum_.name == name) {
-        return enum_;
-      }
-    }
-    throw StateError('Not found: $name');
-  }
-
   ExportElement export(String targetUri) {
     ExportElement result;
 
@@ -86,63 +34,6 @@
     throw StateError('Not found: $targetUri');
   }
 
-  ExtensionElement extension_(String name) {
-    for (var extension_ in unitElement.extensions) {
-      if (extension_.name == name) {
-        return extension_;
-      }
-    }
-    throw StateError('Not found: $name');
-  }
-
-  FieldElement field(String name, {String of}) {
-    FieldElement result;
-
-    void findIn(List<FieldElement> fields) {
-      for (var field in fields) {
-        if (field.name == name) {
-          if (result != null) {
-            throw StateError('Not unique: $name');
-          }
-          result = field;
-        }
-      }
-    }
-
-    for (var enum_ in unitElement.enums) {
-      if (of != null && enum_.name != of) {
-        continue;
-      }
-      findIn(enum_.fields);
-    }
-
-    for (var class_ in unitElement.types) {
-      if (of != null && class_.name != of) {
-        continue;
-      }
-      findIn(class_.fields);
-    }
-
-    for (var mixin in unitElement.mixins) {
-      if (of != null && mixin.name != of) {
-        continue;
-      }
-      findIn(mixin.fields);
-    }
-
-    for (var extension in unitElement.extensions) {
-      if (of != null && extension.name != of) {
-        continue;
-      }
-      findIn(extension.fields);
-    }
-
-    if (result != null) {
-      return result;
-    }
-    throw StateError('Not found: $name');
-  }
-
   FieldFormalParameterElement fieldFormalParameter(String name) {
     return parameter(name) as FieldFormalParameterElement;
   }
@@ -156,63 +47,6 @@
     throw StateError('Not found: $name');
   }
 
-  GenericTypeAliasElement genericTypeAlias(String name) {
-    for (var element in unitElement.functionTypeAliases) {
-      if (element is GenericTypeAliasElement && element.name == name) {
-        return element;
-      }
-    }
-    throw StateError('Not found: $name');
-  }
-
-  PropertyAccessorElement getter(String name, {String of}) {
-    PropertyAccessorElement result;
-
-    void findIn(List<PropertyAccessorElement> accessors) {
-      for (var accessor in accessors) {
-        if (accessor.isGetter && accessor.displayName == name) {
-          if (result != null) {
-            throw StateError('Not unique: $name');
-          }
-          result = accessor;
-        }
-      }
-    }
-
-    for (var enum_ in unitElement.enums) {
-      if (of != null && enum_.name != of) {
-        continue;
-      }
-      findIn(enum_.accessors);
-    }
-
-    for (var extension_ in unitElement.extensions) {
-      if (of != null && extension_.name != of) {
-        continue;
-      }
-      findIn(extension_.accessors);
-    }
-
-    for (var class_ in unitElement.types) {
-      if (of != null && class_.name != of) {
-        continue;
-      }
-      findIn(class_.accessors);
-    }
-
-    for (var mixin in unitElement.mixins) {
-      if (of != null && mixin.name != of) {
-        continue;
-      }
-      findIn(mixin.accessors);
-    }
-
-    if (result != null) {
-      return result;
-    }
-    throw StateError('Not found: $name');
-  }
-
   ImportElement import(String targetUri) {
     ImportElement importElement;
 
@@ -285,56 +119,6 @@
     return result;
   }
 
-  MethodElement method(String name, {String of}) {
-    MethodElement result;
-
-    void findIn(List<MethodElement> methods) {
-      for (var method in methods) {
-        if (method.name == name) {
-          if (result != null) {
-            throw StateError('Not unique: $name');
-          }
-          result = method;
-        }
-      }
-    }
-
-    for (var extension_ in unitElement.extensions) {
-      if (of != null && extension_.name != of) {
-        continue;
-      }
-      findIn(extension_.methods);
-    }
-
-    for (var class_ in unitElement.types) {
-      if (of != null && class_.name != of) {
-        continue;
-      }
-      findIn(class_.methods);
-    }
-
-    for (var mixin in unitElement.mixins) {
-      if (of != null && mixin.name != of) {
-        continue;
-      }
-      findIn(mixin.methods);
-    }
-
-    if (result != null) {
-      return result;
-    }
-    throw StateError('Not found: $name');
-  }
-
-  ClassElement mixin(String name) {
-    for (var mixin in unitElement.mixins) {
-      if (mixin.name == name) {
-        return mixin;
-      }
-    }
-    throw StateError('Not found: $name');
-  }
-
   ParameterElement parameter(String name) {
     ParameterElement result;
 
@@ -405,6 +189,277 @@
     throw StateError('Not found: $name');
   }
 
+  TypeParameterElement typeParameter(String name) {
+    TypeParameterElement result;
+
+    void findIn(List<TypeParameterElement> typeParameters) {
+      for (var typeParameter in typeParameters) {
+        if (typeParameter.name == name) {
+          if (result != null) {
+            throw StateError('Not unique: $name');
+          }
+          result = typeParameter;
+        }
+      }
+    }
+
+    for (var type in unitElement.functionTypeAliases) {
+      findIn(type.typeParameters);
+      if (type is GenericTypeAliasElement) {
+        findIn(type.function.typeParameters);
+      }
+    }
+
+    for (var class_ in unitElement.types) {
+      findIn(class_.typeParameters);
+    }
+
+    for (var mixin in unitElement.mixins) {
+      findIn(mixin.typeParameters);
+    }
+
+    if (result != null) {
+      return result;
+    }
+    throw StateError('Not found: $name');
+  }
+}
+
+/// Helper for searching imported elements.
+class ImportFindElement extends _FindElementBase {
+  final ImportElement import;
+
+  ImportFindElement(this.import);
+
+  LibraryElement get importedLibrary => import.importedLibrary;
+
+  PrefixElement get prefix => import.prefix;
+
+  CompilationUnitElement get unitElement {
+    return importedLibrary.definingCompilationUnit;
+  }
+}
+
+abstract class _FindElementBase {
+  CompilationUnitElement get unitElement;
+
+  ClassElement class_(String name) {
+    for (var class_ in unitElement.types) {
+      if (class_.name == name) {
+        return class_;
+      }
+    }
+    throw StateError('Not found: $name');
+  }
+
+  ClassElement classOrMixin(String name) {
+    for (var class_ in unitElement.types) {
+      if (class_.name == name) {
+        return class_;
+      }
+    }
+    for (var mixin in unitElement.mixins) {
+      if (mixin.name == name) {
+        return mixin;
+      }
+    }
+    throw StateError('Not found: $name');
+  }
+
+  ConstructorElement constructor(String name, {String of}) {
+    assert(name != '');
+    ConstructorElement result;
+    for (var class_ in unitElement.types) {
+      if (of == null || class_.name == of) {
+        for (var constructor in class_.constructors) {
+          if (constructor.name == name) {
+            if (result != null) {
+              throw StateError('Not unique: $name');
+            }
+            result = constructor;
+          }
+        }
+      }
+    }
+    if (result != null) {
+      return result;
+    }
+    throw StateError('Not found: $name');
+  }
+
+  ClassElement enum_(String name) {
+    for (var enum_ in unitElement.enums) {
+      if (enum_.name == name) {
+        return enum_;
+      }
+    }
+    throw StateError('Not found: $name');
+  }
+
+  ExtensionElement extension_(String name) {
+    for (var extension_ in unitElement.extensions) {
+      if (extension_.name == name) {
+        return extension_;
+      }
+    }
+    throw StateError('Not found: $name');
+  }
+
+  FieldElement field(String name, {String of}) {
+    FieldElement result;
+
+    void findIn(List<FieldElement> fields) {
+      for (var field in fields) {
+        if (field.name == name) {
+          if (result != null) {
+            throw StateError('Not unique: $name');
+          }
+          result = field;
+        }
+      }
+    }
+
+    for (var enum_ in unitElement.enums) {
+      if (of != null && enum_.name != of) {
+        continue;
+      }
+      findIn(enum_.fields);
+    }
+
+    for (var class_ in unitElement.types) {
+      if (of != null && class_.name != of) {
+        continue;
+      }
+      findIn(class_.fields);
+    }
+
+    for (var mixin in unitElement.mixins) {
+      if (of != null && mixin.name != of) {
+        continue;
+      }
+      findIn(mixin.fields);
+    }
+
+    for (var extension in unitElement.extensions) {
+      if (of != null && extension.name != of) {
+        continue;
+      }
+      findIn(extension.fields);
+    }
+
+    if (result != null) {
+      return result;
+    }
+    throw StateError('Not found: $name');
+  }
+
+  FunctionTypeAliasElement functionTypeAlias(String name) {
+    for (var element in unitElement.functionTypeAliases) {
+      if (element is GenericTypeAliasElement && element.name == name) {
+        return element;
+      }
+    }
+    throw StateError('Not found: $name');
+  }
+
+  PropertyAccessorElement getter(String name, {String of}) {
+    PropertyAccessorElement result;
+
+    void findIn(List<PropertyAccessorElement> accessors) {
+      for (var accessor in accessors) {
+        if (accessor.isGetter && accessor.displayName == name) {
+          if (result != null) {
+            throw StateError('Not unique: $name');
+          }
+          result = accessor;
+        }
+      }
+    }
+
+    for (var enum_ in unitElement.enums) {
+      if (of != null && enum_.name != of) {
+        continue;
+      }
+      findIn(enum_.accessors);
+    }
+
+    for (var extension_ in unitElement.extensions) {
+      if (of != null && extension_.name != of) {
+        continue;
+      }
+      findIn(extension_.accessors);
+    }
+
+    for (var class_ in unitElement.types) {
+      if (of != null && class_.name != of) {
+        continue;
+      }
+      findIn(class_.accessors);
+    }
+
+    for (var mixin in unitElement.mixins) {
+      if (of != null && mixin.name != of) {
+        continue;
+      }
+      findIn(mixin.accessors);
+    }
+
+    if (result != null) {
+      return result;
+    }
+    throw StateError('Not found: $name');
+  }
+
+  MethodElement method(String name, {String of}) {
+    MethodElement result;
+
+    void findIn(List<MethodElement> methods) {
+      for (var method in methods) {
+        if (method.name == name) {
+          if (result != null) {
+            throw StateError('Not unique: $name');
+          }
+          result = method;
+        }
+      }
+    }
+
+    for (var extension_ in unitElement.extensions) {
+      if (of != null && extension_.name != of) {
+        continue;
+      }
+      findIn(extension_.methods);
+    }
+
+    for (var class_ in unitElement.types) {
+      if (of != null && class_.name != of) {
+        continue;
+      }
+      findIn(class_.methods);
+    }
+
+    for (var mixin in unitElement.mixins) {
+      if (of != null && mixin.name != of) {
+        continue;
+      }
+      findIn(mixin.methods);
+    }
+
+    if (result != null) {
+      return result;
+    }
+    throw StateError('Not found: $name');
+  }
+
+  ClassElement mixin(String name) {
+    for (var mixin in unitElement.mixins) {
+      if (mixin.name == name) {
+        return mixin;
+      }
+    }
+    throw StateError('Not found: $name');
+  }
+
   PropertyAccessorElement setter(String name, {String of}) {
     PropertyAccessorElement result;
 
@@ -472,111 +527,7 @@
     throw StateError('Not found: $name');
   }
 
-  TypeParameterElement typeParameter(String name) {
-    TypeParameterElement result;
-
-    void findIn(List<TypeParameterElement> typeParameters) {
-      for (var typeParameter in typeParameters) {
-        if (typeParameter.name == name) {
-          if (result != null) {
-            throw StateError('Not unique: $name');
-          }
-          result = typeParameter;
-        }
-      }
-    }
-
-    for (var type in unitElement.functionTypeAliases) {
-      findIn(type.typeParameters);
-      if (type is GenericTypeAliasElement) {
-        findIn(type.function.typeParameters);
-      }
-    }
-
-    for (var class_ in unitElement.types) {
-      findIn(class_.typeParameters);
-    }
-
-    for (var mixin in unitElement.mixins) {
-      findIn(mixin.typeParameters);
-    }
-
-    if (result != null) {
-      return result;
-    }
-    throw StateError('Not found: $name');
-  }
-
   ConstructorElement unnamedConstructor(String name) {
     return class_(name).unnamedConstructor;
   }
 }
-
-/// Helper for searching imported elements.
-class ImportFindElement {
-  final ImportElement import;
-
-  ImportFindElement(this.import);
-
-  CompilationUnitElement get definingUnit {
-    return importedLibrary.definingCompilationUnit;
-  }
-
-  LibraryElement get importedLibrary => import.importedLibrary;
-
-  PrefixElement get prefix => import.prefix;
-
-  ClassElement class_(String name) {
-    for (var class_ in definingUnit.types) {
-      if (class_.name == name) {
-        return class_;
-      }
-    }
-    throw StateError('Not found: $name');
-  }
-
-  ExtensionElement extension_(String name) {
-    for (var element in definingUnit.extensions) {
-      if (element.name == name) {
-        return element;
-      }
-    }
-    throw StateError('Not found: $name');
-  }
-
-  GenericTypeAliasElement functionTypeAlias(String name) {
-    for (var element in definingUnit.functionTypeAliases) {
-      if (element.name == name) {
-        return element;
-      }
-    }
-    throw StateError('Not found: $name');
-  }
-
-  FunctionElement topFunction(String name) {
-    for (var function in definingUnit.functions) {
-      if (function.name == name) {
-        return function;
-      }
-    }
-    throw StateError('Not found: $name');
-  }
-
-  PropertyAccessorElement topGetter(String name) {
-    for (var accessor in definingUnit.accessors) {
-      if (accessor.name == name && accessor.isGetter) {
-        return accessor;
-      }
-    }
-    throw StateError('Not found: $name');
-  }
-
-  TopLevelVariableElement topVar(String name) {
-    for (var variable in definingUnit.topLevelVariables) {
-      if (variable.name == name) {
-        return variable;
-      }
-    }
-    throw StateError('Not found: $name');
-  }
-}
diff --git a/pkg/analyzer/lib/src/test_utilities/find_node.dart b/pkg/analyzer/lib/src/test_utilities/find_node.dart
index 87a5af6..b862a58 100644
--- a/pkg/analyzer/lib/src/test_utilities/find_node.dart
+++ b/pkg/analyzer/lib/src/test_utilities/find_node.dart
@@ -247,6 +247,10 @@
     return _node(search, (n) => n is SuperExpression);
   }
 
+  SuperConstructorInvocation superConstructorInvocation(String search) {
+    return _node(search, (n) => n is SuperConstructorInvocation);
+  }
+
   SwitchStatement switchStatement(String search) {
     return _node(search, (n) => n is SwitchStatement);
   }
diff --git a/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart b/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
index 2ae5993..eb7bc31 100644
--- a/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
+++ b/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
@@ -5,6 +5,7 @@
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/file_system/memory_file_system.dart';
 import 'package:analyzer/src/context/context.dart';
+import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/summary/idl.dart' show PackageBundle;
@@ -869,6 +870,8 @@
 
   final Map<String, String> uriMap = {};
 
+  final AnalysisOptionsImpl _analysisOptions;
+
   /**
    * The [AnalysisContextImpl] which is used for all of the sources.
    */
@@ -887,8 +890,9 @@
   MockSdk({
     bool generateSummaryFiles: false,
     @required this.resourceProvider,
+    AnalysisOptionsImpl analysisOptions,
     List<MockSdkLibrary> additionalLibraries = const [],
-  }) {
+  }) : _analysisOptions = analysisOptions ?? AnalysisOptionsImpl() {
     for (MockSdkLibrary library in _LIBRARIES) {
       var convertedLibrary = library._toProvider(resourceProvider);
       sdkLibraries.add(convertedLibrary);
@@ -943,9 +947,8 @@
   @override
   AnalysisContextImpl get context {
     if (_analysisContext == null) {
-      _analysisContext = new _SdkAnalysisContext(this);
-      SourceFactory factory = new SourceFactory([new DartUriResolver(this)]);
-      _analysisContext.sourceFactory = factory;
+      var factory = SourceFactory([DartUriResolver(this)]);
+      _analysisContext = SdkAnalysisContext(_analysisOptions, factory);
     }
     return _analysisContext;
   }
@@ -1096,12 +1099,3 @@
     );
   }
 }
-
-/**
- * An [AnalysisContextImpl] that only contains sources for a Dart SDK.
- */
-class _SdkAnalysisContext extends AnalysisContextImpl {
-  final DartSdk sdk;
-
-  _SdkAnalysisContext(this.sdk);
-}
diff --git a/pkg/analyzer/lib/src/workspace/bazel.dart b/pkg/analyzer/lib/src/workspace/bazel.dart
index 5209ea3..ea670ae 100644
--- a/pkg/analyzer/lib/src/workspace/bazel.dart
+++ b/pkg/analyzer/lib/src/workspace/bazel.dart
@@ -101,7 +101,7 @@
 
     // Search in each root.
     for (String root in [
-      _workspace.bin,
+      ..._workspace.binPaths,
       _workspace.genfiles,
       _workspace.readonly,
       _workspace.root
@@ -181,10 +181,11 @@
    */
   final String readonly;
 
-  /**
-   * The absolute path to the `bazel-bin` folder.
-   */
-  final String bin;
+  /// The absolute paths to all `bazel-bin` folders.
+  ///
+  /// In practice, there is usually one "bin" path, and sometimes there are two,
+  /// on distributed build systems. It is very rare to have more than two.
+  final List<String> binPaths;
 
   /**
    * The absolute path to the `bazel-genfiles` folder.
@@ -192,7 +193,10 @@
   final String genfiles;
 
   BazelWorkspace._(
-      this.provider, this.root, this.readonly, this.bin, this.genfiles);
+      this.provider, this.root, this.readonly, this.binPaths, this.genfiles);
+
+  @override
+  bool get isBazel => true;
 
   @override
   Map<String, List<Folder>> get packageMap => null;
@@ -236,7 +240,7 @@
         }
       }
       // bin
-      if (bin != null) {
+      for (String bin in binPaths) {
         File file = provider.getFile(context.join(bin, relative));
         if (file.exists) {
           return file;
@@ -291,18 +295,20 @@
       // In some distributed build environments, BUILD files are not preserved.
       // We can still look for a ".packages" file in order to determine a
       // package's root. A ".packages" file found in [folder]'s sister path
-      // under [bin] denotes a Dart package.
+      // under a "bin" path among [binPaths] denotes a Dart package.
       //
       // For example, if this BazelWorkspace's [root] is
-      // "/build/work/abc123/workspace" with a [bin] folder of
+      // "/build/work/abc123/workspace" with two "bin" folders,
+      // "/build/work/abc123/workspace/blaze-out/host/bin/" and
       // "/build/work/abc123/workspace/blaze-out/k8-opt/bin/", and [folder]
       // is at "/build/work/abc123/workspace/foo/bar", then we  must look for a
-      // file ending in ".packages" in the folder
+      // file ending in ".packages" in the folders
+      // "/build/work/abc123/workspace/blaze-out/host/bin/foo/bar" and
       // "/build/work/abc123/workspace/blaze-out/k8-opt/bin/foo/bar".
 
       // [folder]'s path, relative to [root]. For example, "foo/bar".
       String relative = context.relative(folder.path, from: root);
-      if (bin != null) {
+      for (String bin in binPaths) {
         Folder binChild = provider.getFolder(context.join(bin, relative));
         if (binChild.exists &&
             binChild.getChildren().any((c) => c.path.endsWith('.packages'))) {
@@ -355,11 +361,11 @@
         String readonlyRoot =
             context.join(readonlyFolder.path, folder.shortName);
         if (provider.getFolder(readonlyRoot).exists) {
-          String binPath = _findBinFolderPath(folder);
+          List<String> binPaths = _findBinFolderPaths(folder);
           String symlinkPrefix =
-              _findSymlinkPrefix(provider, root, binPath: binPath);
-          binPath ??= context.join(root, '$symlinkPrefix-bin');
-          return new BazelWorkspace._(provider, root, readonlyRoot, binPath,
+              _findSymlinkPrefix(provider, root, binPaths: binPaths);
+          binPaths ??= [context.join(root, '$symlinkPrefix-bin')];
+          return new BazelWorkspace._(provider, root, readonlyRoot, binPaths,
               context.join(root, '$symlinkPrefix-genfiles'));
         }
       }
@@ -367,23 +373,23 @@
       if (_firstExistingFolder(parent, ['blaze-out', 'bazel-out']) != null) {
         // Found the "out" folder; must be a bazel workspace.
         String root = parent.path;
-        String binPath = _findBinFolderPath(parent);
+        List<String> binPaths = _findBinFolderPaths(parent);
         String symlinkPrefix =
-            _findSymlinkPrefix(provider, root, binPath: binPath);
-        binPath ??= context.join(root, '$symlinkPrefix-bin');
+            _findSymlinkPrefix(provider, root, binPaths: binPaths);
+        binPaths ??= [context.join(root, '$symlinkPrefix-bin')];
         return new BazelWorkspace._(provider, root, null /* readonly */,
-            binPath, context.join(root, '$symlinkPrefix-genfiles'));
+            binPaths, context.join(root, '$symlinkPrefix-genfiles'));
       }
 
       // Found the WORKSPACE file, must be a non-git workspace.
       if (folder.getChildAssumingFile(_WORKSPACE).exists) {
         String root = folder.path;
-        String binPath = _findBinFolderPath(folder);
+        List<String> binPaths = _findBinFolderPaths(folder);
         String symlinkPrefix =
-            _findSymlinkPrefix(provider, root, binPath: binPath);
-        binPath ??= context.join(root, '$symlinkPrefix-bin');
+            _findSymlinkPrefix(provider, root, binPaths: binPaths);
+        binPaths ??= [context.join(root, '$symlinkPrefix-bin')];
         return new BazelWorkspace._(provider, root, null /* readonly */,
-            binPath, context.join(root, '$symlinkPrefix-genfiles'));
+            binPaths, context.join(root, '$symlinkPrefix-genfiles'));
       }
 
       // Go up the folder.
@@ -391,11 +397,6 @@
     }
   }
 
-  /// Return the first folder within [root], chosen from [names], which exists.
-  static Folder _firstExistingFolder(Folder root, List<String> names) => names
-      .map((name) => root.getChildAssumingFolder(name))
-      .firstWhere((folder) => folder.exists, orElse: () => null);
-
   /// Find the "bin" folder path, by searching for it.
   ///
   /// Depending on the environment we're working in (source code tree, build
@@ -403,15 +404,15 @@
   /// folder may be available at a symlink found at `$root/blaze-bin/` or
   /// `$root/bazel-bin/`. If that symlink is not available, then we must search
   /// the immediate folders found in `$root/blaze-out/` and `$root/bazel-out/`
-  /// for a folder named "bin".
+  /// for folders named "bin".
   ///
   /// If no "bin" folder is found in any of those locations, `null` is returned.
-  static String _findBinFolderPath(Folder root) {
-    // This is a symlink to the real bin folder, but it is the easiest and
-    // cheapest to search for.
+  static List<String> _findBinFolderPaths(Folder root) {
+    // This is a symlink to the real, singular "bin" folder, but it is the
+    // easiest and cheapest to search for.
     Folder symlink = _firstExistingFolder(root, ['blaze-bin', 'bazel-bin']);
     if (symlink != null) {
-      return symlink.path;
+      return [symlink.path];
     }
 
     Folder out = _firstExistingFolder(root, ['blaze-out', 'bazel-out']);
@@ -419,28 +420,32 @@
       return null;
     }
 
+    List<String> binPaths = [];
     for (var child in out.getChildren().whereType<Folder>()) {
       // Children are folders denoting architectures and build flags, like
       // 'k8-opt', 'k8-fastbuild', perhaps 'host'.
       Folder possibleBin = child.getChildAssumingFolder('bin');
       if (possibleBin.exists) {
-        return possibleBin.path;
+        binPaths.add(possibleBin.path);
       }
     }
-    return null;
+    return binPaths.isEmpty ? null : binPaths;
   }
 
   /// Return the symlink prefix, _X_, for folders `X-bin` or `X-genfiles`.
   ///
-  /// If the workspace's "bin" folder was already found, the symlink prefix is
-  /// determined from [binPath]. Otherwise it is determined by probing the
-  /// internal `blaze-genfiles` and `bazel-genfiles`. Make a default assumption
-  /// according to [defaultSymlinkPrefix] if neither of the folders exists.
+  /// If the workspace's "bin" folders were already found, the symlink prefix is
+  /// determined from one of the [binPaths]. Otherwise it is determined by
+  /// probing the internal `blaze-genfiles` and `bazel-genfiles`. Make a default
+  /// assumption according to [defaultSymlinkPrefix] if neither of the folders
+  /// exists.
   static String _findSymlinkPrefix(ResourceProvider provider, String root,
-      {String binPath}) {
+      {List<String> binPaths}) {
     path.Context context = provider.pathContext;
-    if (binPath != null) {
-      return context.basename(binPath).startsWith('bazel') ? 'bazel' : 'blaze';
+    if (binPaths != null && binPaths.isNotEmpty) {
+      return context.basename(binPaths.first).startsWith('bazel')
+          ? 'bazel'
+          : 'blaze';
     }
     if (provider.getFolder(context.join(root, 'blaze-genfiles')).exists) {
       return 'blaze';
@@ -451,6 +456,11 @@
     // Couldn't find it.  Make a default assumption.
     return defaultSymlinkPrefix;
   }
+
+  /// Return the first folder within [root], chosen from [names], which exists.
+  static Folder _firstExistingFolder(Folder root, List<String> names) => names
+      .map((name) => root.getChildAssumingFolder(name))
+      .firstWhere((folder) => folder.exists, orElse: () => null);
 }
 
 /**
diff --git a/pkg/analyzer/lib/src/workspace/workspace.dart b/pkg/analyzer/lib/src/workspace/workspace.dart
index 7b74cb5..9b70903 100644
--- a/pkg/analyzer/lib/src/workspace/workspace.dart
+++ b/pkg/analyzer/lib/src/workspace/workspace.dart
@@ -6,6 +6,7 @@
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/summary/package_bundle_reader.dart';
+import 'package:analyzer/src/workspace/bazel.dart';
 
 /**
  * Abstract superclass of classes that provide information about the workspace
@@ -19,6 +20,11 @@
   bool get hasFlutterDependency => packageMap?.containsKey('flutter') ?? false;
 
   /**
+   * Return true iff this [Workspace] is a [BazelWorkspace].
+   */
+  bool get isBazel => false;
+
+  /**
    * Return a (possibly null) map of package sources.
    */
   Map<String, List<Folder>> get packageMap;
diff --git a/pkg/analyzer/test/generated/compile_time_error_code.dart b/pkg/analyzer/test/generated/compile_time_error_code.dart
index d5cf46c..0f460595 100644
--- a/pkg/analyzer/test/generated/compile_time_error_code.dart
+++ b/pkg/analyzer/test/generated/compile_time_error_code.dart
@@ -16,21 +16,6 @@
 import 'test_support.dart';
 
 class CompileTimeErrorCodeTestBase extends DriverResolutionTest {
-  disabled_test_conflictingGenericInterfaces_hierarchyLoop_infinite() async {
-    // There is an interface conflict here due to a loop in the class
-    // hierarchy leading to an infinite set of implemented types; this loop
-    // shouldn't cause non-termination.
-
-    // TODO(paulberry): this test is currently disabled due to non-termination
-    // bugs elsewhere in the analyzer.
-    await assertErrorsInCode('''
-class A<T> implements B<List<T>> {}
-class B<T> implements A<List<T>> {}
-''', [
-      error(CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES, 0, 0),
-    ]);
-  }
-
   @failingTest
   test_accessPrivateEnumField() async {
     await assertErrorsInCode(r'''
@@ -4365,7 +4350,7 @@
   test_typeAliasCannotReferenceItself_generic() async {
     List<ExpectedError> expectedErrors = [
       error(CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF, 0, 37),
-      error(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE, 101, 1),
+      error(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE_FROM_FUNCTION, 101, 1),
     ];
     await assertErrorsInCode(r'''
 typedef F = void Function(List<G> l);
diff --git a/pkg/analyzer/test/generated/element_resolver_test.dart b/pkg/analyzer/test/generated/element_resolver_test.dart
index 8f4902a7..c28ee46 100644
--- a/pkg/analyzer/test/generated/element_resolver_test.dart
+++ b/pkg/analyzer/test/generated/element_resolver_test.dart
@@ -384,6 +384,7 @@
     // abstract class A { int operator[](int index); }
     //
     ClassElementImpl classA = ElementFactory.classElement2("A");
+    _encloseElement(classA);
     MethodElement operator =
         ElementFactory.methodElement("[]", intType, [intType]);
     classA.methods = <MethodElement>[operator];
@@ -391,23 +392,26 @@
     // class B implements A {}
     //
     ClassElementImpl classB = ElementFactory.classElement2("B");
-    classB.interfaces = <InterfaceType>[interfaceType(classA)];
+    _encloseElement(classB);
+    classB.interfaces = <InterfaceType>[interfaceTypeStar(classA)];
     //
     // class C extends Object with B {}
     //
     ClassElementImpl classC = ElementFactory.classElement2("C");
-    classC.mixins = <InterfaceType>[interfaceType(classB)];
+    _encloseElement(classC);
+    classC.mixins = <InterfaceType>[interfaceTypeStar(classB)];
     //
     // class D extends C {}
     //
     ClassElementImpl classD =
-        ElementFactory.classElement("D", interfaceType(classC));
+        ElementFactory.classElement("D", interfaceTypeStar(classC));
+    _encloseElement(classA);
     //
     // D a;
     // a[i];
     //
     SimpleIdentifier array = AstTestFactory.identifier3("a");
-    array.staticType = interfaceType(classD);
+    array.staticType = interfaceTypeStar(classD);
     IndexExpression expression =
         AstTestFactory.indexExpression(array, AstTestFactory.identifier3("i"));
     expect(_resolveIndexExpression(expression), same(operator));
@@ -492,8 +496,8 @@
     //   break loop;
     // }
     String label = "loop";
-    LabelElementImpl labelElement = new LabelElementImpl.forNode(
-        AstTestFactory.identifier3(label), false, false);
+    LabelElementImpl labelElement =
+        new LabelElementImpl(label, -1, false, false);
     BreakStatement breakStatement = AstTestFactory.breakStatement2(label);
     Expression condition = AstTestFactory.booleanLiteral(true);
     WhileStatement whileStatement =
@@ -575,6 +579,7 @@
 
   test_visitConstructorName_named() async {
     ClassElementImpl classA = ElementFactory.classElement2("A");
+    _encloseElement(classA);
     String constructorName = "a";
     ConstructorElement constructor =
         ElementFactory.constructorElement2(classA, constructorName);
@@ -588,6 +593,7 @@
 
   test_visitConstructorName_unnamed() async {
     ClassElementImpl classA = ElementFactory.classElement2("A");
+    _encloseElement(classA);
     String constructorName;
     ConstructorElement constructor =
         ElementFactory.constructorElement2(classA, constructorName);
@@ -604,8 +610,8 @@
     //   continue loop;
     // }
     String label = "loop";
-    LabelElementImpl labelElement = new LabelElementImpl.forNode(
-        AstTestFactory.identifier3(label), false, false);
+    LabelElementImpl labelElement =
+        new LabelElementImpl(label, -1, false, false);
     ContinueStatement continueStatement =
         AstTestFactory.continueStatement(label);
     Expression condition = AstTestFactory.booleanLiteral(true);
@@ -758,7 +764,8 @@
     ConstructorElementImpl constructor =
         ElementFactory.constructorElement2(classA, constructorName);
     String parameterName = "a";
-    ParameterElement parameter = ElementFactory.namedParameter(parameterName);
+    ParameterElement parameter =
+        ElementFactory.namedParameter2(parameterName, _typeProvider.intType);
     constructor.parameters = <ParameterElement>[parameter];
     classA.constructors = <ConstructorElement>[constructor];
     ConstructorName name = AstTestFactory.constructorName(
@@ -848,15 +855,16 @@
 
   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 = interfaceType(classA);
+    variable.type = interfaceTypeStar(classA);
     target.staticElement = variable;
-    target.staticType = interfaceType(classA);
+    target.staticType = interfaceTypeStar(classA);
     PrefixedIdentifier identifier = AstTestFactory.identifier(
         target, AstTestFactory.identifier3(getterName));
     _resolveNode(identifier);
@@ -867,6 +875,7 @@
 
   test_visitPrefixedIdentifier_staticClassMember_getter() async {
     ClassElementImpl classA = ElementFactory.classElement2("A");
+    _encloseElement(classA);
     // set accessors
     String propName = "b";
     PropertyAccessorElement getter =
@@ -877,7 +886,7 @@
     // prepare "A.b"
     SimpleIdentifier target = AstTestFactory.identifier3("A");
     target.staticElement = classA;
-    target.staticType = interfaceType(classA);
+    target.staticType = interfaceTypeStar(classA);
     PrefixedIdentifier identifier =
         AstTestFactory.identifier(target, AstTestFactory.identifier3(propName));
     // resolve
@@ -889,6 +898,7 @@
 
   test_visitPrefixedIdentifier_staticClassMember_method() async {
     ClassElementImpl classA = ElementFactory.classElement2("A");
+    _encloseElement(classA);
     // set methods
     String propName = "m";
     var method = ElementFactory.methodElement("m", _typeProvider.intType);
@@ -897,7 +907,7 @@
     // prepare "A.m"
     SimpleIdentifier target = AstTestFactory.identifier3("A");
     target.staticElement = classA;
-    target.staticType = interfaceType(classA);
+    target.staticType = interfaceTypeStar(classA);
     PrefixedIdentifier identifier =
         AstTestFactory.identifier(target, AstTestFactory.identifier3(propName));
     AstTestFactory.expressionStatement(identifier);
@@ -910,6 +920,7 @@
 
   test_visitPrefixedIdentifier_staticClassMember_setter() async {
     ClassElementImpl classA = ElementFactory.classElement2("A");
+    _encloseElement(classA);
     // set accessors
     String propName = "b";
     PropertyAccessorElement getter =
@@ -920,7 +931,7 @@
     // prepare "A.b = null"
     SimpleIdentifier target = AstTestFactory.identifier3("A");
     target.staticElement = classA;
-    target.staticType = interfaceType(classA);
+    target.staticType = interfaceTypeStar(classA);
     PrefixedIdentifier identifier =
         AstTestFactory.identifier(target, AstTestFactory.identifier3(propName));
     AstTestFactory.assignmentExpression(
@@ -945,12 +956,13 @@
 
   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 = interfaceType(classA);
+    target.staticType = interfaceTypeStar(classA);
     PropertyAccess access = AstTestFactory.propertyAccess2(target, getterName);
     _resolveNode(access);
     expect(access.propertyName.staticElement, same(getter));
@@ -967,13 +979,14 @@
     // }
     //
     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();
-    target.staticType =
-        interfaceType(ElementFactory.classElement("B", interfaceType(classA)));
+    target.staticType = interfaceTypeStar(
+        ElementFactory.classElement("B", interfaceTypeStar(classA)));
     PropertyAccess access = AstTestFactory.propertyAccess2(target, getterName);
     AstTestFactory.methodDeclaration2(
         null,
@@ -990,12 +1003,13 @@
 
   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 = interfaceType(classA);
+    target.staticType = interfaceTypeStar(classA);
     PropertyAccess access = AstTestFactory.propertyAccess2(target, setterName);
     AstTestFactory.assignmentExpression(
         access, TokenType.EQ, AstTestFactory.integer(0));
@@ -1031,6 +1045,7 @@
   test_visitSimpleIdentifier_lexicalScope_field_setter() async {
     InterfaceType intType = _typeProvider.intType;
     ClassElementImpl classA = ElementFactory.classElement2("A");
+    _encloseElement(classA);
     String fieldName = "a";
     FieldElement field =
         ElementFactory.fieldElement(fieldName, false, false, false, intType);
@@ -1047,11 +1062,13 @@
 
   test_visitSuperConstructorInvocation() async {
     ClassElementImpl superclass = ElementFactory.classElement2("A");
+    _encloseElement(superclass);
     ConstructorElementImpl superConstructor =
         ElementFactory.constructorElement2(superclass, null);
     superclass.constructors = <ConstructorElement>[superConstructor];
     ClassElementImpl subclass =
-        ElementFactory.classElement("B", interfaceType(superclass));
+        ElementFactory.classElement("B", interfaceTypeStar(superclass));
+    _encloseElement(subclass);
     ConstructorElementImpl subConstructor =
         ElementFactory.constructorElement2(subclass, null);
     subclass.constructors = <ConstructorElement>[subConstructor];
@@ -1067,6 +1084,7 @@
 
   test_visitSuperConstructorInvocation_namedParameter() async {
     ClassElementImpl superclass = ElementFactory.classElement2("A");
+    _encloseElement(superclass);
     ConstructorElementImpl superConstructor =
         ElementFactory.constructorElement2(superclass, null);
     String parameterName = "p";
@@ -1074,7 +1092,8 @@
     superConstructor.parameters = <ParameterElement>[parameter];
     superclass.constructors = <ConstructorElement>[superConstructor];
     ClassElementImpl subclass =
-        ElementFactory.classElement("B", interfaceType(superclass));
+        ElementFactory.classElement("B", interfaceTypeStar(superclass));
+    _encloseElement(subclass);
     ConstructorElementImpl subConstructor =
         ElementFactory.constructorElement2(subclass, null);
     subclass.constructors = <ConstructorElement>[subConstructor];
@@ -1103,12 +1122,17 @@
     AnalysisContext context = TestAnalysisContext();
     _typeProvider = context.typeProvider;
 
-    var inheritance = new InheritanceManager3(context.typeSystem);
     Source source = new FileSource(getFile("/test.dart"));
     CompilationUnitElementImpl unit = new CompilationUnitElementImpl();
     unit.librarySource = unit.source = source;
-    _definingLibrary = ElementFactory.library(context, "test");
+    _definingLibrary =
+        ElementFactory.library(context, "test", isNonNullableByDefault: false);
     _definingLibrary.definingCompilationUnit = unit;
+
+    _definingLibrary.typeProvider = context.typeProvider;
+    _definingLibrary.typeSystem = context.typeSystem;
+    var inheritance = new InheritanceManager3();
+
     _visitor = new ResolverVisitor(
         inheritance, _definingLibrary, source, _typeProvider, _listener,
         featureSet: FeatureSet.forTesting(),
@@ -1116,6 +1140,12 @@
     _resolver = _visitor.elementResolver;
   }
 
+  void _encloseElement(ElementImpl element) {
+    if (element is ClassElement) {
+      element.enclosingElement = _definingLibrary;
+    }
+  }
+
   /**
    * Return the element associated with the label of [statement] after the
    * resolver has resolved it.  [labelElement] is the label element to be
diff --git a/pkg/analyzer/test/generated/elements_types_mixin.dart b/pkg/analyzer/test/generated/elements_types_mixin.dart
index cff157f..08de4eb 100644
--- a/pkg/analyzer/test/generated/elements_types_mixin.dart
+++ b/pkg/analyzer/test/generated/elements_types_mixin.dart
@@ -6,6 +6,7 @@
 import 'package:analyzer/dart/element/nullability_suffix.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/member.dart';
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/dart/resolver/variance.dart';
 import 'package:analyzer/src/generated/resolver.dart';
@@ -13,7 +14,54 @@
 import 'package:meta/meta.dart';
 
 mixin ElementsTypesMixin {
-  DynamicTypeImpl get dynamicType => typeProvider.dynamicType;
+  InterfaceType get doubleNone {
+    var element = typeProvider.doubleType.element;
+    return interfaceTypeNone(element);
+  }
+
+  InterfaceType get doubleQuestion {
+    var element = typeProvider.doubleType.element;
+    return interfaceTypeQuestion(element);
+  }
+
+  InterfaceType get doubleStar {
+    var element = typeProvider.doubleType.element;
+    return interfaceTypeStar(element);
+  }
+
+  DartType get dynamicNone => DynamicTypeImpl.instance;
+
+  DynamicTypeImpl get dynamicType => DynamicTypeImpl.instance;
+
+  InterfaceType get functionNone {
+    var element = typeProvider.functionType.element;
+    return interfaceTypeNone(element);
+  }
+
+  InterfaceType get functionQuestion {
+    var element = typeProvider.functionType.element;
+    return interfaceTypeQuestion(element);
+  }
+
+  InterfaceType get functionStar {
+    var element = typeProvider.functionType.element;
+    return interfaceTypeStar(element);
+  }
+
+  InterfaceType get intNone {
+    var element = typeProvider.intType.element;
+    return interfaceTypeNone(element);
+  }
+
+  InterfaceType get intQuestion {
+    var element = typeProvider.intType.element;
+    return interfaceTypeQuestion(element);
+  }
+
+  InterfaceType get intStar {
+    var element = typeProvider.intType.element;
+    return interfaceTypeStar(element);
+  }
 
   NeverTypeImpl get neverNone => NeverTypeImpl.instance;
 
@@ -21,8 +69,70 @@
 
   NeverTypeImpl get neverStar => NeverTypeImpl.instanceLegacy;
 
+  InterfaceType get nullNone {
+    var element = typeProvider.nullType.element;
+    return interfaceTypeNone(element);
+  }
+
+  InterfaceType get nullQuestion {
+    var element = typeProvider.nullType.element;
+    return interfaceTypeQuestion(element);
+  }
+
+  InterfaceType get nullStar {
+    var element = typeProvider.nullType.element;
+    return interfaceTypeStar(element);
+  }
+
+  InterfaceType get numNone {
+    var element = typeProvider.numType.element;
+    return interfaceTypeNone(element);
+  }
+
+  InterfaceType get numQuestion {
+    var element = typeProvider.numType.element;
+    return interfaceTypeQuestion(element);
+  }
+
+  InterfaceType get numStar {
+    var element = typeProvider.numType.element;
+    return interfaceTypeStar(element);
+  }
+
+  InterfaceType get objectNone {
+    var element = typeProvider.objectType.element;
+    return interfaceTypeNone(element);
+  }
+
+  InterfaceType get objectQuestion {
+    var element = typeProvider.objectType.element;
+    return interfaceTypeQuestion(element);
+  }
+
+  InterfaceType get objectStar {
+    var element = typeProvider.objectType.element;
+    return interfaceTypeStar(element);
+  }
+
+  InterfaceType get stringNone {
+    var element = typeProvider.stringType.element;
+    return interfaceTypeNone(element);
+  }
+
+  InterfaceType get stringQuestion {
+    var element = typeProvider.stringType.element;
+    return interfaceTypeQuestion(element);
+  }
+
+  InterfaceType get stringStar {
+    var element = typeProvider.stringType.element;
+    return interfaceTypeStar(element);
+  }
+
   TypeProvider get typeProvider;
 
+  VoidType get voidNone => typeProvider.voidType;
+
   ClassElementImpl class_({
     @required String name,
     bool isAbstract = false,
@@ -41,6 +151,33 @@
     return element;
   }
 
+  InterfaceType comparableNone(DartType type) {
+    var coreLibrary = typeProvider.intElement.library;
+    var element = coreLibrary.getType('Comparable');
+    return element.instantiate(
+      typeArguments: [type],
+      nullabilitySuffix: NullabilitySuffix.none,
+    );
+  }
+
+  InterfaceType comparableQuestion(DartType type) {
+    var coreLibrary = typeProvider.intElement.library;
+    var element = coreLibrary.getType('Comparable');
+    return element.instantiate(
+      typeArguments: [type],
+      nullabilitySuffix: NullabilitySuffix.question,
+    );
+  }
+
+  InterfaceType comparableStar(DartType type) {
+    var coreLibrary = typeProvider.intElement.library;
+    var element = coreLibrary.getType('Comparable');
+    return element.instantiate(
+      typeArguments: [type],
+      nullabilitySuffix: NullabilitySuffix.star,
+    );
+  }
+
   FunctionTypeImpl functionType({
     @required List<TypeParameterElement> typeFormals,
     @required List<ParameterElement> parameters,
@@ -105,9 +242,51 @@
     );
   }
 
+  InterfaceTypeImpl futureNone(DartType type) {
+    return typeProvider.futureElement.instantiate(
+      typeArguments: [type],
+      nullabilitySuffix: NullabilitySuffix.none,
+    );
+  }
+
+  InterfaceTypeImpl futureOrNone(DartType type) {
+    return typeProvider.futureOrElement.instantiate(
+      typeArguments: [type],
+      nullabilitySuffix: NullabilitySuffix.none,
+    );
+  }
+
+  InterfaceTypeImpl futureOrQuestion(DartType type) {
+    return typeProvider.futureOrElement.instantiate(
+      typeArguments: [type],
+      nullabilitySuffix: NullabilitySuffix.question,
+    );
+  }
+
+  InterfaceTypeImpl futureOrStar(DartType type) {
+    return typeProvider.futureOrElement.instantiate(
+      typeArguments: [type],
+      nullabilitySuffix: NullabilitySuffix.star,
+    );
+  }
+
+  InterfaceTypeImpl futureQuestion(DartType type) {
+    return typeProvider.futureElement.instantiate(
+      typeArguments: [type],
+      nullabilitySuffix: NullabilitySuffix.question,
+    );
+  }
+
+  InterfaceTypeImpl futureStar(DartType type) {
+    return typeProvider.futureElement.instantiate(
+      typeArguments: [type],
+      nullabilitySuffix: NullabilitySuffix.star,
+    );
+  }
+
   DartType futureType(DartType T) {
     var futureElement = typeProvider.futureElement;
-    return interfaceType(futureElement, typeArguments: [T]);
+    return interfaceTypeStar(futureElement, typeArguments: [T]);
   }
 
   GenericFunctionTypeElementImpl genericFunctionType({
@@ -135,15 +314,86 @@
   InterfaceType interfaceType(
     ClassElement element, {
     List<DartType> typeArguments = const [],
-    NullabilitySuffix nullabilitySuffix = NullabilitySuffix.star,
+    @required NullabilitySuffix nullabilitySuffix,
   }) {
-    return InterfaceTypeImpl.explicit(
-      element,
-      typeArguments,
+    return element.instantiate(
+      typeArguments: typeArguments,
       nullabilitySuffix: nullabilitySuffix,
     );
   }
 
+  InterfaceType interfaceTypeNone(
+    ClassElement element, {
+    List<DartType> typeArguments = const [],
+  }) {
+    return element.instantiate(
+      typeArguments: typeArguments,
+      nullabilitySuffix: NullabilitySuffix.none,
+    );
+  }
+
+  InterfaceType interfaceTypeQuestion(
+    ClassElement element, {
+    List<DartType> typeArguments = const [],
+  }) {
+    return element.instantiate(
+      typeArguments: typeArguments,
+      nullabilitySuffix: NullabilitySuffix.question,
+    );
+  }
+
+  InterfaceType interfaceTypeStar(
+    ClassElement element, {
+    List<DartType> typeArguments = const [],
+  }) {
+    return element.instantiate(
+      typeArguments: typeArguments,
+      nullabilitySuffix: NullabilitySuffix.star,
+    );
+  }
+
+  InterfaceType iterableNone(DartType type) {
+    return typeProvider.iterableElement.instantiate(
+      typeArguments: [type],
+      nullabilitySuffix: NullabilitySuffix.none,
+    );
+  }
+
+  InterfaceType iterableQuestion(DartType type) {
+    return typeProvider.iterableElement.instantiate(
+      typeArguments: [type],
+      nullabilitySuffix: NullabilitySuffix.question,
+    );
+  }
+
+  InterfaceType iterableStar(DartType type) {
+    return typeProvider.iterableElement.instantiate(
+      typeArguments: [type],
+      nullabilitySuffix: NullabilitySuffix.star,
+    );
+  }
+
+  InterfaceType listNone(DartType type) {
+    return typeProvider.listElement.instantiate(
+      typeArguments: [type],
+      nullabilitySuffix: NullabilitySuffix.none,
+    );
+  }
+
+  InterfaceType listQuestion(DartType type) {
+    return typeProvider.listElement.instantiate(
+      typeArguments: [type],
+      nullabilitySuffix: NullabilitySuffix.question,
+    );
+  }
+
+  InterfaceType listStar(DartType type) {
+    return typeProvider.listElement.instantiate(
+      typeArguments: [type],
+      nullabilitySuffix: NullabilitySuffix.star,
+    );
+  }
+
   MethodElement method(
     String name,
     DartType returnType, {
@@ -158,6 +408,20 @@
       ..typeParameters = typeFormals;
   }
 
+  MixinElementImpl mixin_({
+    @required String name,
+    List<TypeParameterElement> typeParameters = const [],
+    List<InterfaceType> constraints,
+    List<InterfaceType> interfaces = const [],
+  }) {
+    var element = MixinElementImpl(name, 0);
+    element.typeParameters = typeParameters;
+    element.superclassConstraints = constraints ?? [typeProvider.objectType];
+    element.interfaces = interfaces;
+    element.constructors = const <ConstructorElement>[];
+    return element;
+  }
+
   ParameterElement namedParameter({
     @required String name,
     @required DartType type,
@@ -185,6 +449,14 @@
     return parameter;
   }
 
+  TypeParameterMember promoteTypeParameter(
+    TypeParameterElement element,
+    DartType bound,
+  ) {
+    assert(element is! TypeParameterMember);
+    return TypeParameterMember(element, null, bound);
+  }
+
   ParameterElement requiredParameter({String name, @required DartType type}) {
     var parameter = ParameterElementImpl(name ?? '', 0);
     parameter.parameterKind = ParameterKind.REQUIRED;
diff --git a/pkg/analyzer/test/generated/error_suppression_test.dart b/pkg/analyzer/test/generated/error_suppression_test.dart
index d3e8852..003c3b0 100644
--- a/pkg/analyzer/test/generated/error_suppression_test.dart
+++ b/pkg/analyzer/test/generated/error_suppression_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/test_utilities/package_mixin.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import '../src/dart/resolution/driver_resolution.dart';
@@ -14,7 +15,7 @@
 }
 
 @reflectiveTest
-class ErrorSuppressionTest extends DriverResolutionTest {
+class ErrorSuppressionTest extends DriverResolutionTest with PackageMixin {
   String get ignoredCode => 'const_initialized_with_non_constant_value';
 
   test_error_code_mismatch() async {
@@ -98,6 +99,18 @@
     ]);
   }
 
+  test_ignore_uniqueName() async {
+    addMetaPackage();
+    await assertNoErrorsInCode('''
+import 'package:meta/meta.dart';
+
+int f({@Required('x') int a}) => 0;
+
+// ignore: missing_required_param_with_details
+int x = f();
+''');
+  }
+
   test_ignore_upper_case() async {
     await assertNoErrorsInCode('''
 int x = ''; // ignore: INVALID_ASSIGNMENT
diff --git a/pkg/analyzer/test/generated/invalid_code_test.dart b/pkg/analyzer/test/generated/invalid_code_test.dart
index c1531fd..c3f499c 100644
--- a/pkg/analyzer/test/generated/invalid_code_test.dart
+++ b/pkg/analyzer/test/generated/invalid_code_test.dart
@@ -56,7 +56,7 @@
     await _assertCanBeAnalyzed(r'''
 typedef F = void Function(bool, int a(double b));
 ''');
-    var alias = findElement.genericTypeAlias('F');
+    var alias = findElement.functionTypeAlias('F');
     assertElementTypeString(
       alias.instantiate(
         typeArguments: const [],
@@ -126,7 +126,7 @@
     await _assertCanBeAnalyzed(r'''
 typedef void F(int a, this.b);
 ''');
-    var alias = findElement.genericTypeAlias('F');
+    var alias = findElement.functionTypeAlias('F');
     assertElementTypeString(
       alias.instantiate(
         typeArguments: const [],
@@ -202,6 +202,38 @@
     await _assertCanBeAnalyzed(r'c(=k(<)>');
   }
 
+  test_fuzz_38506() async {
+    // https://github.com/dart-lang/sdk/issues/38506
+    // We have only one LibraryElement to get resolved annotations.
+    // Leave annotations node of other LibraryDirective(s) unresolved.
+    await _assertCanBeAnalyzed(r'''
+library c;
+@foo
+library c;
+''');
+  }
+
+  test_fuzz_38953() async {
+    // When we enter a directive, we should stop using the element walker
+    // of the unit, just like when we enter a method body. Even though using
+    // interpolation is not allowed in any directives.
+    await _assertCanBeAnalyzed(r'''
+import '${[for(var v = 0;;) v]}';
+export '${[for(var v = 0;;) v]}';
+part '${[for(var v = 0;;) v]}';
+''');
+  }
+
+  test_fuzz_38878() async {
+    // We should not attempt to resolve `super` in annotations.
+    await _assertCanBeAnalyzed(r'''
+class C {
+  @A(super.f())
+  f(int x) {}
+}
+''');
+  }
+
   test_genericFunction_asTypeArgument_ofUnresolvedClass() async {
     await _assertCanBeAnalyzed(r'''
 C<int Function()> c;
diff --git a/pkg/analyzer/test/generated/parser_test.dart b/pkg/analyzer/test/generated/parser_test.dart
index 207f917..4d04bc4 100644
--- a/pkg/analyzer/test/generated/parser_test.dart
+++ b/pkg/analyzer/test/generated/parser_test.dart
@@ -2598,8 +2598,7 @@
     parser.parseCompilationUnit2();
     listener.assertErrors(usingFastaParser
         ? [
-            expectedError(
-                CompileTimeErrorCode.TYPE_PARAMETER_ON_CONSTRUCTOR, 11, 2),
+            expectedError(ParserErrorCode.TYPE_PARAMETER_ON_CONSTRUCTOR, 11, 2),
             expectedError(ParserErrorCode.MISSING_IDENTIFIER, 13, 1),
             expectedError(ParserErrorCode.MISSING_METHOD_PARAMETERS, 10, 1),
             expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 13, 1),
@@ -2617,8 +2616,7 @@
     parser.parseCompilationUnit2();
     listener.assertErrors(usingFastaParser
         ? [
-            expectedError(
-                CompileTimeErrorCode.TYPE_PARAMETER_ON_CONSTRUCTOR, 11, 6),
+            expectedError(ParserErrorCode.TYPE_PARAMETER_ON_CONSTRUCTOR, 11, 6),
             expectedError(ParserErrorCode.MISSING_IDENTIFIER, 17, 1),
             expectedError(ParserErrorCode.MISSING_METHOD_PARAMETERS, 10, 1),
             expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 17, 1)
@@ -2637,7 +2635,7 @@
     listener.assertErrors(usingFastaParser
         ? [
             expectedError(
-                CompileTimeErrorCode.TYPE_PARAMETER_ON_CONSTRUCTOR, 11, 13),
+                ParserErrorCode.TYPE_PARAMETER_ON_CONSTRUCTOR, 11, 13),
             expectedError(ParserErrorCode.MISSING_IDENTIFIER, 24, 1),
             expectedError(ParserErrorCode.MISSING_METHOD_PARAMETERS, 10, 1),
             expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 24, 1)
diff --git a/pkg/analyzer/test/generated/resolver_test.dart b/pkg/analyzer/test/generated/resolver_test.dart
index 58fc71e..7400a44 100644
--- a/pkg/analyzer/test/generated/resolver_test.dart
+++ b/pkg/analyzer/test/generated/resolver_test.dart
@@ -137,8 +137,7 @@
   void test_creation_nonEmpty() {
     AnalysisContext context = TestAnalysisContext();
     String importedTypeName = "A";
-    ClassElement importedType = new ClassElementImpl.forNode(
-        AstTestFactory.identifier3(importedTypeName));
+    ClassElement importedType = new ClassElementImpl(importedTypeName, -1);
     LibraryElement importedLibrary = createTestLibrary(context, "imported");
     (importedLibrary.definingCompilationUnit as CompilationUnitElementImpl)
         .types = <ClassElement>[importedType];
@@ -224,8 +223,7 @@
   void test_creation_nonEmpty() {
     AnalysisContext context = TestAnalysisContext();
     String importedTypeName = "A";
-    ClassElement importedType = new ClassElementImpl.forNode(
-        AstTestFactory.identifier3(importedTypeName));
+    ClassElement importedType = new ClassElementImpl(importedTypeName, -1);
     LibraryElement importedLibrary = createTestLibrary(context, "imported");
     (importedLibrary.definingCompilationUnit as CompilationUnitElementImpl)
         .types = <ClassElement>[importedType];
diff --git a/pkg/analyzer/test/generated/resolver_test_case.dart b/pkg/analyzer/test/generated/resolver_test_case.dart
index 8978aa5..d3b2718 100644
--- a/pkg/analyzer/test/generated/resolver_test_case.dart
+++ b/pkg/analyzer/test/generated/resolver_test_case.dart
@@ -25,7 +25,6 @@
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source_io.dart';
-import 'package:analyzer/src/generated/testing/ast_test_factory.dart';
 import 'package:analyzer/src/generated/testing/element_factory.dart';
 import 'package:analyzer/src/source/package_map_resolver.dart';
 import 'package:analyzer/src/test_utilities/mock_sdk.dart';
@@ -356,7 +355,7 @@
   /**
    * Return a type system that can be used to test the results of resolution.
    */
-  TypeSystem get typeSystem {
+  TypeSystemImpl get typeSystem {
     if (analysisResults.isEmpty) {
       fail('typeSystem called before computing an analysis result.');
     }
@@ -518,8 +517,7 @@
       sourcedCompilationUnits = new List<CompilationUnitElement>(count);
       for (int i = 0; i < count; i++) {
         String typeName = typeNames[i];
-        ClassElementImpl type =
-            new ClassElementImpl.forNode(AstTestFactory.identifier3(typeName));
+        ClassElementImpl type = new ClassElementImpl(typeName, -1);
         String fileName = "$typeName.dart";
         CompilationUnitElementImpl compilationUnit =
             new CompilationUnitElementImpl();
@@ -534,10 +532,12 @@
     compilationUnit.librarySource =
         compilationUnit.source = definingCompilationUnitSource;
     var featureSet = context.analysisOptions.contextFeatures;
-    LibraryElementImpl library = new LibraryElementImpl.forNode(
+    LibraryElementImpl library = new LibraryElementImpl(
         context,
         driver?.currentSession,
-        AstTestFactory.libraryIdentifier2([libraryName]),
+        libraryName,
+        -1,
+        0,
         featureSet.isEnabled(Feature.non_nullable));
     library.definingCompilationUnit = compilationUnit;
     library.parts = sourcedCompilationUnits;
@@ -583,8 +583,10 @@
     if (experiments != null) {
       (options as AnalysisOptionsImpl).enabledExperiments = experiments;
     }
-    DartSdk sdk = new MockSdk(resourceProvider: resourceProvider)
-      ..context.analysisOptions = options;
+    DartSdk sdk = new MockSdk(
+      resourceProvider: resourceProvider,
+      analysisOptions: options,
+    );
 
     List<UriResolver> resolvers = <UriResolver>[
       new DartUriResolver(sdk),
@@ -812,7 +814,7 @@
   final Source source;
   final CompilationUnit unit;
   final List<AnalysisError> errors;
-  final TypeSystem typeSystem;
+  final TypeSystemImpl typeSystem;
 
   TestAnalysisResult(this.source, this.unit, this.errors, this.typeSystem);
 }
diff --git a/pkg/analyzer/test/generated/simple_resolver_test.dart b/pkg/analyzer/test/generated/simple_resolver_test.dart
index 9a2e72b..501a1ef 100644
--- a/pkg/analyzer/test/generated/simple_resolver_test.dart
+++ b/pkg/analyzer/test/generated/simple_resolver_test.dart
@@ -1064,7 +1064,7 @@
     verifyTestResolved();
 
     expect(
-      findElement.genericTypeAlias('F').metadata,
+      findElement.functionTypeAlias('F').metadata,
       hasLength(1),
     );
 
diff --git a/pkg/analyzer/test/generated/static_type_analyzer_test.dart b/pkg/analyzer/test/generated/static_type_analyzer_test.dart
index 3e27401..2c4562d 100644
--- a/pkg/analyzer/test/generated/static_type_analyzer_test.dart
+++ b/pkg/analyzer/test/generated/static_type_analyzer_test.dart
@@ -220,7 +220,7 @@
   /**
    * The type system used to analyze the test cases.
    */
-  TypeSystem get _typeSystem => _visitor.typeSystem;
+  TypeSystemImpl get _typeSystem => _visitor.typeSystem;
 
   void fail_visitFunctionExpressionInvocation() {
     _fail("Not yet tested");
@@ -251,21 +251,22 @@
     InterfaceType intType = _typeProvider.intType;
     DartType dynamicType = _typeProvider.dynamicType;
     InterfaceType derivedIntType =
-        interfaceType(derivedClass, typeArguments: [intType]);
+        interfaceTypeStar(derivedClass, typeArguments: [intType]);
     // flatten(Derived) = dynamic
     InterfaceType derivedDynamicType =
-        interfaceType(derivedClass, typeArguments: [dynamicType]);
+        interfaceTypeStar(derivedClass, typeArguments: [dynamicType]);
     expect(_flatten(derivedDynamicType), dynamicType);
     // flatten(Derived<int>) = int
     expect(_flatten(derivedIntType), intType);
     // flatten(Derived<Derived>) = Derived
     expect(
-        _flatten(
-            interfaceType(derivedClass, typeArguments: [derivedDynamicType])),
+        _flatten(interfaceTypeStar(derivedClass,
+            typeArguments: [derivedDynamicType])),
         derivedDynamicType);
     // flatten(Derived<Derived<int>>) = Derived<int>
     expect(
-        _flatten(interfaceType(derivedClass, typeArguments: [derivedIntType])),
+        _flatten(
+            interfaceTypeStar(derivedClass, typeArguments: [derivedIntType])),
         derivedIntType);
   }
 
@@ -274,13 +275,13 @@
     // class B extends A
     ClassElementImpl classA = ElementFactory.classElement2('A', []);
     ClassElementImpl classB = ElementFactory.classElement2('B', []);
-    classA.supertype = interfaceType(classB);
-    classB.supertype = interfaceType(classA);
+    classA.supertype = interfaceTypeStar(classB);
+    classB.supertype = interfaceTypeStar(classA);
     // flatten(A) = A and flatten(B) = B, since neither class contains Future
     // in its class hierarchy.  Even though there is a loop in the class
     // hierarchy, flatten() should terminate.
-    expect(_flatten(interfaceType(classA)), interfaceType(classA));
-    expect(_flatten(interfaceType(classB)), interfaceType(classB));
+    expect(_flatten(interfaceTypeStar(classA)), interfaceTypeStar(classA));
+    expect(_flatten(interfaceTypeStar(classB)), interfaceTypeStar(classB));
   }
 
   void test_flatten_related_derived_types() {
@@ -293,21 +294,21 @@
         futureType(typeParameterType(derivedClass.typeParameters[0]));
     // class A extends Derived<int> implements Derived<num> { ... }
     ClassElementImpl classA = ElementFactory.classElement(
-        'A', interfaceType(derivedClass, typeArguments: [intType]));
+        'A', interfaceTypeStar(derivedClass, typeArguments: [intType]));
     classA.interfaces = <InterfaceType>[
-      interfaceType(derivedClass, typeArguments: [numType]),
+      interfaceTypeStar(derivedClass, typeArguments: [numType]),
     ];
     // class B extends Future<num> implements Future<int> { ... }
     ClassElementImpl classB = ElementFactory.classElement(
-        'B', interfaceType(derivedClass, typeArguments: [numType]));
+        'B', interfaceTypeStar(derivedClass, typeArguments: [numType]));
     classB.interfaces = <InterfaceType>[
-      interfaceType(derivedClass, typeArguments: [intType])
+      interfaceTypeStar(derivedClass, typeArguments: [intType])
     ];
     // flatten(A) = flatten(B) = int, since int is more specific than num.
     // The code in flatten() that inhibits infinite recursion shouldn't be
     // fooled by the fact that Derived appears twice in the type hierarchy.
-    expect(_flatten(interfaceType(classA)), intType);
-    expect(_flatten(interfaceType(classB)), intType);
+    expect(_flatten(interfaceTypeStar(classA)), intType);
+    expect(_flatten(interfaceTypeStar(classB)), intType);
   }
 
   void test_flatten_related_types() {
@@ -322,8 +323,8 @@
         ElementFactory.classElement('B', _typeProvider.futureType2(numType));
     classB.interfaces = <InterfaceType>[_typeProvider.futureType2(intType)];
     // flatten(A) = flatten(B) = int, since int is more specific than num.
-    expect(_flatten(interfaceType(classA)), intType);
-    expect(_flatten(interfaceType(classB)), intType);
+    expect(_flatten(interfaceTypeStar(classA)), intType);
+    expect(_flatten(interfaceTypeStar(classB)), intType);
   }
 
   void test_flatten_simple() {
@@ -362,8 +363,8 @@
     classB.interfaces = <InterfaceType>[_typeProvider.futureType2(intType)];
     // flatten(A) = A and flatten(B) = B, since neither string nor int is more
     // specific than the other.
-    expect(_flatten(interfaceType(classA)), interfaceType(classA));
-    expect(_flatten(interfaceType(classB)), interfaceType(classB));
+    expect(_flatten(interfaceTypeStar(classA)), interfaceTypeStar(classA));
+    expect(_flatten(interfaceTypeStar(classB)), interfaceTypeStar(classB));
   }
 
   void test_visitAdjacentStrings() {
@@ -378,11 +379,11 @@
     // class A { ... this as B ... }
     // class B extends A {}
     ClassElement superclass = ElementFactory.classElement2("A");
-    InterfaceType superclassType = interfaceType(superclass);
+    InterfaceType superclassType = interfaceTypeStar(superclass);
     ClassElement subclass = ElementFactory.classElement("B", superclassType);
     Expression node = AstTestFactory.asExpression(
         AstTestFactory.thisExpression(), AstTestFactory.typeName(subclass));
-    expect(_analyze(node, superclassType), interfaceType(subclass));
+    expect(_analyze(node, superclassType), interfaceTypeStar(subclass));
     _listener.assertNoErrors();
   }
 
@@ -509,7 +510,7 @@
     // }
     // (a as A) * 2.0
     ClassElementImpl classA = ElementFactory.classElement2("A");
-    InterfaceType typeA = interfaceType(classA);
+    InterfaceType typeA = interfaceTypeStar(classA);
     MethodElement operator =
         ElementFactory.methodElement("*", typeA, [_typeProvider.doubleType]);
     classA.methods = <MethodElement>[operator];
@@ -872,7 +873,7 @@
             AstTestFactory.typeName(classElement),
             [AstTestFactory.identifier3(constructorName)]);
     node.staticElement = constructor;
-    expect(_analyze(node), interfaceType(classElement));
+    expect(_analyze(node), interfaceTypeStar(classElement));
     _listener.assertNoErrors();
   }
 
@@ -885,15 +886,15 @@
     elementC.constructors = <ConstructorElement>[constructor];
     TypeName typeName =
         AstTestFactory.typeName(elementC, [AstTestFactory.typeName(elementI)]);
-    typeName.type =
-        interfaceType(elementC, typeArguments: [interfaceType(elementI)]);
+    typeName.type = interfaceTypeStar(elementC,
+        typeArguments: [interfaceTypeStar(elementI)]);
     InstanceCreationExpression node =
         AstTestFactory.instanceCreationExpression2(null, typeName);
     node.staticElement = constructor;
     InterfaceType type = _analyze(node) as InterfaceType;
     List<DartType> typeArgs = type.typeArguments;
     expect(typeArgs.length, 1);
-    expect(typeArgs[0], interfaceType(elementI));
+    expect(typeArgs[0], interfaceTypeStar(elementI));
     _listener.assertNoErrors();
   }
 
@@ -907,7 +908,7 @@
         AstTestFactory.instanceCreationExpression2(
             null, AstTestFactory.typeName(classElement));
     node.staticElement = constructor;
-    expect(_analyze(node), interfaceType(classElement));
+    expect(_analyze(node), interfaceTypeStar(classElement));
     _listener.assertNoErrors();
   }
 
@@ -1179,9 +1180,10 @@
 
   void test_visitSuperExpression() {
     // super
-    InterfaceType superType = interfaceType(ElementFactory.classElement2("A"));
+    InterfaceType superType =
+        interfaceTypeStar(ElementFactory.classElement2("A"));
     InterfaceType thisType =
-        interfaceType(ElementFactory.classElement("B", superType));
+        interfaceTypeStar(ElementFactory.classElement("B", superType));
     Expression node = AstTestFactory.superExpression();
     expect(_analyze(node, thisType), same(thisType));
     _listener.assertNoErrors();
@@ -1194,8 +1196,8 @@
 
   void test_visitThisExpression() {
     // this
-    InterfaceType thisType = interfaceType(ElementFactory.classElement(
-        "B", interfaceType(ElementFactory.classElement2("A"))));
+    InterfaceType thisType = interfaceTypeStar(ElementFactory.classElement(
+        "B", interfaceTypeStar(ElementFactory.classElement2("A"))));
     Expression node = AstTestFactory.thisExpression();
     expect(_analyze(node, thisType), same(thisType));
     _listener.assertNoErrors();
@@ -1312,15 +1314,15 @@
    */
   StaticTypeAnalyzer _createAnalyzer() {
     var context = TestAnalysisContext();
-    var inheritance = new InheritanceManager3(context.typeSystem);
+    var inheritance = new InheritanceManager3();
     Source source = new FileSource(getFile("/lib.dart"));
     CompilationUnitElementImpl definingCompilationUnit =
         new CompilationUnitElementImpl();
     definingCompilationUnit.librarySource =
         definingCompilationUnit.source = source;
     var featureSet = FeatureSet.forTesting();
-    LibraryElementImpl definingLibrary = new LibraryElementImpl.forNode(
-        context, null, null, featureSet.isEnabled(Feature.non_nullable));
+    LibraryElementImpl definingLibrary = new LibraryElementImpl(
+        context, null, null, -1, 0, featureSet.isEnabled(Feature.non_nullable));
     definingLibrary.definingCompilationUnit = definingCompilationUnit;
     _typeProvider = context.typeProvider;
     _visitor = new ResolverVisitor(
@@ -1367,17 +1369,18 @@
       FormalParameterList parameters, FunctionBody body) {
     List<ParameterElement> parameterElements = new List<ParameterElement>();
     for (FormalParameter parameter in parameters.parameters) {
+      var nameNode = parameter.identifier;
       ParameterElementImpl element =
-          new ParameterElementImpl.forNode(parameter.identifier);
+          new ParameterElementImpl(nameNode.name, nameNode.offset);
       // ignore: deprecated_member_use_from_same_package
       element.parameterKind = parameter.kind;
       element.type = _typeProvider.dynamicType;
-      parameter.identifier.staticElement = element;
+      nameNode.staticElement = element;
       parameterElements.add(element);
     }
     FunctionExpression node =
         AstTestFactory.functionExpression2(parameters, body);
-    FunctionElementImpl element = new FunctionElementImpl.forNode(null);
+    FunctionElementImpl element = new FunctionElementImpl('', -1);
     element.parameters = parameterElements;
     (node as FunctionExpressionImpl).declaredElement = element;
     return node;
@@ -1434,7 +1437,7 @@
     SimpleIdentifier identifier = parameter.identifier;
     Element element = identifier.staticElement;
     if (element is! ParameterElement) {
-      element = new ParameterElementImpl.forNode(identifier);
+      element = new ParameterElementImpl(identifier.name, identifier.offset);
       identifier.staticElement = element;
     }
     (element as ParameterElementImpl).type = type;
diff --git a/pkg/analyzer/test/generated/static_type_warning_code_test.dart b/pkg/analyzer/test/generated/static_type_warning_code_test.dart
index 033dc53..4a2ffd8 100644
--- a/pkg/analyzer/test/generated/static_type_warning_code_test.dart
+++ b/pkg/analyzer/test/generated/static_type_warning_code_test.dart
@@ -927,7 +927,7 @@
 }
 Future<Future<int>> g() => null;
 ''', [
-      error(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE, 54, 3),
+      error(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE_FROM_FUNCTION, 54, 3),
     ]);
   }
 
@@ -938,7 +938,7 @@
   return 5;
 }
 ''', [
-      error(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE, 57, 1),
+      error(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE_FROM_FUNCTION, 57, 1),
     ]);
   }
 
@@ -949,7 +949,7 @@
 }
 ''', [
       error(StaticTypeWarningCode.ILLEGAL_ASYNC_RETURN_TYPE, 0, 3),
-      error(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE, 25, 1),
+      error(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE_FROM_FUNCTION, 25, 1),
     ]);
   }
 
@@ -957,7 +957,7 @@
     await assertErrorsInCode('''
 int f() => '0';
 ''', [
-      error(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE, 11, 3),
+      error(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE_FROM_FUNCTION, 11, 3),
     ]);
   }
 
@@ -965,7 +965,7 @@
     await assertErrorsInCode('''
 int get g => '0';
 ''', [
-      error(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE, 13, 3),
+      error(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE_FROM_FUNCTION, 13, 3),
     ]);
   }
 
@@ -979,7 +979,7 @@
 }
 ''', [
       error(HintCode.UNUSED_ELEMENT, 33, 1),
-      error(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE, 40, 3),
+      error(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE_FROM_FUNCTION, 40, 3),
     ]);
   }
 
@@ -989,7 +989,7 @@
   int f() => '0';
 }
 ''', [
-      error(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE, 23, 3),
+      error(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE_FROM_METHOD, 23, 3),
     ]);
   }
 
@@ -997,7 +997,7 @@
     await assertErrorsInCode('''
 int f() { return '0'; }
 ''', [
-      error(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE, 17, 3),
+      error(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE_FROM_FUNCTION, 17, 3),
     ]);
   }
 
@@ -1005,7 +1005,7 @@
     await assertErrorsInCode('''
 int get g { return '0'; }
 ''', [
-      error(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE, 19, 3),
+      error(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE_FROM_FUNCTION, 19, 3),
     ]);
   }
 
@@ -1019,7 +1019,7 @@
 }
 ''', [
       error(HintCode.UNUSED_ELEMENT, 33, 1),
-      error(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE, 46, 3),
+      error(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE_FROM_FUNCTION, 46, 3),
     ]);
   }
 
@@ -1029,7 +1029,7 @@
   int f() { return '0'; }
 }
 ''', [
-      error(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE, 29, 3),
+      error(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE_FROM_METHOD, 29, 3),
     ]);
   }
 
@@ -1059,7 +1059,7 @@
 
   test_returnOfInvalidType_void() async {
     await assertErrorsInCode("void f() { return 42; }", [
-      error(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE, 18, 2),
+      error(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE_FROM_FUNCTION, 18, 2),
     ]);
   }
 
diff --git a/pkg/analyzer/test/generated/strong_mode_test.dart b/pkg/analyzer/test/generated/strong_mode_test.dart
index 3b2b23d..1aa5efc 100644
--- a/pkg/analyzer/test/generated/strong_mode_test.dart
+++ b/pkg/analyzer/test/generated/strong_mode_test.dart
@@ -5462,7 +5462,7 @@
   test_returnOfInvalidType_object_void() async {
     await assertErrorsInCode(
         "Object f() { void voidFn() => null; return voidFn(); }", [
-      error(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE, 43, 8),
+      error(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE_FROM_FUNCTION, 43, 8),
     ]);
   }
 
@@ -5497,7 +5497,7 @@
 }
 set g(int x) => 42;
 ''', [
-      error(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE, 41, 4),
+      error(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE_FROM_FUNCTION, 41, 4),
     ]);
   }
 
diff --git a/pkg/analyzer/test/generated/test_analysis_context.dart b/pkg/analyzer/test/generated/test_analysis_context.dart
index 29f75ef..e42b7ee 100644
--- a/pkg/analyzer/test/generated/test_analysis_context.dart
+++ b/pkg/analyzer/test/generated/test_analysis_context.dart
@@ -4,6 +4,7 @@
 
 import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/element/nullability_suffix.dart';
+import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/type_provider.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/resolver.dart';
@@ -16,7 +17,7 @@
 
   AnalysisOptions _analysisOptions;
   TypeProviderImpl _typeProvider;
-  TypeSystem _typeSystem;
+  TypeSystemImpl _typeSystem;
 
   TestAnalysisContext({FeatureSet featureSet}) {
     _analysisOptions = AnalysisOptionsImpl()
@@ -30,15 +31,24 @@
     );
 
     _typeProvider = TypeProviderImpl(
-      sdkElements.coreLibrary,
-      sdkElements.asyncLibrary,
+      coreLibrary: sdkElements.coreLibrary,
+      asyncLibrary: sdkElements.asyncLibrary,
+      isNonNullableByDefault: false,
     );
 
     if (_analysisOptions.contextFeatures.isEnabled(Feature.non_nullable)) {
-      _typeProvider = _typeProvider.withNullability(NullabilitySuffix.none);
+      _typeProvider = _typeProvider.asNonNullableByDefault;
     }
 
-    _typeSystem = Dart2TypeSystem(typeProvider);
+    _typeSystem = TypeSystemImpl(
+      implicitCasts: true,
+      isNonNullableByDefault: false,
+      strictInference: false,
+      typeProvider: typeProvider,
+    );
+
+    _setLibraryTypeSystem(sdkElements.coreLibrary);
+    _setLibraryTypeSystem(sdkElements.asyncLibrary);
   }
 
   @override
@@ -48,9 +58,14 @@
   TypeProvider get typeProvider => _typeProvider;
 
   @override
-  TypeSystem get typeSystem => _typeSystem;
+  TypeSystemImpl get typeSystem => _typeSystem;
 
   noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+
+  void _setLibraryTypeSystem(LibraryElementImpl libraryElement) {
+    libraryElement.typeProvider = _typeProvider;
+    libraryElement.typeSystem = _typeSystem;
+  }
 }
 
 class _MockSource implements Source {
diff --git a/pkg/analyzer/test/generated/type_system_test.dart b/pkg/analyzer/test/generated/type_system_test.dart
index ee8f7eb..5bc1e83 100644
--- a/pkg/analyzer/test/generated/type_system_test.dart
+++ b/pkg/analyzer/test/generated/type_system_test.dart
@@ -20,7 +20,6 @@
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/generated/source.dart'
     show NonExistingSource, UriKind;
-import 'package:analyzer/src/generated/testing/element_factory.dart';
 import 'package:meta/meta.dart';
 import 'package:path/path.dart' show toUri;
 import 'package:test/test.dart';
@@ -43,7 +42,7 @@
 
 abstract class AbstractTypeSystemTest with ElementsTypesMixin {
   TypeProvider typeProvider;
-  Dart2TypeSystem typeSystem;
+  TypeSystemImpl typeSystem;
 
   InterfaceType get doubleType => typeProvider.doubleType;
 
@@ -65,22 +64,22 @@
 
   DartType futureOrType(DartType T) {
     var futureOrElement = typeProvider.futureOrElement;
-    return interfaceType(futureOrElement, typeArguments: [T]);
+    return interfaceTypeStar(futureOrElement, typeArguments: [T]);
   }
 
   DartType futureType(DartType T) {
     var futureElement = typeProvider.futureElement;
-    return interfaceType(futureElement, typeArguments: [T]);
+    return interfaceTypeStar(futureElement, typeArguments: [T]);
   }
 
   DartType iterableType(DartType T) {
     var iterableElement = typeProvider.iterableElement;
-    return interfaceType(iterableElement, typeArguments: [T]);
+    return interfaceTypeStar(iterableElement, typeArguments: [T]);
   }
 
   DartType listType(DartType T) {
     var listElement = typeProvider.listElement;
-    return interfaceType(listElement, typeArguments: [T]);
+    return interfaceTypeStar(listElement, typeArguments: [T]);
   }
 
   void setUp() {
@@ -93,6 +92,10 @@
     typeProvider = typeProvider;
     typeSystem = typeSystem;
   }
+
+  String _typeString(TypeImpl type) {
+    return type.toString(withNullability: true);
+  }
 }
 
 @reflectiveTest
@@ -106,7 +109,7 @@
       doubleType,
       numType,
       stringType,
-      interfaceType(A),
+      interfaceTypeStar(A),
       neverStar,
     ];
 
@@ -124,7 +127,7 @@
     );
 
     _checkIsStrictAssignableTo(
-      interfaceType(B),
+      interfaceTypeStar(B),
       functionTypeStar(
         parameters: [
           requiredParameter(type: intType),
@@ -136,17 +139,17 @@
 
   void test_isAssignableTo_classes() {
     var classTop = class_(name: 'A');
-    var classLeft = class_(name: 'B', superType: interfaceType(classTop));
-    var classRight = class_(name: 'C', superType: interfaceType(classTop));
+    var classLeft = class_(name: 'B', superType: interfaceTypeStar(classTop));
+    var classRight = class_(name: 'C', superType: interfaceTypeStar(classTop));
     var classBottom = class_(
       name: 'D',
-      superType: interfaceType(classLeft),
-      interfaces: [interfaceType(classRight)],
+      superType: interfaceTypeStar(classLeft),
+      interfaces: [interfaceTypeStar(classRight)],
     );
-    var top = interfaceType(classTop);
-    var left = interfaceType(classLeft);
-    var right = interfaceType(classRight);
-    var bottom = interfaceType(classBottom);
+    var top = interfaceTypeStar(classTop);
+    var left = interfaceTypeStar(classLeft);
+    var right = interfaceTypeStar(classRight);
+    var bottom = interfaceTypeStar(classBottom);
 
     _checkLattice(top, left, right, bottom);
   }
@@ -163,7 +166,7 @@
     List<DartType> unrelated = <DartType>[
       intType,
       stringType,
-      interfaceType(A),
+      interfaceTypeStar(A),
     ];
 
     _checkGroups(doubleType,
@@ -179,7 +182,7 @@
       doubleType,
       numType,
       stringType,
-      interfaceType(A),
+      interfaceTypeStar(A),
       neverStar,
     ];
     _checkGroups(dynamicType, interassignable: interassignable);
@@ -194,7 +197,7 @@
       name: 'M',
       typeParameters: [MT],
       interfaces: [
-        interfaceType(
+        interfaceTypeStar(
           L,
           typeArguments: [
             typeParameterTypeStar(MT),
@@ -203,10 +206,10 @@
       ],
     );
 
-    var top = interfaceType(L, typeArguments: [dynamicType]);
-    var left = interfaceType(M, typeArguments: [dynamicType]);
-    var right = interfaceType(L, typeArguments: [intType]);
-    var bottom = interfaceType(M, typeArguments: [intType]);
+    var top = interfaceTypeStar(L, typeArguments: [dynamicType]);
+    var left = interfaceTypeStar(M, typeArguments: [dynamicType]);
+    var right = interfaceTypeStar(L, typeArguments: [intType]);
+    var bottom = interfaceTypeStar(M, typeArguments: [intType]);
 
     _checkCrossLattice(top, left, right, bottom);
   }
@@ -223,7 +226,7 @@
     List<DartType> unrelated = <DartType>[
       doubleType,
       stringType,
-      interfaceType(A),
+      interfaceTypeStar(A),
     ];
 
     _checkGroups(intType,
@@ -324,7 +327,7 @@
     ];
     List<DartType> unrelated = <DartType>[
       stringType,
-      interfaceType(A),
+      interfaceTypeStar(A),
     ];
 
     _checkGroups(numType,
@@ -459,18 +462,27 @@
     expect(glb, expectedResult);
   }
 
-  void _checkLeastUpperBound(
-      DartType type1, DartType type2, DartType expectedResult) {
-    var lub = typeSystem.getLeastUpperBound(type1, type2);
-    expect(lub, expectedResult);
+  void _checkLeastUpperBound(DartType T1, DartType T2, DartType expected) {
+    var expectedStr = _typeString(expected);
+
+    var result = typeSystem.getLeastUpperBound(T1, T2);
+    var resultStr = _typeString(result);
+    expect(result, expected, reason: '''
+expected: $expectedStr
+actual: $resultStr
+''');
 
     // Check that the result is an upper bound.
-    expect(typeSystem.isSubtypeOf(type1, lub), true);
-    expect(typeSystem.isSubtypeOf(type2, lub), true);
+    expect(typeSystem.isSubtypeOf(T1, result), true);
+    expect(typeSystem.isSubtypeOf(T2, result), true);
 
-    // Check for symmetry while we're at it.
-    lub = typeSystem.getLeastUpperBound(type2, type1);
-    expect(lub, expectedResult);
+    // Check for symmetry.
+    result = typeSystem.getLeastUpperBound(T2, T1);
+    resultStr = _typeString(result);
+    expect(result, expected, reason: '''
+expected: $expectedStr
+actual: $resultStr
+''');
   }
 }
 
@@ -757,6 +769,57 @@
         covariant: true);
   }
 
+  void test_variance_contravariant() {
+    // class A<in T>
+    var tContravariant = typeParameter('T', variance: Variance.contravariant);
+    var tType = typeParameterType(tContravariant);
+    var A = class_(name: 'A', typeParameters: [tContravariant]);
+
+    // A<num>
+    // A<T>
+    var aNum = interfaceType(A,
+        typeArguments: [numType], nullabilitySuffix: NullabilitySuffix.none);
+    var aT = interfaceType(A,
+        typeArguments: [tType], nullabilitySuffix: NullabilitySuffix.none);
+
+    _checkIsSubtypeMatchOf(aT, aNum, [tType], ['num <: in T'], covariant: true);
+  }
+
+  void test_variance_covariant() {
+    // class A<out T>
+    var tCovariant = typeParameter('T', variance: Variance.covariant);
+    var tType = typeParameterType(tCovariant);
+    var A = class_(name: 'A', typeParameters: [tCovariant]);
+
+    // A<num>
+    // A<T>
+    var aNum = interfaceType(A,
+        typeArguments: [numType], nullabilitySuffix: NullabilitySuffix.none);
+    var aT = interfaceType(A,
+        typeArguments: [tType], nullabilitySuffix: NullabilitySuffix.none);
+
+    _checkIsSubtypeMatchOf(aT, aNum, [tType], ['out T <: num'],
+        covariant: true);
+  }
+
+  void test_variance_invariant() {
+    // class A<inout T>
+    var tInvariant = typeParameter('T', variance: Variance.invariant);
+    var tType = typeParameterType(tInvariant);
+    var A = class_(name: 'A', typeParameters: [tInvariant]);
+
+    // A<num>
+    // A<T>
+    var aNum = interfaceType(A,
+        typeArguments: [numType], nullabilitySuffix: NullabilitySuffix.none);
+    var aT = interfaceType(A,
+        typeArguments: [tType], nullabilitySuffix: NullabilitySuffix.none);
+
+    _checkIsSubtypeMatchOf(
+        aT, aNum, [tType], ['inout T <: num', 'num <: inout T'],
+        covariant: true);
+  }
+
   void test_x_futureOr_fail_both_branches() {
     // List<T> <: FutureOr<String> can't be satisfied because neither
     // List<T> <: Future<String> nor List<T> <: int can be satisfied
@@ -892,11 +955,11 @@
 
     // class A {}
     var A = class_(name: 'A', superType: objectType);
-    var typeA = interfaceType(A);
+    var typeA = interfaceTypeStar(A);
 
     // class B extends A {}
     var B = class_(name: 'B', superType: typeA);
-    var typeB = interfaceType(B);
+    var typeB = interfaceTypeStar(B);
 
     // class C<T extends A> {
     var CT = typeParameter('T', bound: typeA);
@@ -922,11 +985,11 @@
     // }
 
     // C<Object> cOfObject;
-    var cOfObject = interfaceType(C, typeArguments: [objectType]);
+    var cOfObject = interfaceTypeStar(C, typeArguments: [objectType]);
     // C<A> cOfA;
-    var cOfA = interfaceType(C, typeArguments: [typeA]);
+    var cOfA = interfaceTypeStar(C, typeArguments: [typeA]);
     // C<B> cOfB;
-    var cOfB = interfaceType(C, typeArguments: [typeB]);
+    var cOfB = interfaceTypeStar(C, typeArguments: [typeB]);
     // B b;
     // cOfB.m(b); // infer <B>
     expect(_inferCall2(cOfB.getMethod('m').type, [typeB]).toString(),
@@ -944,11 +1007,11 @@
 
     // class A {}
     var A = class_(name: 'A', superType: objectType);
-    var typeA = interfaceType(A);
+    var typeA = interfaceTypeStar(A);
 
     // class B extends A {}
     var B = class_(name: 'B', superType: typeA);
-    var typeB = interfaceType(B);
+    var typeB = interfaceTypeStar(B);
 
     // class C<T extends A> {
     var CT = typeParameter('T', bound: typeA);
@@ -975,11 +1038,11 @@
     // }
 
     // C<Object> cOfObject;
-    var cOfObject = interfaceType(C, typeArguments: [objectType]);
+    var cOfObject = interfaceTypeStar(C, typeArguments: [objectType]);
     // C<A> cOfA;
-    var cOfA = interfaceType(C, typeArguments: [typeA]);
+    var cOfA = interfaceTypeStar(C, typeArguments: [typeA]);
     // C<B> cOfB;
-    var cOfB = interfaceType(C, typeArguments: [typeB]);
+    var cOfB = interfaceTypeStar(C, typeArguments: [typeB]);
     // List<B> b;
     var listOfB = listType(typeB);
     // cOfB.m(b); // infer <B>
@@ -1001,20 +1064,20 @@
       superType: objectType,
       typeParameters: [T],
     );
-    T.bound = interfaceType(
+    T.bound = interfaceTypeStar(
       A,
       typeArguments: [typeParameterTypeStar(T)],
     );
 
     // class B extends A<B> {}
     var B = class_(name: 'B', superType: null);
-    B.supertype = interfaceType(A, typeArguments: [interfaceType(B)]);
-    var typeB = interfaceType(B);
+    B.supertype = interfaceTypeStar(A, typeArguments: [interfaceTypeStar(B)]);
+    var typeB = interfaceTypeStar(B);
 
     // <S extends A<S>>
     var S = typeParameter('S');
     var typeS = typeParameterTypeStar(S);
-    S.bound = interfaceType(A, typeArguments: [typeS]);
+    S.bound = interfaceTypeStar(A, typeArguments: [typeS]);
 
     // (S, S) -> S
     var clone = functionTypeStar(
@@ -1128,6 +1191,50 @@
     expect(_inferCall(f, [intType]), [intType]);
   }
 
+  void test_parameter_contravariantUseUpperBound() {
+    // <T>(T x, void Function(T) y) -> T
+    // Generates constraints int <: T <: num.
+    // Since T is contravariant, choose num.
+    var T = typeParameter('T', variance: Variance.contravariant);
+    var tFunction = functionTypeStar(
+        parameters: [requiredParameter(type: typeParameterTypeStar(T))],
+        returnType: voidType);
+    var numFunction = functionTypeStar(
+        parameters: [requiredParameter(type: numType)], returnType: voidType);
+    var function = functionTypeStar(
+      typeFormals: [T],
+      parameters: [
+        requiredParameter(type: typeParameterTypeStar(T)),
+        requiredParameter(type: tFunction)
+      ],
+      returnType: typeParameterTypeStar(T),
+    );
+
+    expect(_inferCall(function, [intType, numFunction]), [numType]);
+  }
+
+  void test_parameter_covariantUseLowerBound() {
+    // <T>(T x, void Function(T) y) -> T
+    // Generates constraints int <: T <: num.
+    // Since T is covariant, choose int.
+    var T = typeParameter('T', variance: Variance.covariant);
+    var tFunction = functionTypeStar(
+        parameters: [requiredParameter(type: typeParameterTypeStar(T))],
+        returnType: voidType);
+    var numFunction = functionTypeStar(
+        parameters: [requiredParameter(type: numType)], returnType: voidType);
+    var function = functionTypeStar(
+      typeFormals: [T],
+      parameters: [
+        requiredParameter(type: typeParameterTypeStar(T)),
+        requiredParameter(type: tFunction)
+      ],
+      returnType: typeParameterTypeStar(T),
+    );
+
+    expect(_inferCall(function, [intType, numFunction]), [intType]);
+  }
+
   void test_returnFunctionWithGenericParameter() {
     // <T>(T -> T) -> (T -> void)
     var T = typeParameter('T');
@@ -1382,6 +1489,7 @@
       contextReturnType: returnType,
       errorReporter: reporter,
       errorNode: astFactory.nullLiteral(new KeywordToken(Keyword.NULL, 0)),
+      isNonNullableByDefault: false,
     );
 
     if (expectError) {
@@ -1415,7 +1523,7 @@
 
   void test_bottom_interface() {
     var A = class_(name: 'A');
-    _checkGreatestLowerBound(neverStar, interfaceType(A), neverStar);
+    _checkGreatestLowerBound(neverStar, interfaceTypeStar(A), neverStar);
   }
 
   void test_bottom_typeParam() {
@@ -1486,12 +1594,12 @@
     // class B extends A
     // class C extends B
     var A = class_(name: 'A');
-    var B = class_(name: 'B', superType: interfaceType(A));
-    var C = class_(name: 'C', superType: interfaceType(B));
+    var B = class_(name: 'B', superType: interfaceTypeStar(A));
+    var C = class_(name: 'C', superType: interfaceTypeStar(B));
     _checkGreatestLowerBound(
-      interfaceType(A),
-      interfaceType(C),
-      interfaceType(C),
+      interfaceTypeStar(A),
+      interfaceTypeStar(C),
+      interfaceTypeStar(C),
     );
   }
 
@@ -1500,12 +1608,12 @@
     // class B implements A
     // class C implements B
     var A = class_(name: 'A');
-    var B = class_(name: 'B', interfaces: [interfaceType(A)]);
-    var C = class_(name: 'C', interfaces: [interfaceType(B)]);
+    var B = class_(name: 'B', interfaces: [interfaceTypeStar(A)]);
+    var C = class_(name: 'C', interfaces: [interfaceTypeStar(B)]);
     _checkGreatestLowerBound(
-      interfaceType(A),
-      interfaceType(C),
-      interfaceType(C),
+      interfaceTypeStar(A),
+      interfaceTypeStar(C),
+      interfaceTypeStar(C),
     );
   }
 
@@ -1522,7 +1630,7 @@
 
   void test_dynamic_interface() {
     var A = class_(name: 'A');
-    var typeA = interfaceType(A);
+    var typeA = interfaceTypeStar(A);
     _checkGreatestLowerBound(dynamicType, typeA, typeA);
   }
 
@@ -1849,7 +1957,7 @@
 
   void test_interface_function() {
     var A = class_(name: 'A');
-    var typeA = interfaceType(A);
+    var typeA = interfaceTypeStar(A);
     _checkGreatestLowerBound(
       typeA,
       functionTypeStar(returnType: voidType),
@@ -1863,20 +1971,20 @@
     // class C
     // class D extends A with B, C
     var A = class_(name: 'A');
-    var typeA = interfaceType(A);
+    var typeA = interfaceTypeStar(A);
 
     var B = class_(name: 'B');
-    var typeB = interfaceType(B);
+    var typeB = interfaceTypeStar(B);
 
     var C = class_(name: 'C');
-    var typeC = interfaceType(C);
+    var typeC = interfaceTypeStar(C);
 
     var D = class_(
       name: 'D',
-      superType: interfaceType(A),
+      superType: interfaceTypeStar(A),
       mixins: [typeB, typeC],
     );
-    var typeD = interfaceType(D);
+    var typeD = interfaceTypeStar(D);
 
     _checkGreatestLowerBound(typeA, typeD, typeD);
     _checkGreatestLowerBound(typeB, typeD, typeD);
@@ -1892,7 +2000,7 @@
       voidType,
       neverStar,
       typeParameterTypeStar(T),
-      interfaceType(A),
+      interfaceTypeStar(A),
       functionTypeStar(returnType: voidType),
     ];
 
@@ -1912,13 +2020,13 @@
 
   void test_typeParam_interface_bounded() {
     var A = class_(name: 'A');
-    var typeA = interfaceType(A);
+    var typeA = interfaceTypeStar(A);
 
     var B = class_(name: 'B', superType: typeA);
-    var typeB = interfaceType(B);
+    var typeB = interfaceTypeStar(B);
 
     var C = class_(name: 'C', superType: typeB);
-    var typeC = interfaceType(C);
+    var typeC = interfaceTypeStar(C);
 
     var T = typeParameter('T', bound: typeB);
     _checkGreatestLowerBound(typeParameterTypeStar(T), typeC, neverStar);
@@ -1930,7 +2038,7 @@
     var A = class_(name: 'A');
     _checkGreatestLowerBound(
       typeParameterTypeStar(T),
-      interfaceType(A),
+      interfaceTypeStar(A),
       neverStar,
     );
   }
@@ -1949,144 +2057,14 @@
     _checkGreatestLowerBound(listOfIntType, listOfIntType, listOfIntType);
   }
 
-  void test_typeParameters_covariant_same() {
-    // class A<out T>
-    var T = typeParameter('T', variance: Variance.covariant);
-    var A = class_(name: 'A', typeParameters: [T]);
-
-    // A<num>
-    var aNum = interfaceType(A, typeArguments: [numType]);
-
-    _checkLeastUpperBound(aNum, aNum, aNum);
-  }
-
-  void test_typeParameters_covariant_different() {
-    // class A<out T>
-    var T = typeParameter('T', variance: Variance.covariant);
-    var A = class_(name: 'A', typeParameters: [T]);
-
-    // A<num>
-    // A<int>
-    var aNum = interfaceType(A, typeArguments: [numType]);
-    var aInt = interfaceType(A, typeArguments: [intType]);
-
-    _checkLeastUpperBound(aInt, aNum, aNum);
-  }
-
-  void test_typeParameters_contravariant_same() {
-    // class A<in T>
-    var T = typeParameter('T', variance: Variance.contravariant);
-    var A = class_(name: 'A', typeParameters: [T]);
-
-    // A<num>
-    var aNum = interfaceType(A, typeArguments: [numType]);
-
-    _checkLeastUpperBound(aNum, aNum, aNum);
-  }
-
-  void test_typeParameters_contravariant_different() {
-    // class A<in T>
-    var T = typeParameter('T', variance: Variance.contravariant);
-    var A = class_(name: 'A', typeParameters: [T]);
-
-    // A<num>
-    // A<int>
-    var aNum = interfaceType(A, typeArguments: [numType]);
-    var aInt = interfaceType(A, typeArguments: [intType]);
-
-    _checkLeastUpperBound(aInt, aNum, aInt);
-  }
-
-  void test_typeParameters_invariant_same() {
-    // class A<inout T>
-    var T = typeParameter('T', variance: Variance.invariant);
-    var A = class_(name: 'A', typeParameters: [T]);
-
-    // A<num>
-    var aNum = interfaceType(A, typeArguments: [numType]);
-
-    _checkLeastUpperBound(aNum, aNum, aNum);
-  }
-
-  void test_typeParameters_invariant_object() {
-    // class A<inout T>
-    var T = typeParameter('T', variance: Variance.invariant);
-    var A = class_(name: 'A', typeParameters: [T]);
-
-    // A<num>
-    // A<int>
-    var aNum = interfaceType(A, typeArguments: [numType]);
-    var aInt = interfaceType(A, typeArguments: [intType]);
-
-    _checkLeastUpperBound(aNum, aInt, objectType);
-  }
-
-  void test_typeParameters_multi_basic() {
-    // class Multi<out T, inout U, in V>
-    var T = typeParameter('T', variance: Variance.covariant);
-    var U = typeParameter('T', variance: Variance.invariant);
-    var V = typeParameter('T', variance: Variance.contravariant);
-    var Multi = class_(name: 'A', typeParameters: [T, U, V]);
-
-    // Multi<num, num, num>
-    // Multi<int, num, int>
-    var multiNumNumNum =
-        interfaceType(Multi, typeArguments: [numType, numType, numType]);
-    var multiIntNumInt =
-        interfaceType(Multi, typeArguments: [intType, numType, intType]);
-
-    // We expect Multi<num, num, int>
-    var multiNumNumInt =
-        interfaceType(Multi, typeArguments: [numType, numType, intType]);
-
-    _checkLeastUpperBound(multiNumNumNum, multiIntNumInt, multiNumNumInt);
-  }
-
-  void test_typeParameters_multi_objectInterface() {
-    // class Multi<out T, inout U, in V>
-    var T = typeParameter('T', variance: Variance.covariant);
-    var U = typeParameter('T', variance: Variance.invariant);
-    var V = typeParameter('T', variance: Variance.contravariant);
-    var Multi = class_(name: 'A', typeParameters: [T, U, V]);
-
-    // Multi<num, String, num>
-    // Multi<int, num, int>
-    var multiNumStringNum =
-        interfaceType(Multi, typeArguments: [numType, stringType, numType]);
-    var multiIntNumInt =
-        interfaceType(Multi, typeArguments: [intType, numType, intType]);
-
-    _checkLeastUpperBound(multiNumStringNum, multiIntNumInt, objectType);
-  }
-
-  void test_typeParameters_multi_objectType() {
-    // class Multi<out T, inout U, in V>
-    var T = typeParameter('T', variance: Variance.covariant);
-    var U = typeParameter('T', variance: Variance.invariant);
-    var V = typeParameter('T', variance: Variance.contravariant);
-    var Multi = class_(name: 'A', typeParameters: [T, U, V]);
-
-    // Multi<String, num, num>
-    // Multi<int, num, int>
-    var multiStringNumNum =
-        interfaceType(Multi, typeArguments: [stringType, numType, numType]);
-    var multiIntNumInt =
-        interfaceType(Multi, typeArguments: [intType, numType, intType]);
-
-    // We expect Multi<Object, num, int>
-    var multiObjectNumInt =
-        interfaceType(Multi, typeArguments: [objectType, numType, intType]);
-
-    _checkLeastUpperBound(multiStringNumNum, multiIntNumInt, multiObjectNumInt);
-  }
-
   void test_unrelatedClasses() {
     // class A
     // class B
     // class C
     var A = class_(name: 'A');
     var B = class_(name: 'B');
-    _checkGreatestLowerBound(interfaceType(A), interfaceType(B), neverStar);
+    _checkGreatestLowerBound(
+        interfaceTypeStar(A), interfaceTypeStar(B), neverStar);
   }
 
   void test_void() {
@@ -2095,7 +2073,7 @@
     List<DartType> types = [
       neverStar,
       functionTypeStar(returnType: voidType),
-      interfaceType(A),
+      interfaceTypeStar(A),
       typeParameterTypeStar(T),
     ];
     for (DartType type in types) {
@@ -2405,17 +2383,20 @@
 
 @reflectiveTest
 class LeastUpperBoundTest extends BoundTestBase {
+  @FailingTest(reason: 'With new rules UP(Never*, T)=T?')
   void test_bottom_function() {
     _checkLeastUpperBound(neverStar, functionTypeStar(returnType: voidType),
         functionTypeStar(returnType: voidType));
   }
 
+  @FailingTest(reason: 'With new rules UP(Never*, T)=T?')
   void test_bottom_interface() {
     var A = class_(name: 'A');
-    var typeA = interfaceType(A);
+    var typeA = interfaceTypeStar(A);
     _checkLeastUpperBound(neverStar, typeA, typeA);
   }
 
+  @FailingTest(reason: 'With new rules UP(Never*, T)=T?')
   void test_bottom_typeParam() {
     var T = typeParameter('T');
     var typeT = typeParameterTypeStar(T);
@@ -2428,13 +2409,13 @@
     // class C implements B
 
     var A = class_(name: 'A');
-    var typeA = interfaceType(A);
+    var typeA = interfaceTypeStar(A);
 
     var B = class_(name: 'B', interfaces: [typeA]);
-    var typeB = interfaceType(B);
+    var typeB = interfaceTypeStar(B);
 
     var C = class_(name: 'C', interfaces: [typeB]);
-    var typeC = interfaceType(C);
+    var typeC = interfaceTypeStar(C);
 
     _checkLeastUpperBound(typeB, typeC, typeB);
   }
@@ -2445,31 +2426,22 @@
     // class C extends B
 
     var A = class_(name: 'A');
-    var typeA = interfaceType(A);
+    var typeA = interfaceTypeStar(A);
 
     var B = class_(name: 'B', superType: typeA);
-    var typeB = interfaceType(B);
+    var typeB = interfaceTypeStar(B);
 
     var C = class_(name: 'C', superType: typeB);
-    var typeC = interfaceType(C);
+    var typeC = interfaceTypeStar(C);
 
     _checkLeastUpperBound(typeB, typeC, typeB);
   }
 
   void test_directSuperclass_nullability() {
     var aElement = class_(name: 'A');
-    var aQuestion = interfaceType(
-      aElement,
-      nullabilitySuffix: NullabilitySuffix.question,
-    );
-    var aStar = interfaceType(
-      aElement,
-      nullabilitySuffix: NullabilitySuffix.star,
-    );
-    var aNone = interfaceType(
-      aElement,
-      nullabilitySuffix: NullabilitySuffix.none,
-    );
+    var aQuestion = interfaceTypeQuestion(aElement);
+    var aStar = interfaceTypeStar(aElement);
+    var aNone = interfaceTypeNone(aElement);
 
     var bElementStar = class_(name: 'B', superType: aStar);
     var bElementNone = class_(name: 'B', superType: aNone);
@@ -2537,7 +2509,7 @@
 
   void test_dynamic_interface() {
     var A = class_(name: 'A');
-    _checkLeastUpperBound(dynamicType, interfaceType(A), dynamicType);
+    _checkLeastUpperBound(dynamicType, interfaceTypeStar(A), dynamicType);
   }
 
   void test_dynamic_typeParam() {
@@ -2552,25 +2524,16 @@
 
   void test_interface_function() {
     var A = class_(name: 'A');
-    _checkLeastUpperBound(
-        interfaceType(A), functionTypeStar(returnType: voidType), objectType);
+    _checkLeastUpperBound(interfaceTypeStar(A),
+        functionTypeStar(returnType: voidType), objectType);
   }
 
   void test_interface_sameElement_nullability() {
     var aElement = class_(name: 'A');
 
-    var aQuestion = interfaceType(
-      aElement,
-      nullabilitySuffix: NullabilitySuffix.question,
-    );
-    var aStar = interfaceType(
-      aElement,
-      nullabilitySuffix: NullabilitySuffix.star,
-    );
-    var aNone = interfaceType(
-      aElement,
-      nullabilitySuffix: NullabilitySuffix.none,
-    );
+    var aQuestion = interfaceTypeQuestion(aElement);
+    var aStar = interfaceTypeStar(aElement);
+    var aNone = interfaceTypeNone(aElement);
 
     void assertLUB(DartType type1, DartType type2, DartType expected) {
       expect(typeSystem.getLeastUpperBound(type1, type2), expected);
@@ -2599,31 +2562,25 @@
       interfaces: [instA.withNullabilitySuffixNone],
     );
 
-    var mixinM = ElementFactory.mixinElement(
+    var mixinM = mixin_(
       name: 'M',
       constraints: [instA.withNullabilitySuffixNone],
     );
 
     _checkLeastUpperBound(
-      interfaceType(
-        classB,
-        nullabilitySuffix: NullabilitySuffix.star,
-      ),
-      interfaceType(
-        mixinM,
-        nullabilitySuffix: NullabilitySuffix.star,
-      ),
+      interfaceTypeStar(classB),
+      interfaceTypeStar(mixinM),
       instA.withNullability(NullabilitySuffix.star),
     );
   }
 
   void test_mixinAndClass_object() {
     var classA = class_(name: 'A');
-    var mixinM = ElementFactory.mixinElement(name: 'M');
+    var mixinM = mixin_(name: 'M');
 
     _checkLeastUpperBound(
-      interfaceType(classA),
-      interfaceType(mixinM),
+      interfaceTypeStar(classA),
+      interfaceTypeStar(mixinM),
       objectType,
     );
   }
@@ -2637,20 +2594,14 @@
       interfaces: [instA.withNullabilitySuffixNone],
     );
 
-    var mixinM = ElementFactory.mixinElement(
+    var mixinM = mixin_(
       name: 'M',
       interfaces: [instA.withNullabilitySuffixNone],
     );
 
     _checkLeastUpperBound(
-      interfaceType(
-        classB,
-        nullabilitySuffix: NullabilitySuffix.star,
-      ),
-      interfaceType(
-        mixinM,
-        nullabilitySuffix: NullabilitySuffix.star,
-      ),
+      interfaceTypeStar(classB),
+      interfaceTypeStar(mixinM),
       instA.withNullability(NullabilitySuffix.star),
     );
   }
@@ -2662,25 +2613,25 @@
     // class D extends B with M, N, O, P
 
     var A = class_(name: 'A');
-    var typeA = interfaceType(A);
+    var typeA = interfaceTypeStar(A);
 
     var B = class_(name: 'B', superType: typeA);
-    var typeB = interfaceType(B);
+    var typeB = interfaceTypeStar(B);
 
     var C = class_(name: 'C', superType: typeA);
-    var typeC = interfaceType(C);
+    var typeC = interfaceTypeStar(C);
 
     var D = class_(
       name: 'D',
       superType: typeB,
       mixins: [
-        interfaceType(class_(name: 'M')),
-        interfaceType(class_(name: 'N')),
-        interfaceType(class_(name: 'O')),
-        interfaceType(class_(name: 'P')),
+        interfaceTypeStar(class_(name: 'M')),
+        interfaceTypeStar(class_(name: 'N')),
+        interfaceTypeStar(class_(name: 'O')),
+        interfaceTypeStar(class_(name: 'P')),
       ],
     );
-    var typeD = interfaceType(D);
+    var typeD = interfaceTypeStar(D);
 
     _checkLeastUpperBound(typeD, typeC, typeA);
   }
@@ -2821,8 +2772,8 @@
   void test_object() {
     var A = class_(name: 'A');
     var B = class_(name: 'B');
-    var typeA = interfaceType(A);
-    var typeB = interfaceType(B);
+    var typeA = interfaceTypeStar(A);
+    var typeB = interfaceTypeStar(B);
     var typeObject = typeA.element.supertype;
     // assert that object does not have a super type
     expect(typeObject.element.supertype, isNull);
@@ -2841,7 +2792,7 @@
       voidType,
       neverStar,
       typeParameterTypeStar(T),
-      interfaceType(A),
+      interfaceTypeStar(A),
       functionTypeStar(returnType: voidType)
     ];
 
@@ -2852,31 +2803,22 @@
 
   void test_sharedSuperclass1() {
     var A = class_(name: 'A');
-    var typeA = interfaceType(A);
+    var typeA = interfaceTypeStar(A);
 
     var B = class_(name: 'B', superType: typeA);
-    var typeB = interfaceType(B);
+    var typeB = interfaceTypeStar(B);
 
     var C = class_(name: 'C', superType: typeA);
-    var typeC = interfaceType(C);
+    var typeC = interfaceTypeStar(C);
 
     _checkLeastUpperBound(typeB, typeC, typeA);
   }
 
   void test_sharedSuperclass1_nullability() {
     var aElement = class_(name: 'A');
-    var aQuestion = interfaceType(
-      aElement,
-      nullabilitySuffix: NullabilitySuffix.question,
-    );
-    var aStar = interfaceType(
-      aElement,
-      nullabilitySuffix: NullabilitySuffix.star,
-    );
-    var aNone = interfaceType(
-      aElement,
-      nullabilitySuffix: NullabilitySuffix.none,
-    );
+    var aQuestion = interfaceTypeQuestion(aElement);
+    var aStar = interfaceTypeStar(aElement);
+    var aNone = interfaceTypeNone(aElement);
 
     var bElementNone = class_(name: 'B', superType: aNone);
     var bElementStar = class_(name: 'B', superType: aStar);
@@ -2978,115 +2920,115 @@
 
   void test_sharedSuperclass2() {
     var A = class_(name: 'A');
-    var typeA = interfaceType(A);
+    var typeA = interfaceTypeStar(A);
 
     var B = class_(name: 'B', superType: typeA);
-    var typeB = interfaceType(B);
+    var typeB = interfaceTypeStar(B);
 
     var C = class_(name: 'C', superType: typeA);
-    var typeC = interfaceType(C);
+    var typeC = interfaceTypeStar(C);
 
     var D = class_(name: 'D', superType: typeC);
-    var typeD = interfaceType(D);
+    var typeD = interfaceTypeStar(D);
 
     _checkLeastUpperBound(typeB, typeD, typeA);
   }
 
   void test_sharedSuperclass3() {
     var A = class_(name: 'A');
-    var typeA = interfaceType(A);
+    var typeA = interfaceTypeStar(A);
 
     var B = class_(name: 'B', superType: typeA);
-    var typeB = interfaceType(B);
+    var typeB = interfaceTypeStar(B);
 
     var C = class_(name: 'C', superType: typeB);
-    var typeC = interfaceType(C);
+    var typeC = interfaceTypeStar(C);
 
     var D = class_(name: 'D', superType: typeB);
-    var typeD = interfaceType(D);
+    var typeD = interfaceTypeStar(D);
 
     _checkLeastUpperBound(typeC, typeD, typeB);
   }
 
   void test_sharedSuperclass4() {
     var A = class_(name: 'A');
-    var typeA = interfaceType(A);
+    var typeA = interfaceTypeStar(A);
 
     var A2 = class_(name: 'A2');
-    var typeA2 = interfaceType(A2);
+    var typeA2 = interfaceTypeStar(A2);
 
     var A3 = class_(name: 'A3');
-    var typeA3 = interfaceType(A3);
+    var typeA3 = interfaceTypeStar(A3);
 
     var B = class_(name: 'B', superType: typeA, interfaces: [typeA2]);
-    var typeB = interfaceType(B);
+    var typeB = interfaceTypeStar(B);
 
     var C = class_(name: 'C', superType: typeA, interfaces: [typeA3]);
-    var typeC = interfaceType(C);
+    var typeC = interfaceTypeStar(C);
 
     _checkLeastUpperBound(typeB, typeC, typeA);
   }
 
   void test_sharedSuperinterface1() {
     var A = class_(name: 'A');
-    var typeA = interfaceType(A);
+    var typeA = interfaceTypeStar(A);
 
     var B = class_(name: 'B', interfaces: [typeA]);
-    var typeB = interfaceType(B);
+    var typeB = interfaceTypeStar(B);
 
     var C = class_(name: 'C', interfaces: [typeA]);
-    var typeC = interfaceType(C);
+    var typeC = interfaceTypeStar(C);
 
     _checkLeastUpperBound(typeB, typeC, typeA);
   }
 
   void test_sharedSuperinterface2() {
     var A = class_(name: 'A');
-    var typeA = interfaceType(A);
+    var typeA = interfaceTypeStar(A);
 
     var B = class_(name: 'B', interfaces: [typeA]);
-    var typeB = interfaceType(B);
+    var typeB = interfaceTypeStar(B);
 
     var C = class_(name: 'C', interfaces: [typeA]);
-    var typeC = interfaceType(C);
+    var typeC = interfaceTypeStar(C);
 
     var D = class_(name: 'D', interfaces: [typeC]);
-    var typeD = interfaceType(D);
+    var typeD = interfaceTypeStar(D);
 
     _checkLeastUpperBound(typeB, typeD, typeA);
   }
 
   void test_sharedSuperinterface3() {
     var A = class_(name: 'A');
-    var typeA = interfaceType(A);
+    var typeA = interfaceTypeStar(A);
 
     var B = class_(name: 'B', interfaces: [typeA]);
-    var typeB = interfaceType(B);
+    var typeB = interfaceTypeStar(B);
 
     var C = class_(name: 'C', interfaces: [typeB]);
-    var typeC = interfaceType(C);
+    var typeC = interfaceTypeStar(C);
 
     var D = class_(name: 'D', interfaces: [typeB]);
-    var typeD = interfaceType(D);
+    var typeD = interfaceTypeStar(D);
 
     _checkLeastUpperBound(typeC, typeD, typeB);
   }
 
   void test_sharedSuperinterface4() {
     var A = class_(name: 'A');
-    var typeA = interfaceType(A);
+    var typeA = interfaceTypeStar(A);
 
     var A2 = class_(name: 'A2');
-    var typeA2 = interfaceType(A2);
+    var typeA2 = interfaceTypeStar(A2);
 
     var A3 = class_(name: 'A3');
-    var typeA3 = interfaceType(A3);
+    var typeA3 = interfaceTypeStar(A3);
 
     var B = class_(name: 'B', interfaces: [typeA, typeA2]);
-    var typeB = interfaceType(B);
+    var typeB = interfaceTypeStar(B);
 
     var C = class_(name: 'C', interfaces: [typeA, typeA3]);
-    var typeC = interfaceType(C);
+    var typeC = interfaceTypeStar(C);
 
     _checkLeastUpperBound(typeB, typeC, typeA);
   }
@@ -3107,7 +3049,7 @@
 
   void test_typeParam_class_implements_Function_ignored() {
     var A = class_(name: 'A', superType: typeProvider.functionType);
-    var T = typeParameter('T', bound: interfaceType(A));
+    var T = typeParameter('T', bound: interfaceTypeStar(A));
     _checkLeastUpperBound(typeParameterTypeStar(T),
         functionTypeStar(returnType: voidType), objectType);
   }
@@ -3118,16 +3060,16 @@
 
     var S = typeParameter('S');
     var typeS = typeParameterTypeStar(S);
-    S.bound = interfaceType(A, typeArguments: [typeS]);
+    S.bound = interfaceTypeStar(A, typeArguments: [typeS]);
 
     var U = typeParameter('U');
     var typeU = typeParameterTypeStar(U);
-    U.bound = interfaceType(A, typeArguments: [typeU]);
+    U.bound = interfaceTypeStar(A, typeArguments: [typeU]);
 
     _checkLeastUpperBound(
       typeS,
       typeParameterTypeStar(U),
-      interfaceType(A, typeArguments: [objectType]),
+      interfaceTypeStar(A, typeArguments: [objectType]),
     );
   }
 
@@ -3151,13 +3093,13 @@
 
   void test_typeParam_interface_bounded() {
     var A = class_(name: 'A');
-    var typeA = interfaceType(A);
+    var typeA = interfaceTypeStar(A);
 
     var B = class_(name: 'B', superType: typeA);
-    var typeB = interfaceType(B);
+    var typeB = interfaceTypeStar(B);
 
     var C = class_(name: 'C', superType: typeA);
-    var typeC = interfaceType(C);
+    var typeC = interfaceTypeStar(C);
 
     var T = typeParameter('T', bound: typeB);
     var typeT = typeParameterTypeStar(T);
@@ -3170,11 +3112,59 @@
     var A = class_(name: 'A');
     _checkLeastUpperBound(
       typeParameterTypeStar(T),
-      interfaceType(A),
+      interfaceTypeStar(A),
       objectType,
     );
   }
 
+  void test_typeParameters_contravariant_different() {
+    // class A<in T>
+    var T = typeParameter('T', variance: Variance.contravariant);
+    var A = class_(name: 'A', typeParameters: [T]);
+
+    // A<num>
+    // A<int>
+    var aNum = interfaceTypeStar(A, typeArguments: [numType]);
+    var aInt = interfaceTypeStar(A, typeArguments: [intType]);
+
+    _checkLeastUpperBound(aInt, aNum, aInt);
+  }
+
+  void test_typeParameters_contravariant_same() {
+    // class A<in T>
+    var T = typeParameter('T', variance: Variance.contravariant);
+    var A = class_(name: 'A', typeParameters: [T]);
+
+    // A<num>
+    var aNum = interfaceTypeStar(A, typeArguments: [numType]);
+
+    _checkLeastUpperBound(aNum, aNum, aNum);
+  }
+
+  void test_typeParameters_covariant_different() {
+    // class A<out T>
+    var T = typeParameter('T', variance: Variance.covariant);
+    var A = class_(name: 'A', typeParameters: [T]);
+
+    // A<num>
+    // A<int>
+    var aNum = interfaceTypeStar(A, typeArguments: [numType]);
+    var aInt = interfaceTypeStar(A, typeArguments: [intType]);
+
+    _checkLeastUpperBound(aInt, aNum, aNum);
+  }
+
+  void test_typeParameters_covariant_same() {
+    // class A<out T>
+    var T = typeParameter('T', variance: Variance.covariant);
+    var A = class_(name: 'A', typeParameters: [T]);
+
+    // A<num>
+    var aNum = interfaceTypeStar(A, typeArguments: [numType]);
+
+    _checkLeastUpperBound(aNum, aNum, aNum);
+  }
+
   /// Check least upper bound of the same class with different type parameters.
   void test_typeParameters_different() {
     // class List<int>
@@ -3185,6 +3175,89 @@
     _checkLeastUpperBound(listOfIntType, listOfDoubleType, listOfNum);
   }
 
+  void test_typeParameters_invariant_object() {
+    // class A<inout T>
+    var T = typeParameter('T', variance: Variance.invariant);
+    var A = class_(name: 'A', typeParameters: [T]);
+
+    // A<num>
+    // A<int>
+    var aNum = interfaceTypeStar(A, typeArguments: [numType]);
+    var aInt = interfaceTypeStar(A, typeArguments: [intType]);
+
+    _checkLeastUpperBound(aNum, aInt, objectType);
+  }
+
+  void test_typeParameters_invariant_same() {
+    // class A<inout T>
+    var T = typeParameter('T', variance: Variance.invariant);
+    var A = class_(name: 'A', typeParameters: [T]);
+
+    // A<num>
+    var aNum = interfaceTypeStar(A, typeArguments: [numType]);
+
+    _checkLeastUpperBound(aNum, aNum, aNum);
+  }
+
+  void test_typeParameters_multi_basic() {
+    // class Multi<out T, inout U, in V>
+    var T = typeParameter('T', variance: Variance.covariant);
+    var U = typeParameter('T', variance: Variance.invariant);
+    var V = typeParameter('T', variance: Variance.contravariant);
+    var Multi = class_(name: 'A', typeParameters: [T, U, V]);
+
+    // Multi<num, num, num>
+    // Multi<int, num, int>
+    var multiNumNumNum =
+        interfaceTypeStar(Multi, typeArguments: [numType, numType, numType]);
+    var multiIntNumInt =
+        interfaceTypeStar(Multi, typeArguments: [intType, numType, intType]);
+
+    // We expect Multi<num, num, int>
+    var multiNumNumInt =
+        interfaceTypeStar(Multi, typeArguments: [numType, numType, intType]);
+
+    _checkLeastUpperBound(multiNumNumNum, multiIntNumInt, multiNumNumInt);
+  }
+
+  void test_typeParameters_multi_objectInterface() {
+    // class Multi<out T, inout U, in V>
+    var T = typeParameter('T', variance: Variance.covariant);
+    var U = typeParameter('T', variance: Variance.invariant);
+    var V = typeParameter('T', variance: Variance.contravariant);
+    var Multi = class_(name: 'A', typeParameters: [T, U, V]);
+
+    // Multi<num, String, num>
+    // Multi<int, num, int>
+    var multiNumStringNum =
+        interfaceTypeStar(Multi, typeArguments: [numType, stringType, numType]);
+    var multiIntNumInt =
+        interfaceTypeStar(Multi, typeArguments: [intType, numType, intType]);
+
+    _checkLeastUpperBound(multiNumStringNum, multiIntNumInt, objectType);
+  }
+
+  void test_typeParameters_multi_objectType() {
+    // class Multi<out T, inout U, in V>
+    var T = typeParameter('T', variance: Variance.covariant);
+    var U = typeParameter('T', variance: Variance.invariant);
+    var V = typeParameter('T', variance: Variance.contravariant);
+    var Multi = class_(name: 'A', typeParameters: [T, U, V]);
+
+    // Multi<String, num, num>
+    // Multi<int, num, int>
+    var multiStringNumNum =
+        interfaceTypeStar(Multi, typeArguments: [stringType, numType, numType]);
+    var multiIntNumInt =
+        interfaceTypeStar(Multi, typeArguments: [intType, numType, intType]);
+
+    // We expect Multi<Object, num, int>
+    var multiObjectNumInt =
+        interfaceTypeStar(Multi, typeArguments: [objectType, numType, intType]);
+
+    _checkLeastUpperBound(multiStringNumNum, multiIntNumInt, multiObjectNumInt);
+  }
+
   void test_typeParameters_same() {
     // List<int>
     // List<int>
@@ -3209,7 +3282,7 @@
     List<DartType> types = [
       neverStar,
       functionTypeStar(returnType: voidType),
-      interfaceType(A),
+      interfaceTypeStar(A),
       typeParameterTypeStar(T),
     ];
     for (DartType type in types) {
@@ -3222,123 +3295,23 @@
   }
 }
 
-//class Mix with ElementsTypesMixin {
-//  TypeProvider typeProvider;
-//  Dart2TypeSystem typeSystem;
-//
-//  FeatureSet get testFeatureSet {
-//    return FeatureSet.forTesting();
-//  }
-//
-//  void setUp() {
-//    var analysisContext = TestAnalysisContext(
-//      featureSet: testFeatureSet,
-//    );
-//    typeProvider = analysisContext.typeProvider;
-//    typeSystem = analysisContext.typeSystem;
-//  }
-//}
-
-class SubtypingTestBase extends AbstractTypeSystemTest {
-  void _checkEquivalent(DartType type1, DartType type2) {
-    _checkIsSubtypeOf(type1, type2);
-    _checkIsSubtypeOf(type2, type1);
-  }
-
-  void _checkGroups(DartType t1,
-      {List<DartType> equivalents,
-      List<DartType> unrelated,
-      List<DartType> subtypes,
-      List<DartType> supertypes}) {
-    if (equivalents != null) {
-      for (DartType t2 in equivalents) {
-        _checkEquivalent(t1, t2);
-      }
-    }
-    if (unrelated != null) {
-      for (DartType t2 in unrelated) {
-        _checkUnrelated(t1, t2);
-      }
-    }
-    if (subtypes != null) {
-      for (DartType t2 in subtypes) {
-        _checkIsStrictSubtypeOf(t2, t1);
-      }
-    }
-    if (supertypes != null) {
-      for (DartType t2 in supertypes) {
-        _checkIsStrictSubtypeOf(t1, t2);
-      }
-    }
-  }
-
-  void _checkIsNotSubtypeOf(DartType type1, DartType type2) {
-    var strType1 = _toStringWithNullability(type1);
-    var strType2 = _toStringWithNullability(type2);
-    expect(typeSystem.isSubtypeOf(type1, type2), false,
-        reason: '$strType1 was not supposed to be a subtype of $strType2');
-  }
-
-  void _checkIsStrictSubtypeOf(DartType type1, DartType type2) {
-    _checkIsSubtypeOf(type1, type2);
-    _checkIsNotSubtypeOf(type2, type1);
-  }
-
-  void _checkIsSubtypeOf(DartType type1, DartType type2) {
-    expect(typeSystem.isSubtypeOf(type1, type2), true,
-        reason: '$type1 is not a subtype of $type2');
-  }
-
-  void _checkLattice(
-      DartType top, DartType left, DartType right, DartType bottom) {
-    _checkGroups(top,
-        equivalents: <DartType>[top],
-        subtypes: <DartType>[left, right, bottom]);
-    _checkGroups(left,
-        equivalents: <DartType>[left],
-        subtypes: <DartType>[bottom],
-        unrelated: <DartType>[right],
-        supertypes: <DartType>[top]);
-    _checkGroups(right,
-        equivalents: <DartType>[right],
-        subtypes: <DartType>[bottom],
-        unrelated: <DartType>[left],
-        supertypes: <DartType>[top]);
-    _checkGroups(bottom,
-        equivalents: <DartType>[bottom],
-        supertypes: <DartType>[top, left, right]);
-  }
-
-  void _checkUnrelated(DartType type1, DartType type2) {
-    _checkIsNotSubtypeOf(type1, type2);
-    _checkIsNotSubtypeOf(type2, type1);
-  }
-
-  static String _toStringWithNullability(DartType type) {
-    return (type as TypeImpl).toString(withNullability: true);
-  }
-}
-
 @reflectiveTest
 class TypeSystemTest extends AbstractTypeSystemTest {
   InterfaceTypeImpl get functionClassTypeNone {
-    return interfaceType(
+    return interfaceTypeNone(
       typeProvider.functionType.element,
-      nullabilitySuffix: NullabilitySuffix.none,
     );
   }
 
   InterfaceTypeImpl get functionClassTypeQuestion {
-    return interfaceType(
+    return interfaceTypeQuestion(
       typeProvider.functionType.element,
-      nullabilitySuffix: NullabilitySuffix.question,
     );
   }
 
   InterfaceTypeImpl get functionClassTypeStar {
-    return interfaceType(
+    return interfaceTypeStar(
       typeProvider.functionType.element,
-      nullabilitySuffix: NullabilitySuffix.star,
     );
   }
 
@@ -3379,75 +3352,60 @@
       .withNullability(NullabilitySuffix.star);
 
   InterfaceTypeImpl get stringClassTypeNone {
-    return interfaceType(
+    return interfaceTypeNone(
       typeProvider.stringType.element,
-      nullabilitySuffix: NullabilitySuffix.none,
     );
   }
 
   InterfaceTypeImpl get stringClassTypeQuestion {
-    return interfaceType(
+    return interfaceTypeQuestion(
       typeProvider.stringType.element,
-      nullabilitySuffix: NullabilitySuffix.question,
     );
   }
 
   InterfaceTypeImpl get stringClassTypeStar {
-    return interfaceType(
+    return interfaceTypeStar(
       typeProvider.stringType.element,
-      nullabilitySuffix: NullabilitySuffix.star,
     );
   }
 
   InterfaceTypeImpl futureOrTypeNone({@required DartType argument}) {
-    var element = typeProvider.futureOrElement;
-    return interfaceType(
-      element,
+    return typeProvider.futureOrElement.instantiate(
       typeArguments: <DartType>[argument],
       nullabilitySuffix: NullabilitySuffix.none,
     );
   }
 
   InterfaceTypeImpl futureOrTypeQuestion({@required DartType argument}) {
-    var element = typeProvider.futureOrElement;
-    return interfaceType(
-      element,
+    return typeProvider.futureOrElement.instantiate(
       typeArguments: <DartType>[argument],
       nullabilitySuffix: NullabilitySuffix.question,
     );
   }
 
   InterfaceTypeImpl futureOrTypeStar({@required DartType argument}) {
-    var element = typeProvider.futureOrElement;
-    return interfaceType(
-      element,
+    return typeProvider.futureOrElement.instantiate(
       typeArguments: <DartType>[argument],
       nullabilitySuffix: NullabilitySuffix.star,
     );
   }
 
   InterfaceTypeImpl listClassTypeNone(DartType argument) {
-    var element = typeProvider.listElement;
-    return interfaceType(
-      element,
+    return typeProvider.listElement.instantiate(
       typeArguments: <DartType>[argument],
       nullabilitySuffix: NullabilitySuffix.none,
     );
   }
 
   InterfaceTypeImpl listClassTypeQuestion(DartType argument) {
-    var element = typeProvider.listElement;
-    return interfaceType(
-      element,
+    return typeProvider.listElement.instantiate(
       typeArguments: <DartType>[argument],
       nullabilitySuffix: NullabilitySuffix.question,
     );
   }
 
   InterfaceTypeImpl listClassTypeStar(DartType argument) {
-    var element = typeProvider.listElement;
-    return interfaceType(
-      element,
+    return typeProvider.listElement.instantiate(
       typeArguments: <DartType>[argument],
       nullabilitySuffix: NullabilitySuffix.star,
     );
diff --git a/pkg/analyzer/test/source/error_processor_test.dart b/pkg/analyzer/test/source/error_processor_test.dart
index 71d8d5e..ec49f93 100644
--- a/pkg/analyzer/test/source/error_processor_test.dart
+++ b/pkg/analyzer/test/source/error_processor_test.dart
@@ -2,11 +2,14 @@
 // 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/analysis/declared_variables.dart';
 import 'package:analyzer/error/error.dart';
 import 'package:analyzer/source/error_processor.dart';
 import 'package:analyzer/src/analysis_options/analysis_options_provider.dart';
 import 'package:analyzer/src/context/context.dart';
+import 'package:analyzer/src/dart/analysis/session.dart';
 import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/task/options.dart';
 import 'package:test/test.dart';
 import 'package:yaml/yaml.dart';
@@ -157,4 +160,13 @@
 ErrorProcessor getProcessor(AnalysisError error) =>
     ErrorProcessor.getProcessor(context.analysisOptions, error);
 
-class TestContext extends AnalysisContextImpl {}
+class TestContext extends AnalysisContextImpl {
+  TestContext()
+      : super(
+          SynchronousSession(
+            AnalysisOptionsImpl(),
+            DeclaredVariables(),
+          ),
+          null,
+        );
+}
diff --git a/pkg/analyzer/test/src/context/builder_test.dart b/pkg/analyzer/test/src/context/builder_test.dart
index cfe7454..fccee0d 100644
--- a/pkg/analyzer/test/src/context/builder_test.dart
+++ b/pkg/analyzer/test/src/context/builder_test.dart
@@ -593,35 +593,6 @@
     expect(workspace, TypeMatcher<BasicWorkspace>());
   }
 
-  void test_declareVariables_emptyMap() {
-    AnalysisContext context = AnalysisEngine.instance.createAnalysisContext();
-    Iterable<String> expected = context.declaredVariables.variableNames;
-    builderOptions.declaredVariables = <String, String>{};
-
-    builder.declareVariables(context);
-    expect(context.declaredVariables.variableNames, unorderedEquals(expected));
-  }
-
-  void test_declareVariables_nonEmptyMap() {
-    AnalysisContext context = AnalysisEngine.instance.createAnalysisContext();
-    List<String> expected = context.declaredVariables.variableNames.toList();
-    expect(expected, isNot(contains('a')));
-    expect(expected, isNot(contains('b')));
-    expected.addAll(['a', 'b']);
-    builderOptions.declaredVariables = <String, String>{'a': 'a', 'b': 'b'};
-
-    builder.declareVariables(context);
-    expect(context.declaredVariables.variableNames, unorderedEquals(expected));
-  }
-
-  void test_declareVariables_null() {
-    AnalysisContext context = AnalysisEngine.instance.createAnalysisContext();
-    Iterable<String> expected = context.declaredVariables.variableNames;
-
-    builder.declareVariables(context);
-    expect(context.declaredVariables.variableNames, unorderedEquals(expected));
-  }
-
   @failingTest
   void test_findSdk_embedder_extensions() {
     // See test_createSourceFactory_noProvider_packages_embedder_extensions
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_resolution_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_resolution_test.dart
index 2bba18a..573749d 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_resolution_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_resolution_test.dart
@@ -833,10 +833,10 @@
     expect(atD.element, constructorD);
 
     expect(constC.staticElement, constructorC);
-    expect(constC.staticType, interfaceType(elementC));
+    expect(constC.staticType, interfaceTypeStar(elementC));
 
     expect(constC.constructorName.staticElement, constructorC);
-    expect(constC.constructorName.type.type, interfaceType(elementC));
+    expect(constC.constructorName.type.type, interfaceTypeStar(elementC));
   }
 
   test_annotation_unprefixed_topLevelVariable() async {
@@ -1468,7 +1468,7 @@
       expect(constructorName.staticElement, same(aUnnamed));
 
       TypeName typeName = constructorName.type;
-      expect(typeName.type, interfaceType(aElement));
+      expect(typeName.type, interfaceTypeStar(aElement));
 
       SimpleIdentifier identifier = typeName.name;
       expect(identifier.staticElement, same(aElement));
@@ -1488,7 +1488,7 @@
       expect(constructorName.staticElement, same(aNamed));
 
       TypeName typeName = constructorName.type;
-      expect(typeName.type, interfaceType(aElement));
+      expect(typeName.type, interfaceTypeStar(aElement));
 
       SimpleIdentifier identifier = typeName.name;
       expect(identifier.staticElement, same(aElement));
@@ -2217,7 +2217,7 @@
       VariableDeclaration aNode = aDeclaration.variables.variables[0];
       InstanceCreationExpression value = aNode.initializer;
       expect(value.staticElement, defaultConstructor);
-      expect(value.staticType, interfaceType(cElement));
+      expect(value.staticType, interfaceTypeStar(cElement));
 
       TypeName typeName = value.constructorName.type;
       expect(typeName.typeArguments, isNull);
@@ -2234,7 +2234,7 @@
       VariableDeclaration bNode = bDeclaration.variables.variables[0];
       InstanceCreationExpression value = bNode.initializer;
       expect(value.staticElement, namedConstructor);
-      expect(value.staticType, interfaceType(cElement));
+      expect(value.staticType, interfaceTypeStar(cElement));
 
       TypeName typeName = value.constructorName.type;
       expect(typeName.typeArguments, isNull);
@@ -2270,7 +2270,7 @@
     InstanceCreationExpression creation = vNode.initializer;
     List<Expression> arguments = creation.argumentList.arguments;
     expect(creation.staticElement, constructorElement);
-    expect(creation.staticType, interfaceType(xElement));
+    expect(creation.staticType, interfaceTypeStar(xElement));
 
     TypeName typeName = creation.constructorName.type;
     expect(typeName.typeArguments, isNull);
@@ -2310,7 +2310,7 @@
       VariableDeclaration aNode = aDeclaration.variables.variables[0];
       InstanceCreationExpression value = aNode.initializer;
       expect(value.staticElement, defaultConstructor);
-      expect(value.staticType, interfaceType(cElement));
+      expect(value.staticType, interfaceTypeStar(cElement));
 
       TypeName typeName = value.constructorName.type;
       expect(typeName.typeArguments, isNull);
@@ -2330,7 +2330,7 @@
       VariableDeclaration bNode = bDeclaration.variables.variables[0];
       InstanceCreationExpression value = bNode.initializer;
       expect(value.staticElement, namedConstructor);
-      expect(value.staticType, interfaceType(cElement));
+      expect(value.staticType, interfaceTypeStar(cElement));
 
       TypeName typeName = value.constructorName.type;
       expect(typeName.typeArguments, isNull);
@@ -2616,7 +2616,7 @@
       expect(creation.constructorName.name, isNull);
 
       Expression argument = creation.argumentList.arguments[0];
-      _assertArgumentToParameter(argument, defaultConstructor.parameters[0]);
+      _assertArgumentToParameter2(argument, 'int');
     }
 
     {
@@ -2638,7 +2638,7 @@
       assertType(constructorName, null);
 
       var argument = creation.argumentList.arguments[0];
-      _assertArgumentToParameter(argument, namedConstructor.parameters[0]);
+      _assertArgumentToParameter2(argument, 'num');
     }
   }
 
@@ -6295,7 +6295,7 @@
 
     SimpleIdentifier prefix = prefixed.prefix;
     expect(prefix.staticElement, same(vElement));
-    expect(prefix.staticType, interfaceType(cElement));
+    expect(prefix.staticType, interfaceTypeStar(cElement));
 
     SimpleIdentifier identifier = prefixed.identifier;
     expect(identifier.staticElement, same(fElement.getter));
@@ -6623,7 +6623,7 @@
 
       InstanceCreationExpression newC = access.target;
       expect(newC.staticElement, cClassElement.unnamedConstructor);
-      expect(newC.staticType, interfaceType(cClassElement));
+      expect(newC.staticType, interfaceTypeStar(cClassElement));
 
       expect(access.propertyName.staticElement, same(fElement.getter));
       expect(access.propertyName.staticType, typeProvider.intType);
@@ -6658,7 +6658,7 @@
 
       InstanceCreationExpression newC = access.target;
       expect(newC.staticElement, cClassElement.unnamedConstructor);
-      expect(newC.staticType, interfaceType(cClassElement));
+      expect(newC.staticType, interfaceTypeStar(cClassElement));
 
       expect(access.propertyName.staticElement, same(fElement.getter));
       expect(access.propertyName.staticType, typeProvider.intType);
@@ -6823,7 +6823,8 @@
       MethodInvocation invocation = statement.expression;
 
       SuperExpression target = invocation.target;
-      expect(target.staticType, interfaceType(bNode.declaredElement)); // raw
+      expect(
+          target.staticType, interfaceTypeStar(bNode.declaredElement)); // raw
 
       expect(invocation.methodName.staticElement, same(methodElement));
     }
@@ -6844,7 +6845,8 @@
       expect(propertyAccess.staticType, typeProvider.intType);
 
       SuperExpression target = propertyAccess.target;
-      expect(target.staticType, interfaceType(bNode.declaredElement)); // raw
+      expect(
+          target.staticType, interfaceTypeStar(bNode.declaredElement)); // raw
 
       expect(propertyAccess.propertyName.staticElement, same(getterElement));
       expect(propertyAccess.propertyName.staticType, typeProvider.intType);
@@ -6868,7 +6870,8 @@
       PropertyAccess propertyAccess = assignment.leftHandSide;
 
       SuperExpression target = propertyAccess.target;
-      expect(target.staticType, interfaceType(bNode.declaredElement)); // raw
+      expect(
+          target.staticType, interfaceTypeStar(bNode.declaredElement)); // raw
 
       expect(propertyAccess.propertyName.staticElement, same(setterElement));
       expect(propertyAccess.propertyName.staticType, typeProvider.intType);
@@ -6880,7 +6883,8 @@
       BinaryExpression binary = statement.expression;
 
       ThisExpression target = binary.leftOperand;
-      expect(target.staticType, interfaceType(bNode.declaredElement)); // raw
+      expect(
+          target.staticType, interfaceTypeStar(bNode.declaredElement)); // raw
 
       expect(binary.staticElement, same(operatorElement));
       expect(binary.staticType, typeProvider.intType);
@@ -6920,7 +6924,7 @@
     List<Statement> testStatements = testBody.block.statements;
 
     var elementA = findElement.class_('A');
-    var thisTypeA = interfaceType(elementA);
+    var thisTypeA = interfaceTypeStar(elementA);
 
     // method(1);
     {
@@ -7763,7 +7767,7 @@
       expect(tNode.declaredElement, same(cElement.typeParameters[0]));
 
       TypeName bound = tNode.bound;
-      expect(bound.type, interfaceType(aElement));
+      expect(bound.type, interfaceTypeStar(aElement));
 
       SimpleIdentifier boundIdentifier = bound.name;
       expect(boundIdentifier.staticElement, same(aElement));
@@ -7773,7 +7777,7 @@
     {
       var listElement = typeProvider.listElement;
       var listOfA = listElement.instantiate(
-        typeArguments: [interfaceType(aElement)],
+        typeArguments: [interfaceTypeStar(aElement)],
         nullabilitySuffix: NullabilitySuffix.star,
       );
 
@@ -7788,7 +7792,7 @@
       expect(listIdentifier.staticType, isNull);
 
       TypeName aTypeName = bound.typeArguments.arguments[0];
-      expect(aTypeName.type, interfaceType(aElement));
+      expect(aTypeName.type, interfaceTypeStar(aElement));
 
       SimpleIdentifier aIdentifier = aTypeName.name;
       expect(aIdentifier.staticElement, same(aElement));
@@ -8291,7 +8295,7 @@
     ExpressionStatement statement = statements[0];
 
     InstanceCreationExpression creation = statement.expression;
-    expect(creation.staticType, interfaceType(randomElement));
+    expect(creation.staticType, interfaceTypeStar(randomElement));
 
     ConstructorName constructorName = creation.constructorName;
 
diff --git a/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart b/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart
index a56c686..791e065 100644
--- a/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart
+++ b/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart
@@ -2706,6 +2706,18 @@
     _assertSource("E", AstTestFactory.typeParameter("E"));
   }
 
+  void test_visitTypeParameter_variance_covariant() {
+    _assertSource("out E", AstTestFactory.typeParameter3("E", "out"));
+  }
+
+  void test_visitTypeParameter_variance_contravariant() {
+    _assertSource("in E", AstTestFactory.typeParameter3("E", "in"));
+  }
+
+  void test_visitTypeParameter_variance_invariant() {
+    _assertSource("inout E", AstTestFactory.typeParameter3("E", "inout"));
+  }
+
   void test_visitTypeParameterList_multiple() {
     _assertSource("<E, F>", AstTestFactory.typeParameterList(["E", "F"]));
   }
diff --git a/pkg/analyzer/test/src/dart/ast/utilities_test.dart b/pkg/analyzer/test/src/dart/ast/utilities_test.dart
index bc1afd0..8f414bc 100644
--- a/pkg/analyzer/test/src/dart/ast/utilities_test.dart
+++ b/pkg/analyzer/test/src/dart/ast/utilities_test.dart
@@ -138,7 +138,7 @@
         ]);
 
     AdjacentStrings fromNode = createNode();
-    DartType staticType = interfaceType(ElementFactory.classElement2('B'));
+    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('B'));
     fromNode.staticType = staticType;
 
     AdjacentStrings toNode = createNode();
@@ -161,7 +161,7 @@
   void test_visitAsExpression() {
     AsExpression fromNode = AstTestFactory.asExpression(
         AstTestFactory.identifier3("x"), AstTestFactory.typeName4("A"));
-    DartType staticType = interfaceType(ElementFactory.classElement2('B'));
+    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('B'));
     fromNode.staticType = staticType;
     AsExpression toNode = AstTestFactory.asExpression(
         AstTestFactory.identifier3("x"), AstTestFactory.typeName4("A"));
@@ -174,7 +174,7 @@
         AstTestFactory.identifier3("a"),
         TokenType.PLUS_EQ,
         AstTestFactory.identifier3("b"));
-    DartType staticType = interfaceType(ElementFactory.classElement2('C'));
+    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
     MethodElement staticElement = ElementFactory.methodElement("+", staticType);
     fromNode.staticElement = staticElement;
     fromNode.staticType = staticType;
@@ -192,7 +192,7 @@
         AstTestFactory.identifier3("a"),
         TokenType.PLUS,
         AstTestFactory.identifier3("b"));
-    DartType staticType = interfaceType(ElementFactory.classElement2('C'));
+    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
     MethodElement staticElement = ElementFactory.methodElement("+", staticType);
     fromNode.staticElement = staticElement;
     fromNode.staticType = staticType;
@@ -207,7 +207,7 @@
 
   void test_visitBooleanLiteral() {
     BooleanLiteral fromNode = AstTestFactory.booleanLiteral(true);
-    DartType staticType = interfaceType(ElementFactory.classElement2('C'));
+    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
     fromNode.staticType = staticType;
     BooleanLiteral toNode = AstTestFactory.booleanLiteral(true);
     ResolutionCopier.copyResolutionData(fromNode, toNode);
@@ -217,7 +217,7 @@
   void test_visitCascadeExpression() {
     CascadeExpression fromNode = AstTestFactory.cascadeExpression(
         AstTestFactory.identifier3("a"), [AstTestFactory.identifier3("b")]);
-    DartType staticType = interfaceType(ElementFactory.classElement2('C'));
+    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
     fromNode.staticType = staticType;
     CascadeExpression toNode = AstTestFactory.cascadeExpression(
         AstTestFactory.identifier3("a"), [AstTestFactory.identifier3("b")]);
@@ -239,7 +239,7 @@
         AstTestFactory.identifier3("c"),
         AstTestFactory.identifier3("a"),
         AstTestFactory.identifier3("b"));
-    DartType staticType = interfaceType(ElementFactory.classElement2('C'));
+    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
     fromNode.staticType = staticType;
     ConditionalExpression toNode = AstTestFactory.conditionalExpression(
         AstTestFactory.identifier3("c"),
@@ -283,7 +283,7 @@
 
   void test_visitDoubleLiteral() {
     DoubleLiteral fromNode = AstTestFactory.doubleLiteral(1.0);
-    DartType staticType = interfaceType(ElementFactory.classElement2('C'));
+    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
     fromNode.staticType = staticType;
     DoubleLiteral toNode = AstTestFactory.doubleLiteral(1.0);
     ResolutionCopier.copyResolutionData(fromNode, toNode);
@@ -305,7 +305,7 @@
             loopVariable: AstTestFactory.declaredIdentifier3('a'),
             iterable: AstTestFactory.identifier3('b'));
 
-    DartType typeB = interfaceType(ElementFactory.classElement2('B'));
+    DartType typeB = interfaceTypeStar(ElementFactory.classElement2('B'));
 
     ForEachPartsWithDeclaration fromNode = createNode();
     (fromNode.iterable as SimpleIdentifier).staticType = typeB;
@@ -321,8 +321,8 @@
             identifier: AstTestFactory.identifier3('a'),
             iterable: AstTestFactory.identifier3('b'));
 
-    DartType typeA = interfaceType(ElementFactory.classElement2('A'));
-    DartType typeB = interfaceType(ElementFactory.classElement2('B'));
+    DartType typeA = interfaceTypeStar(ElementFactory.classElement2('A'));
+    DartType typeB = interfaceTypeStar(ElementFactory.classElement2('B'));
 
     ForEachPartsWithIdentifier fromNode = createNode();
     fromNode.identifier.staticType = typeA;
@@ -341,7 +341,7 @@
             iterable: AstTestFactory.identifier3('b')),
         body: AstTestFactory.identifier3('c'));
 
-    DartType typeC = interfaceType(ElementFactory.classElement2('C'));
+    DartType typeC = interfaceTypeStar(ElementFactory.classElement2('C'));
 
     ForElement fromNode = createNode();
     (fromNode.body as SimpleIdentifier).staticType = typeC;
@@ -359,8 +359,8 @@
             condition: AstTestFactory.identifier3('b'),
             updaters: [AstTestFactory.identifier3('c')]);
 
-    DartType typeB = interfaceType(ElementFactory.classElement2('B'));
-    DartType typeC = interfaceType(ElementFactory.classElement2('C'));
+    DartType typeB = interfaceTypeStar(ElementFactory.classElement2('B'));
+    DartType typeC = interfaceTypeStar(ElementFactory.classElement2('C'));
 
     ForPartsWithDeclarations fromNode = createNode();
     (fromNode.condition as SimpleIdentifier).staticType = typeB;
@@ -378,9 +378,9 @@
         condition: AstTestFactory.identifier3('b'),
         updaters: [AstTestFactory.identifier3('c')]);
 
-    DartType typeA = interfaceType(ElementFactory.classElement2('A'));
-    DartType typeB = interfaceType(ElementFactory.classElement2('B'));
-    DartType typeC = interfaceType(ElementFactory.classElement2('C'));
+    DartType typeA = interfaceTypeStar(ElementFactory.classElement2('A'));
+    DartType typeB = interfaceTypeStar(ElementFactory.classElement2('B'));
+    DartType typeC = interfaceTypeStar(ElementFactory.classElement2('C'));
 
     ForPartsWithExpression fromNode = createNode();
     (fromNode.initialization as SimpleIdentifier).staticType = typeA;
@@ -402,9 +402,9 @@
         body: AstTestFactory.expressionStatement(
             AstTestFactory.identifier3('c')));
 
-    DartType typeA = interfaceType(ElementFactory.classElement2('A'));
-    DartType typeB = interfaceType(ElementFactory.classElement2('B'));
-    DartType typeC = interfaceType(ElementFactory.classElement2('C'));
+    DartType typeA = interfaceTypeStar(ElementFactory.classElement2('A'));
+    DartType typeB = interfaceTypeStar(ElementFactory.classElement2('B'));
+    DartType typeC = interfaceTypeStar(ElementFactory.classElement2('C'));
 
     ForStatement fromNode = createNode();
     ForEachPartsWithIdentifier fromForLoopParts = fromNode.forLoopParts;
@@ -430,9 +430,9 @@
         AstTestFactory.formalParameterList(),
         AstTestFactory.emptyFunctionBody());
     MethodElement element = ElementFactory.methodElement(
-        "m", interfaceType(ElementFactory.classElement2('C')));
+        "m", interfaceTypeStar(ElementFactory.classElement2('C')));
     fromNode.declaredElement = element;
-    DartType staticType = interfaceType(ElementFactory.classElement2('C'));
+    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
     fromNode.staticType = staticType;
     FunctionExpression toNode = AstTestFactory.functionExpression2(
         AstTestFactory.formalParameterList(),
@@ -447,7 +447,7 @@
         AstTestFactory.functionExpressionInvocation(
             AstTestFactory.identifier3("f"));
     MethodElement staticElement = ElementFactory.methodElement(
-        "m", interfaceType(ElementFactory.classElement2('C')));
+        "m", interfaceTypeStar(ElementFactory.classElement2('C')));
     fromNode.staticElement = staticElement;
     FunctionExpressionInvocation toNode =
         AstTestFactory.functionExpressionInvocation(
@@ -469,9 +469,9 @@
         thenElement: AstTestFactory.identifier3('b'),
         elseElement: AstTestFactory.identifier3('c'));
 
-    DartType typeA = interfaceType(ElementFactory.classElement2('A'));
-    DartType typeB = interfaceType(ElementFactory.classElement2('B'));
-    DartType typeC = interfaceType(ElementFactory.classElement2('C'));
+    DartType typeA = interfaceTypeStar(ElementFactory.classElement2('A'));
+    DartType typeB = interfaceTypeStar(ElementFactory.classElement2('B'));
+    DartType typeC = interfaceTypeStar(ElementFactory.classElement2('C'));
 
     IfElement fromNode = createNode();
     (fromNode.condition as SimpleIdentifier).staticType = typeA;
@@ -499,11 +499,11 @@
     IndexExpression fromNode = AstTestFactory.indexExpression(
         AstTestFactory.identifier3("a"), AstTestFactory.integer(0));
     MethodElement staticElement = ElementFactory.methodElement(
-        "m", interfaceType(ElementFactory.classElement2('C')));
+        "m", interfaceTypeStar(ElementFactory.classElement2('C')));
     AuxiliaryElements auxiliaryElements = new AuxiliaryElements(staticElement);
     fromNode.auxiliaryElements = auxiliaryElements;
     fromNode.staticElement = staticElement;
-    DartType staticType = interfaceType(ElementFactory.classElement2('C'));
+    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
     fromNode.staticType = staticType;
     IndexExpression toNode = AstTestFactory.indexExpression(
         AstTestFactory.identifier3("a"), AstTestFactory.integer(0));
@@ -520,7 +520,7 @@
     ConstructorElement staticElement = ElementFactory.constructorElement2(
         ElementFactory.classElement2("C"), null);
     fromNode.staticElement = staticElement;
-    DartType staticType = interfaceType(ElementFactory.classElement2('C'));
+    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
     fromNode.staticType = staticType;
     InstanceCreationExpression toNode =
         AstTestFactory.instanceCreationExpression2(
@@ -532,7 +532,7 @@
 
   void test_visitIntegerLiteral() {
     IntegerLiteral fromNode = AstTestFactory.integer(2);
-    DartType staticType = interfaceType(ElementFactory.classElement2('C'));
+    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
     fromNode.staticType = staticType;
     IntegerLiteral toNode = AstTestFactory.integer(2);
     ResolutionCopier.copyResolutionData(fromNode, toNode);
@@ -542,7 +542,7 @@
   void test_visitIsExpression() {
     IsExpression fromNode = AstTestFactory.isExpression(
         AstTestFactory.identifier3("x"), false, AstTestFactory.typeName4("A"));
-    DartType staticType = interfaceType(ElementFactory.classElement2('C'));
+    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
     fromNode.staticType = staticType;
     IsExpression toNode = AstTestFactory.isExpression(
         AstTestFactory.identifier3("x"), false, AstTestFactory.typeName4("A"));
@@ -553,7 +553,7 @@
   void test_visitLibraryIdentifier() {
     LibraryIdentifier fromNode =
         AstTestFactory.libraryIdentifier([AstTestFactory.identifier3("lib")]);
-    DartType staticType = interfaceType(ElementFactory.classElement2('C'));
+    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
     fromNode.staticType = staticType;
     LibraryIdentifier toNode =
         AstTestFactory.libraryIdentifier([AstTestFactory.identifier3("lib")]);
@@ -569,9 +569,9 @@
         [AstTestFactory.identifier3('b')],
         null);
 
-    DartType typeA = interfaceType(ElementFactory.classElement2('A'));
-    DartType typeB = interfaceType(ElementFactory.classElement2('B'));
-    DartType typeC = interfaceType(ElementFactory.classElement2('C'));
+    DartType typeA = interfaceTypeStar(ElementFactory.classElement2('A'));
+    DartType typeB = interfaceTypeStar(ElementFactory.classElement2('B'));
+    DartType typeC = interfaceTypeStar(ElementFactory.classElement2('C'));
 
     ListLiteral fromNode = createNode();
     (fromNode.typeArguments.arguments[0] as TypeName).type = typeA;
@@ -587,7 +587,7 @@
 
   void test_visitMapLiteral() {
     SetOrMapLiteral fromNode = AstTestFactory.setOrMapLiteral(null, null);
-    DartType staticType = interfaceType(ElementFactory.classElement2('C'));
+    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
     fromNode.staticType = staticType;
     SetOrMapLiteral toNode = AstTestFactory.setOrMapLiteral(null, null);
     ResolutionCopier.copyResolutionData(fromNode, toNode);
@@ -608,7 +608,7 @@
   void test_visitNamedExpression() {
     NamedExpression fromNode =
         AstTestFactory.namedExpression2("n", AstTestFactory.integer(0));
-    DartType staticType = interfaceType(ElementFactory.classElement2('C'));
+    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
     fromNode.staticType = staticType;
     NamedExpression toNode =
         AstTestFactory.namedExpression2("n", AstTestFactory.integer(0));
@@ -618,7 +618,7 @@
 
   void test_visitNullLiteral() {
     NullLiteral fromNode = AstTestFactory.nullLiteral();
-    DartType staticType = interfaceType(ElementFactory.classElement2('C'));
+    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
     fromNode.staticType = staticType;
     NullLiteral toNode = AstTestFactory.nullLiteral();
     ResolutionCopier.copyResolutionData(fromNode, toNode);
@@ -628,7 +628,7 @@
   void test_visitParenthesizedExpression() {
     ParenthesizedExpression fromNode =
         AstTestFactory.parenthesizedExpression(AstTestFactory.integer(0));
-    DartType staticType = interfaceType(ElementFactory.classElement2('C'));
+    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
     fromNode.staticType = staticType;
     ParenthesizedExpression toNode =
         AstTestFactory.parenthesizedExpression(AstTestFactory.integer(0));
@@ -638,8 +638,8 @@
 
   void test_visitPartDirective() {
     PartDirective fromNode = AstTestFactory.partDirective2("part.dart");
-    LibraryElement element = new LibraryElementImpl.forNode(
-        null, null, AstTestFactory.libraryIdentifier2(["lib"]), true);
+    LibraryElement element =
+        new LibraryElementImpl(null, null, 'lib', -1, 0, true);
     fromNode.element = element;
     PartDirective toNode = AstTestFactory.partDirective2("part.dart");
     ResolutionCopier.copyResolutionData(fromNode, toNode);
@@ -649,8 +649,8 @@
   void test_visitPartOfDirective() {
     PartOfDirective fromNode = AstTestFactory.partOfDirective(
         AstTestFactory.libraryIdentifier2(["lib"]));
-    LibraryElement element = new LibraryElementImpl.forNode(
-        null, null, AstTestFactory.libraryIdentifier2(["lib"]), true);
+    LibraryElement element =
+        new LibraryElementImpl(null, null, 'lib', -1, 0, true);
     fromNode.element = element;
     PartOfDirective toNode = AstTestFactory.partOfDirective(
         AstTestFactory.libraryIdentifier2(["lib"]));
@@ -663,9 +663,9 @@
     PostfixExpression fromNode = AstTestFactory.postfixExpression(
         AstTestFactory.identifier3(variableName), TokenType.PLUS_PLUS);
     MethodElement staticElement = ElementFactory.methodElement(
-        "+", interfaceType(ElementFactory.classElement2('C')));
+        "+", interfaceTypeStar(ElementFactory.classElement2('C')));
     fromNode.staticElement = staticElement;
-    DartType staticType = interfaceType(ElementFactory.classElement2('C'));
+    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
     fromNode.staticType = staticType;
     PostfixExpression toNode = AstTestFactory.postfixExpression(
         AstTestFactory.identifier3(variableName), TokenType.PLUS_PLUS);
@@ -676,7 +676,7 @@
 
   void test_visitPrefixedIdentifier() {
     PrefixedIdentifier fromNode = AstTestFactory.identifier5("p", "f");
-    DartType staticType = interfaceType(ElementFactory.classElement2('C'));
+    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
     fromNode.staticType = staticType;
     PrefixedIdentifier toNode = AstTestFactory.identifier5("p", "f");
     ResolutionCopier.copyResolutionData(fromNode, toNode);
@@ -686,9 +686,9 @@
   void test_visitPrefixExpression() {
     PrefixExpression fromNode = AstTestFactory.prefixExpression(
         TokenType.PLUS_PLUS, AstTestFactory.identifier3("x"));
-    DartType staticType = interfaceType(ElementFactory.classElement2('C'));
+    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
     MethodElement staticElement = ElementFactory.methodElement(
-        "+", interfaceType(ElementFactory.classElement2('C')));
+        "+", interfaceTypeStar(ElementFactory.classElement2('C')));
     fromNode.staticElement = staticElement;
     fromNode.staticType = staticType;
     PrefixExpression toNode = AstTestFactory.prefixExpression(
@@ -701,7 +701,7 @@
   void test_visitPropertyAccess() {
     PropertyAccess fromNode =
         AstTestFactory.propertyAccess2(AstTestFactory.identifier3("x"), "y");
-    DartType staticType = interfaceType(ElementFactory.classElement2('C'));
+    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
     fromNode.staticType = staticType;
     PropertyAccess toNode =
         AstTestFactory.propertyAccess2(AstTestFactory.identifier3("x"), "y");
@@ -723,7 +723,7 @@
 
   void test_visitRethrowExpression() {
     RethrowExpression fromNode = AstTestFactory.rethrowExpression();
-    DartType staticType = interfaceType(ElementFactory.classElement2('C'));
+    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
     fromNode.staticType = staticType;
     RethrowExpression toNode = AstTestFactory.rethrowExpression();
     ResolutionCopier.copyResolutionData(fromNode, toNode);
@@ -736,10 +736,10 @@
             [AstTestFactory.typeName4('A'), AstTestFactory.typeName4('B')]),
         elements: [AstTestFactory.mapLiteralEntry3('c', 'd')]);
 
-    DartType typeA = interfaceType(ElementFactory.classElement2('A'));
-    DartType typeB = interfaceType(ElementFactory.classElement2('B'));
-    DartType typeC = interfaceType(ElementFactory.classElement2('C'));
-    DartType typeD = interfaceType(ElementFactory.classElement2('D'));
+    DartType typeA = interfaceTypeStar(ElementFactory.classElement2('A'));
+    DartType typeB = interfaceTypeStar(ElementFactory.classElement2('B'));
+    DartType typeC = interfaceTypeStar(ElementFactory.classElement2('C'));
+    DartType typeD = interfaceTypeStar(ElementFactory.classElement2('D'));
 
     SetOrMapLiteral fromNode = createNode();
     (fromNode.typeArguments.arguments[0] as TypeName).type = typeA;
@@ -763,8 +763,8 @@
             AstTestFactory.typeArgumentList([AstTestFactory.typeName4('A')]),
         elements: [AstTestFactory.identifier3('b')]);
 
-    DartType typeA = interfaceType(ElementFactory.classElement2('A'));
-    DartType typeB = interfaceType(ElementFactory.classElement2('B'));
+    DartType typeA = interfaceTypeStar(ElementFactory.classElement2('A'));
+    DartType typeB = interfaceTypeStar(ElementFactory.classElement2('B'));
 
     SetOrMapLiteral fromNode = createNode();
     (fromNode.typeArguments.arguments[0] as TypeName).type = typeA;
@@ -779,11 +779,11 @@
   void test_visitSimpleIdentifier() {
     SimpleIdentifier fromNode = AstTestFactory.identifier3("x");
     MethodElement staticElement = ElementFactory.methodElement(
-        "m", interfaceType(ElementFactory.classElement2('C')));
+        "m", interfaceTypeStar(ElementFactory.classElement2('C')));
     AuxiliaryElements auxiliaryElements = new AuxiliaryElements(staticElement);
     fromNode.auxiliaryElements = auxiliaryElements;
     fromNode.staticElement = staticElement;
-    DartType staticType = interfaceType(ElementFactory.classElement2('C'));
+    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
     fromNode.staticType = staticType;
     SimpleIdentifier toNode = AstTestFactory.identifier3("x");
     ResolutionCopier.copyResolutionData(fromNode, toNode);
@@ -794,7 +794,7 @@
 
   void test_visitSimpleStringLiteral() {
     SimpleStringLiteral fromNode = AstTestFactory.string2("abc");
-    DartType staticType = interfaceType(ElementFactory.classElement2('C'));
+    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
     fromNode.staticType = staticType;
     SimpleStringLiteral toNode = AstTestFactory.string2("abc");
     ResolutionCopier.copyResolutionData(fromNode, toNode);
@@ -808,7 +808,7 @@
         expression: astFactory.listLiteral(
             null, null, null, [AstTestFactory.identifier3('a')], null));
 
-    DartType typeA = interfaceType(ElementFactory.classElement2('A'));
+    DartType typeA = interfaceTypeStar(ElementFactory.classElement2('A'));
 
     SpreadElement fromNode = createNode();
     ((fromNode.expression as ListLiteral).elements[0] as SimpleIdentifier)
@@ -825,7 +825,7 @@
   void test_visitStringInterpolation() {
     StringInterpolation fromNode =
         AstTestFactory.string([AstTestFactory.interpolationString("a", "'a'")]);
-    DartType staticType = interfaceType(ElementFactory.classElement2('C'));
+    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
     fromNode.staticType = staticType;
     StringInterpolation toNode =
         AstTestFactory.string([AstTestFactory.interpolationString("a", "'a'")]);
@@ -847,7 +847,7 @@
 
   void test_visitSuperExpression() {
     SuperExpression fromNode = AstTestFactory.superExpression();
-    DartType staticType = interfaceType(ElementFactory.classElement2('C'));
+    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
     fromNode.staticType = staticType;
     SuperExpression toNode = AstTestFactory.superExpression();
     ResolutionCopier.copyResolutionData(fromNode, toNode);
@@ -856,7 +856,7 @@
 
   void test_visitSymbolLiteral() {
     SymbolLiteral fromNode = AstTestFactory.symbolLiteral(["s"]);
-    DartType staticType = interfaceType(ElementFactory.classElement2('C'));
+    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
     fromNode.staticType = staticType;
     SymbolLiteral toNode = AstTestFactory.symbolLiteral(["s"]);
     ResolutionCopier.copyResolutionData(fromNode, toNode);
@@ -865,7 +865,7 @@
 
   void test_visitThisExpression() {
     ThisExpression fromNode = AstTestFactory.thisExpression();
-    DartType staticType = interfaceType(ElementFactory.classElement2('C'));
+    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
     fromNode.staticType = staticType;
     ThisExpression toNode = AstTestFactory.thisExpression();
     ResolutionCopier.copyResolutionData(fromNode, toNode);
@@ -874,7 +874,7 @@
 
   void test_visitThrowExpression() {
     ThrowExpression fromNode = AstTestFactory.throwExpression();
-    DartType staticType = interfaceType(ElementFactory.classElement2('C'));
+    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
     fromNode.staticType = staticType;
     ThrowExpression toNode = AstTestFactory.throwExpression();
     ResolutionCopier.copyResolutionData(fromNode, toNode);
@@ -883,7 +883,7 @@
 
   void test_visitTypeName() {
     TypeName fromNode = AstTestFactory.typeName4("C");
-    DartType type = interfaceType(ElementFactory.classElement2('C'));
+    DartType type = interfaceTypeStar(ElementFactory.classElement2('C'));
     fromNode.type = type;
     TypeName toNode = AstTestFactory.typeName4("C");
     ResolutionCopier.copyResolutionData(fromNode, toNode);
@@ -892,11 +892,11 @@
 
   void _copyAndVerifyInvocation(
       InvocationExpression fromNode, InvocationExpression toNode) {
-    DartType staticType = interfaceType(ElementFactory.classElement2('C'));
+    DartType staticType = interfaceTypeStar(ElementFactory.classElement2('C'));
     fromNode.staticType = staticType;
 
     DartType staticInvokeType =
-        interfaceType(ElementFactory.classElement2('C'));
+        interfaceTypeStar(ElementFactory.classElement2('C'));
     fromNode.staticInvokeType = staticInvokeType;
 
     ResolutionCopier.copyResolutionData(fromNode, toNode);
diff --git a/pkg/analyzer/test/src/dart/element/element_test.dart b/pkg/analyzer/test/src/dart/element/element_test.dart
index 9ef159d..49b073d 100644
--- a/pkg/analyzer/test/src/dart/element/element_test.dart
+++ b/pkg/analyzer/test/src/dart/element/element_test.dart
@@ -11,7 +11,6 @@
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
 import 'package:analyzer/src/generated/resolver.dart';
-import 'package:analyzer/src/generated/testing/ast_test_factory.dart';
 import 'package:analyzer/src/generated/testing/element_factory.dart';
 import 'package:analyzer/src/generated/testing/test_type_provider.dart';
 import 'package:test/test.dart';
@@ -55,12 +54,12 @@
   void test_getAllSupertypes_interface() {
     ClassElement classA = class_(name: 'A');
     ClassElement classB =
-        ElementFactory.classElement("B", interfaceType(classA));
+        ElementFactory.classElement("B", interfaceTypeStar(classA));
     ClassElementImpl elementC = ElementFactory.classElement2("C");
     InterfaceType typeObject = classA.supertype;
-    InterfaceType typeA = interfaceType(classA);
-    InterfaceType typeB = interfaceType(classB);
-    InterfaceType typeC = interfaceType(elementC);
+    InterfaceType typeA = interfaceTypeStar(classA);
+    InterfaceType typeB = interfaceTypeStar(classB);
+    InterfaceType typeC = interfaceTypeStar(elementC);
     elementC.interfaces = <InterfaceType>[typeB];
     List<InterfaceType> supers = elementC.allSupertypes;
     List<InterfaceType> types = new List<InterfaceType>();
@@ -74,12 +73,12 @@
   void test_getAllSupertypes_mixins() {
     ClassElement classA = class_(name: 'A');
     ClassElement classB =
-        ElementFactory.classElement("B", interfaceType(classA));
+        ElementFactory.classElement("B", interfaceTypeStar(classA));
     var classC = ElementFactory.classElement2("C");
     InterfaceType typeObject = classA.supertype;
-    InterfaceType typeA = interfaceType(classA);
-    InterfaceType typeB = interfaceType(classB);
-    InterfaceType typeC = interfaceType(classC);
+    InterfaceType typeA = interfaceTypeStar(classA);
+    InterfaceType typeB = interfaceTypeStar(classB);
+    InterfaceType typeC = interfaceTypeStar(classC);
     classC.mixins = <InterfaceType>[typeB];
     List<InterfaceType> supers = classC.allSupertypes;
     List<InterfaceType> types = new List<InterfaceType>();
@@ -93,8 +92,8 @@
   void test_getAllSupertypes_recursive() {
     var classA = class_(name: 'A');
     ClassElementImpl classB =
-        ElementFactory.classElement("B", interfaceType(classA));
-    classA.supertype = interfaceType(classB);
+        ElementFactory.classElement("B", interfaceTypeStar(classA));
+    classA.supertype = interfaceTypeStar(classB);
     List<InterfaceType> supers = classB.allSupertypes;
     expect(supers, hasLength(1));
   }
@@ -131,7 +130,7 @@
     var classA = class_(name: 'A');
     classA.fields = <FieldElement>[
       ElementFactory.fieldElement(
-          "f", false, false, true, interfaceType(classA))
+          "f", false, false, true, interfaceTypeStar(classA))
     ];
     expect(classA.hasNonFinalField, isFalse);
   }
@@ -140,7 +139,7 @@
     var classA = class_(name: 'A');
     classA.fields = <FieldElement>[
       ElementFactory.fieldElement(
-          "f", false, true, false, interfaceType(classA))
+          "f", false, true, false, interfaceTypeStar(classA))
     ];
     expect(classA.hasNonFinalField, isFalse);
   }
@@ -148,8 +147,8 @@
   void test_hasNonFinalField_false_recursive() {
     var classA = class_(name: 'A');
     ClassElementImpl classB =
-        ElementFactory.classElement("B", interfaceType(classA));
-    classA.supertype = interfaceType(classB);
+        ElementFactory.classElement("B", interfaceTypeStar(classA));
+    classA.supertype = interfaceTypeStar(classB);
     expect(classA.hasNonFinalField, isFalse);
   }
 
@@ -157,7 +156,7 @@
     var classA = class_(name: 'A');
     classA.fields = <FieldElement>[
       ElementFactory.fieldElement(
-          "f", false, false, false, interfaceType(classA))
+          "f", false, false, false, interfaceTypeStar(classA))
     ];
     expect(classA.hasNonFinalField, isTrue);
   }
@@ -165,10 +164,10 @@
   void test_hasNonFinalField_true_inherited() {
     var classA = class_(name: 'A');
     ClassElementImpl classB =
-        ElementFactory.classElement("B", interfaceType(classA));
+        ElementFactory.classElement("B", interfaceTypeStar(classA));
     classA.fields = <FieldElement>[
       ElementFactory.fieldElement(
-          "f", false, false, false, interfaceType(classA))
+          "f", false, false, false, interfaceTypeStar(classA))
     ];
     expect(classB.hasNonFinalField, isTrue);
   }
@@ -280,7 +279,7 @@
         ElementFactory.methodElement(methodName, null);
     classA.methods = <MethodElement>[inheritedMethod];
     ClassElementImpl classB =
-        ElementFactory.classElement("B", interfaceType(classA));
+        ElementFactory.classElement("B", interfaceTypeStar(classA));
     MethodElementImpl method = ElementFactory.methodElement(methodName, null);
     method.isAbstract = true;
     classB.methods = <MethodElement>[method];
@@ -304,7 +303,7 @@
         ElementFactory.methodElement(methodName, null);
     classA.methods = <MethodElement>[inheritedMethod];
     ClassElementImpl classB =
-        ElementFactory.classElement("B", interfaceType(classA));
+        ElementFactory.classElement("B", interfaceTypeStar(classA));
     MethodElement method = ElementFactory.methodElement(methodName, null);
     classB.methods = <MethodElement>[method];
     (library.definingCompilationUnit as CompilationUnitElementImpl).types =
@@ -328,7 +327,7 @@
     inheritedMethod.isAbstract = true;
     classA.methods = <MethodElement>[inheritedMethod];
     ClassElementImpl classB =
-        ElementFactory.classElement("B", interfaceType(classA));
+        ElementFactory.classElement("B", interfaceTypeStar(classA));
     MethodElement method = ElementFactory.methodElement(methodName, null);
     classB.methods = <MethodElement>[method];
     (library.definingCompilationUnit as CompilationUnitElementImpl).types =
@@ -349,7 +348,7 @@
         ElementFactory.methodElement(methodName, null);
     classA.methods = <MethodElement>[inheritedMethod];
     ClassElementImpl classB =
-        ElementFactory.classElement("B", interfaceType(classA));
+        ElementFactory.classElement("B", interfaceTypeStar(classA));
     (library.definingCompilationUnit as CompilationUnitElementImpl).types =
         <ClassElement>[classA, classB];
     expect(classB.lookUpConcreteMethod(methodName, library),
@@ -394,7 +393,7 @@
         ElementFactory.getterElement(getterName, false, null);
     classA.accessors = <PropertyAccessorElement>[getter];
     ClassElementImpl classB =
-        ElementFactory.classElement("B", interfaceType(classA));
+        ElementFactory.classElement("B", interfaceTypeStar(classA));
     (library.definingCompilationUnit as CompilationUnitElementImpl).types =
         <ClassElement>[classA, classB];
     expect(classB.lookUpGetter(getterName, library), same(getter));
@@ -418,8 +417,8 @@
     LibraryElementImpl library = _newLibrary();
     var classA = class_(name: 'A');
     ClassElementImpl classB =
-        ElementFactory.classElement("B", interfaceType(classA));
-    classA.supertype = interfaceType(classB);
+        ElementFactory.classElement("B", interfaceTypeStar(classA));
+    classA.supertype = interfaceTypeStar(classB);
     (library.definingCompilationUnit as CompilationUnitElementImpl).types =
         <ClassElement>[classA, classB];
     expect(classA.lookUpGetter("g", library), isNull);
@@ -453,7 +452,7 @@
         ElementFactory.getterElement(getterName, false, null);
     classA.accessors = <PropertyAccessorElement>[inheritedGetter];
     ClassElementImpl classB =
-        ElementFactory.classElement("B", interfaceType(classA));
+        ElementFactory.classElement("B", interfaceTypeStar(classA));
     (library.definingCompilationUnit as CompilationUnitElementImpl).types =
         <ClassElement>[classA, classB];
     expect(classB.lookUpInheritedConcreteGetter(getterName, library),
@@ -478,8 +477,8 @@
     LibraryElementImpl library = _newLibrary();
     var classA = class_(name: 'A');
     ClassElementImpl classB =
-        ElementFactory.classElement("B", interfaceType(classA));
-    classA.supertype = interfaceType(classB);
+        ElementFactory.classElement("B", interfaceTypeStar(classA));
+    classA.supertype = interfaceTypeStar(classB);
     (library.definingCompilationUnit as CompilationUnitElementImpl).types =
         <ClassElement>[classA, classB];
     expect(classA.lookUpInheritedConcreteGetter("g", library), isNull);
@@ -513,7 +512,7 @@
         ElementFactory.methodElement(methodName, null);
     classA.methods = <MethodElement>[inheritedMethod];
     ClassElementImpl classB =
-        ElementFactory.classElement("B", interfaceType(classA));
+        ElementFactory.classElement("B", interfaceTypeStar(classA));
     MethodElementImpl method = ElementFactory.methodElement(methodName, null);
     method.isAbstract = true;
     classB.methods = <MethodElement>[method];
@@ -537,7 +536,7 @@
         ElementFactory.methodElement(methodName, null);
     classA.methods = <MethodElement>[inheritedMethod];
     ClassElementImpl classB =
-        ElementFactory.classElement("B", interfaceType(classA));
+        ElementFactory.classElement("B", interfaceTypeStar(classA));
     MethodElement method = ElementFactory.methodElement(methodName, null);
     classB.methods = <MethodElement>[method];
     (library.definingCompilationUnit as CompilationUnitElementImpl).types =
@@ -562,7 +561,7 @@
     inheritedMethod.isAbstract = true;
     classA.methods = <MethodElement>[inheritedMethod];
     ClassElementImpl classB =
-        ElementFactory.classElement("B", interfaceType(classA));
+        ElementFactory.classElement("B", interfaceTypeStar(classA));
     MethodElement method = ElementFactory.methodElement(methodName, null);
     classB.methods = <MethodElement>[method];
     (library.definingCompilationUnit as CompilationUnitElementImpl).types =
@@ -588,13 +587,13 @@
         ElementFactory.methodElement(methodName, null);
     classA.methods = <MethodElement>[inheritedMethod];
     ClassElementImpl classB =
-        ElementFactory.classElement("B", interfaceType(classA));
+        ElementFactory.classElement("B", interfaceTypeStar(classA));
     MethodElementImpl abstractMethod =
         ElementFactory.methodElement(methodName, null);
     abstractMethod.isAbstract = true;
     classB.methods = <MethodElement>[abstractMethod];
     ClassElementImpl classC =
-        ElementFactory.classElement("C", interfaceType(classB));
+        ElementFactory.classElement("C", interfaceTypeStar(classB));
     MethodElementImpl method = ElementFactory.methodElement(methodName, null);
     classC.methods = <MethodElement>[method];
     (library.definingCompilationUnit as CompilationUnitElementImpl).types =
@@ -616,7 +615,7 @@
         ElementFactory.methodElement(methodName, null);
     classA.methods = <MethodElement>[inheritedMethod];
     ClassElementImpl classB =
-        ElementFactory.classElement("B", interfaceType(classA));
+        ElementFactory.classElement("B", interfaceTypeStar(classA));
     (library.definingCompilationUnit as CompilationUnitElementImpl).types =
         <ClassElement>[classA, classB];
     expect(classB.lookUpInheritedConcreteMethod(methodName, library),
@@ -661,7 +660,7 @@
         ElementFactory.setterElement(setterName, false, null);
     classA.accessors = <PropertyAccessorElement>[setter];
     ClassElementImpl classB =
-        ElementFactory.classElement("B", interfaceType(classA));
+        ElementFactory.classElement("B", interfaceTypeStar(classA));
     (library.definingCompilationUnit as CompilationUnitElementImpl).types =
         <ClassElement>[classA, classB];
     expect(classB.lookUpInheritedConcreteSetter(setterName, library),
@@ -686,8 +685,8 @@
     LibraryElementImpl library = _newLibrary();
     var classA = class_(name: 'A');
     ClassElementImpl classB =
-        ElementFactory.classElement("B", interfaceType(classA));
-    classA.supertype = interfaceType(classB);
+        ElementFactory.classElement("B", interfaceTypeStar(classA));
+    classA.supertype = interfaceTypeStar(classB);
     (library.definingCompilationUnit as CompilationUnitElementImpl).types =
         <ClassElement>[classA, classB];
     expect(classA.lookUpInheritedConcreteSetter("s", library), isNull);
@@ -721,7 +720,7 @@
         ElementFactory.methodElement(methodName, null);
     classA.methods = <MethodElement>[inheritedMethod];
     ClassElementImpl classB =
-        ElementFactory.classElement("B", interfaceType(classA));
+        ElementFactory.classElement("B", interfaceTypeStar(classA));
     MethodElement method = ElementFactory.methodElement(methodName, null);
     classB.methods = <MethodElement>[method];
     (library.definingCompilationUnit as CompilationUnitElementImpl).types =
@@ -743,7 +742,7 @@
         ElementFactory.methodElement(methodName, null);
     classA.methods = <MethodElement>[inheritedMethod];
     ClassElementImpl classB =
-        ElementFactory.classElement("B", interfaceType(classA));
+        ElementFactory.classElement("B", interfaceTypeStar(classA));
     (library.definingCompilationUnit as CompilationUnitElementImpl).types =
         <ClassElement>[classA, classB];
     expect(classB.lookUpInheritedMethod(methodName, library),
@@ -778,7 +777,7 @@
     MethodElement method = ElementFactory.methodElement(methodName, null);
     classA.methods = <MethodElement>[method];
     ClassElementImpl classB =
-        ElementFactory.classElement("B", interfaceType(classA));
+        ElementFactory.classElement("B", interfaceTypeStar(classA));
     (library.definingCompilationUnit as CompilationUnitElementImpl).types =
         <ClassElement>[classA, classB];
     expect(classB.lookUpMethod(methodName, library), same(method));
@@ -796,8 +795,8 @@
     LibraryElementImpl library = _newLibrary();
     var classA = class_(name: 'A');
     ClassElementImpl classB =
-        ElementFactory.classElement("B", interfaceType(classA));
-    classA.supertype = interfaceType(classB);
+        ElementFactory.classElement("B", interfaceTypeStar(classA));
+    classA.supertype = interfaceTypeStar(classB);
     (library.definingCompilationUnit as CompilationUnitElementImpl).types =
         <ClassElement>[classA, classB];
     expect(classA.lookUpMethod("m", library), isNull);
@@ -831,7 +830,7 @@
         ElementFactory.setterElement(setterName, false, null);
     classA.accessors = <PropertyAccessorElement>[setter];
     ClassElementImpl classB =
-        ElementFactory.classElement("B", interfaceType(classA));
+        ElementFactory.classElement("B", interfaceTypeStar(classA));
     (library.definingCompilationUnit as CompilationUnitElementImpl).types =
         <ClassElement>[classA, classB];
     expect(classB.lookUpSetter(setterName, library), same(setter));
@@ -855,8 +854,8 @@
     LibraryElementImpl library = _newLibrary();
     var classA = class_(name: 'A');
     ClassElementImpl classB =
-        ElementFactory.classElement("B", interfaceType(classA));
-    classA.supertype = interfaceType(classB);
+        ElementFactory.classElement("B", interfaceTypeStar(classA));
+    classA.supertype = interfaceTypeStar(classB);
     (library.definingCompilationUnit as CompilationUnitElementImpl).types =
         <ClassElement>[classA, classB];
     expect(classA.lookUpSetter("s", library), isNull);
@@ -1263,8 +1262,7 @@
     ClassElementImpl definingClass = ElementFactory.classElement2("C", ["E"]);
     TypeParameterType parameterType =
         typeParameterType(definingClass.typeParameters[0]);
-    MethodElementImpl functionElement =
-        new MethodElementImpl.forNode(AstTestFactory.identifier3("m"));
+    MethodElementImpl functionElement = new MethodElementImpl('m', -1);
     String namedParameterName = "c";
     functionElement.parameters = <ParameterElement>[
       ElementFactory.requiredParameter2("a", parameterType),
@@ -1274,8 +1272,8 @@
     functionElement.returnType = parameterType;
     definingClass.methods = <MethodElement>[functionElement];
     FunctionTypeImpl functionType = functionElement.type;
-    InterfaceTypeImpl argumentType = new InterfaceTypeImpl(
-        new ClassElementImpl.forNode(AstTestFactory.identifier3("D")));
+    InterfaceTypeImpl argumentType =
+        new InterfaceTypeImpl(new ClassElementImpl('D', -1));
     FunctionType result = functionType
         .substitute2(<DartType>[argumentType], <DartType>[parameterType]);
     expect(result.returnType, argumentType);
@@ -1292,16 +1290,14 @@
 
   @deprecated
   void test_substitute2_notEqual() {
-    DartType returnType = new InterfaceTypeImpl(
-        new ClassElementImpl.forNode(AstTestFactory.identifier3("R")));
-    DartType normalParameterType = new InterfaceTypeImpl(
-        new ClassElementImpl.forNode(AstTestFactory.identifier3("A")));
-    DartType optionalParameterType = new InterfaceTypeImpl(
-        new ClassElementImpl.forNode(AstTestFactory.identifier3("B")));
-    DartType namedParameterType = new InterfaceTypeImpl(
-        new ClassElementImpl.forNode(AstTestFactory.identifier3("C")));
-    FunctionElementImpl functionElement =
-        new FunctionElementImpl.forNode(AstTestFactory.identifier3("f"));
+    DartType returnType = new InterfaceTypeImpl(new ClassElementImpl('R', -1));
+    DartType normalParameterType =
+        new InterfaceTypeImpl(new ClassElementImpl('A', -1));
+    DartType optionalParameterType =
+        new InterfaceTypeImpl(new ClassElementImpl('B', -1));
+    DartType namedParameterType =
+        new InterfaceTypeImpl(new ClassElementImpl('C', -1));
+    FunctionElementImpl functionElement = new FunctionElementImpl('f', -1);
     String namedParameterName = "c";
     functionElement.parameters = <ParameterElement>[
       ElementFactory.requiredParameter2("a", normalParameterType),
@@ -1310,10 +1306,10 @@
     ];
     functionElement.returnType = returnType;
     FunctionTypeImpl functionType = functionElement.type;
-    InterfaceTypeImpl argumentType = new InterfaceTypeImpl(
-        new ClassElementImpl.forNode(AstTestFactory.identifier3("D")));
-    TypeParameterTypeImpl parameterType = new TypeParameterTypeImpl(
-        new TypeParameterElementImpl.forNode(AstTestFactory.identifier3("E")));
+    InterfaceTypeImpl argumentType =
+        new InterfaceTypeImpl(new ClassElementImpl('D', -1));
+    TypeParameterTypeImpl parameterType =
+        new TypeParameterTypeImpl(new TypeParameterElementImpl('E', -1));
     FunctionType result = functionType
         .substitute2(<DartType>[argumentType], <DartType>[parameterType]);
     expect(result.returnType, returnType);
@@ -1367,14 +1363,14 @@
 
     var AofC = A.instantiate(
       typeArguments: [
-        interfaceType(C),
+        interfaceTypeStar(C),
       ],
       nullabilitySuffix: NullabilitySuffix.star,
     );
 
     B.interfaces = <InterfaceType>[AofC];
 
-    InterfaceTypeImpl targetType = interfaceType(B);
+    InterfaceTypeImpl targetType = interfaceTypeStar(B);
     InterfaceType result = targetType.asInstanceOf(A);
     expect(result, AofC);
   }
@@ -1401,14 +1397,14 @@
     var C = class_(name: 'C');
 
     InterfaceTypeImpl targetType = B.instantiate(
-      typeArguments: [interfaceType(C)],
+      typeArguments: [interfaceTypeStar(C)],
       nullabilitySuffix: NullabilitySuffix.star,
     );
     InterfaceType result = targetType.asInstanceOf(A);
     expect(
       result,
       A.instantiate(
-        typeArguments: [interfaceType(C)],
+        typeArguments: [interfaceTypeStar(C)],
         nullabilitySuffix: NullabilitySuffix.star,
       ),
     );
@@ -1471,7 +1467,7 @@
     PropertyAccessorElement getterG =
         ElementFactory.getterElement(getterName, false, null);
     classA.accessors = <PropertyAccessorElement>[getterG];
-    InterfaceType typeA = interfaceType(classA);
+    InterfaceType typeA = interfaceTypeStar(classA);
     expect(typeA.getGetter(getterName), same(getterG));
   }
 
@@ -1490,7 +1486,7 @@
     //
     // A<I>
     //
-    InterfaceType I = interfaceType(class_(name: 'I'));
+    InterfaceType I = interfaceTypeStar(class_(name: 'I'));
     InterfaceTypeImpl AofI = A.instantiate(
       typeArguments: [I],
       nullabilitySuffix: NullabilitySuffix.star,
@@ -1507,7 +1503,7 @@
     // class A {}
     //
     var classA = class_(name: 'A');
-    InterfaceType typeA = interfaceType(classA);
+    InterfaceType typeA = interfaceTypeStar(classA);
     expect(typeA.getGetter("g"), isNull);
   }
 
@@ -1516,12 +1512,12 @@
     // class C implements A, B
     //
     var classA = class_(name: 'A');
-    InterfaceType typeA = interfaceType(classA);
+    InterfaceType typeA = interfaceTypeStar(classA);
     var classB = ElementFactory.classElement2("B");
-    InterfaceType typeB = interfaceType(classB);
+    InterfaceType typeB = interfaceTypeStar(classB);
     var classC = ElementFactory.classElement2("C");
     classC.interfaces = <InterfaceType>[typeA, typeB];
-    List<InterfaceType> interfaces = interfaceType(classC).interfaces;
+    List<InterfaceType> interfaces = interfaceTypeStar(classC).interfaces;
     expect(interfaces, hasLength(2));
     if (identical(interfaces[0], typeA)) {
       expect(interfaces[1], same(typeB));
@@ -1552,8 +1548,8 @@
     //
     // B<I>
     //
-    InterfaceType typeI = interfaceType(class_(name: 'I'));
-    InterfaceTypeImpl typeBI = interfaceType(B, typeArguments: [typeI]);
+    InterfaceType typeI = interfaceTypeStar(class_(name: 'I'));
+    InterfaceTypeImpl typeBI = interfaceTypeStar(B, typeArguments: [typeI]);
 
     List<InterfaceType> interfaces = typeBI.interfaces;
     expect(interfaces, hasLength(1));
@@ -1570,7 +1566,7 @@
     String methodName = "m";
     MethodElementImpl methodM = ElementFactory.methodElement(methodName, null);
     classA.methods = <MethodElement>[methodM];
-    InterfaceType typeA = interfaceType(classA);
+    InterfaceType typeA = interfaceTypeStar(classA);
     expect(typeA.getMethod(methodName), same(methodM));
   }
 
@@ -1580,7 +1576,7 @@
     // class B {}
     //
     var classA = ElementFactory.classElement2("A", ["E"]);
-    InterfaceType typeB = interfaceType(class_(name: 'B'));
+    InterfaceType typeB = interfaceTypeStar(class_(name: 'B'));
     String methodName = "m";
     MethodElementImpl methodM =
         ElementFactory.methodElement(methodName, typeB, []);
@@ -1588,7 +1584,7 @@
     //
     // A<I>
     //
-    InterfaceType typeI = interfaceType(class_(name: 'I'));
+    InterfaceType typeI = interfaceTypeStar(class_(name: 'I'));
     InterfaceTypeImpl typeAI =
         new InterfaceTypeImpl.explicit(classA, <DartType>[typeI]);
     MethodElement method = typeAI.getMethod(methodName);
@@ -1611,7 +1607,7 @@
     //
     // A<I>
     //
-    InterfaceType typeI = interfaceType(class_(name: 'I'));
+    InterfaceType typeI = interfaceTypeStar(class_(name: 'I'));
     InterfaceTypeImpl typeAI =
         new InterfaceTypeImpl.explicit(A, <DartType>[typeI]);
     MethodElement method = typeAI.getMethod(methodName);
@@ -1629,7 +1625,7 @@
     // class A {}
     //
     var classA = class_(name: 'A');
-    InterfaceType typeA = interfaceType(classA);
+    InterfaceType typeA = interfaceTypeStar(classA);
     expect(typeA.getMethod("m"), isNull);
   }
 
@@ -1653,12 +1649,12 @@
     // class C extends Object with A, B
     //
     var classA = class_(name: 'A');
-    InterfaceType typeA = interfaceType(classA);
+    InterfaceType typeA = interfaceTypeStar(classA);
     var classB = ElementFactory.classElement2("B");
-    InterfaceType typeB = interfaceType(classB);
+    InterfaceType typeB = interfaceTypeStar(classB);
     var classC = ElementFactory.classElement2("C");
     classC.mixins = <InterfaceType>[typeA, typeB];
-    List<InterfaceType> interfaces = interfaceType(classC).mixins;
+    List<InterfaceType> interfaces = interfaceTypeStar(classC).mixins;
     expect(interfaces, hasLength(2));
     if (identical(interfaces[0], typeA)) {
       expect(interfaces[1], same(typeB));
@@ -1681,7 +1677,7 @@
       name: 'B',
       typeParameters: [F],
       mixins: [
-        interfaceType(A, typeArguments: [
+        interfaceTypeStar(A, typeArguments: [
           typeParameterType(F),
         ]),
       ],
@@ -1689,7 +1685,7 @@
     //
     // B<I>
     //
-    InterfaceType typeI = interfaceType(class_(name: 'I'));
+    InterfaceType typeI = interfaceTypeStar(class_(name: 'I'));
     InterfaceTypeImpl typeBI =
         new InterfaceTypeImpl.explicit(B, <DartType>[typeI]);
     List<InterfaceType> interfaces = typeBI.mixins;
@@ -1708,7 +1704,7 @@
     PropertyAccessorElement setterS =
         ElementFactory.setterElement(setterName, false, null);
     classA.accessors = <PropertyAccessorElement>[setterS];
-    InterfaceType typeA = interfaceType(classA);
+    InterfaceType typeA = interfaceTypeStar(classA);
     expect(typeA.getSetter(setterName), same(setterS));
   }
 
@@ -1726,7 +1722,7 @@
     //
     // A<I>
     //
-    InterfaceType typeI = interfaceType(class_(name: 'I'));
+    InterfaceType typeI = interfaceTypeStar(class_(name: 'I'));
     InterfaceTypeImpl typeAI =
         new InterfaceTypeImpl.explicit(A, <DartType>[typeI]);
     PropertyAccessorElement setter = typeAI.getSetter(setterName);
@@ -1742,7 +1738,7 @@
     // class A {}
     //
     var classA = class_(name: 'A');
-    InterfaceType typeA = interfaceType(classA);
+    InterfaceType typeA = interfaceTypeStar(classA);
     expect(typeA.getSetter("s"), isNull);
   }
 
@@ -1751,9 +1747,9 @@
     // class B extends A
     //
     var classA = class_(name: 'A');
-    InterfaceType typeA = interfaceType(classA);
+    InterfaceType typeA = interfaceTypeStar(classA);
     var classB = ElementFactory.classElement("B", typeA);
-    InterfaceType typeB = interfaceType(classB);
+    InterfaceType typeB = interfaceTypeStar(classB);
     expect(typeB.superclass, same(typeA));
   }
 
@@ -1771,14 +1767,14 @@
     var B = class_(
       name: 'B',
       typeParameters: [F],
-      superType: interfaceType(A, typeArguments: [typeF]),
+      superType: interfaceTypeStar(A, typeArguments: [typeF]),
     );
 
     var classB = B;
     //
     // B<I>
     //
-    InterfaceType typeI = interfaceType(class_(name: 'I'));
+    InterfaceType typeI = interfaceTypeStar(class_(name: 'I'));
     InterfaceTypeImpl typeBI =
         new InterfaceTypeImpl.explicit(classB, <DartType>[typeI]);
     InterfaceType superclass = typeBI.superclass;
@@ -1787,13 +1783,13 @@
   }
 
   void test_getTypeArguments_empty() {
-    InterfaceType type = interfaceType(ElementFactory.classElement2('A'));
+    InterfaceType type = interfaceTypeStar(ElementFactory.classElement2('A'));
     expect(type.typeArguments, hasLength(0));
   }
 
   void test_hashCode() {
     ClassElement classA = class_(name: 'A');
-    InterfaceType typeA = interfaceType(classA);
+    InterfaceType typeA = interfaceTypeStar(classA);
     expect(0 == typeA.hashCode, isFalse);
   }
 
@@ -1806,7 +1802,7 @@
     PropertyAccessorElement getterG =
         ElementFactory.getterElement(getterName, false, null);
     classA.accessors = <PropertyAccessorElement>[getterG];
-    InterfaceType typeA = interfaceType(classA);
+    InterfaceType typeA = interfaceTypeStar(classA);
     LibraryElementImpl library =
         ElementFactory.library(_analysisContext, "lib");
     CompilationUnitElement unit = library.definingCompilationUnit;
@@ -1825,8 +1821,8 @@
         ElementFactory.getterElement(getterName, false, null);
     classA.accessors = <PropertyAccessorElement>[getterG];
     ClassElementImpl classB =
-        ElementFactory.classElement("B", interfaceType(classA));
-    InterfaceType typeB = interfaceType(classB);
+        ElementFactory.classElement("B", interfaceTypeStar(classA));
+    InterfaceType typeB = interfaceTypeStar(classB);
     LibraryElementImpl library =
         ElementFactory.library(_analysisContext, "lib");
     CompilationUnitElement unit = library.definingCompilationUnit;
@@ -1853,16 +1849,17 @@
         getterName, false, typeProvider.dynamicType);
     classM2.accessors = <PropertyAccessorElement>[getterM2g];
     ClassElementImpl classC =
-        ElementFactory.classElement('C', interfaceType(classB));
+        ElementFactory.classElement('C', interfaceTypeStar(classB));
     classC.mixins = <InterfaceType>[
-      interfaceType(classM1),
-      interfaceType(classM2)
+      interfaceTypeStar(classM1),
+      interfaceTypeStar(classM2)
     ];
     LibraryElementImpl library =
         ElementFactory.library(_analysisContext, "lib");
     CompilationUnitElementImpl unit = library.definingCompilationUnit;
     unit.types = <ClassElement>[classB, classM1, classM2, classC];
-    expect(interfaceType(classC).lookUpGetter(getterName, library), getterM2g);
+    expect(
+        interfaceTypeStar(classC).lookUpGetter(getterName, library), getterM2g);
   }
 
   void test_lookUpGetter_recursive() {
@@ -1871,9 +1868,9 @@
     // class B extends A {}
     //
     var classA = class_(name: 'A');
-    InterfaceType typeA = interfaceType(classA);
+    InterfaceType typeA = interfaceTypeStar(classA);
     var classB = ElementFactory.classElement("B", typeA);
-    classA.supertype = interfaceType(classB);
+    classA.supertype = interfaceTypeStar(classB);
     LibraryElementImpl library =
         ElementFactory.library(_analysisContext, "lib");
     CompilationUnitElement unit = library.definingCompilationUnit;
@@ -1886,7 +1883,7 @@
     // class A {}
     //
     var classA = class_(name: 'A');
-    InterfaceType typeA = interfaceType(classA);
+    InterfaceType typeA = interfaceTypeStar(classA);
     LibraryElementImpl library =
         ElementFactory.library(_analysisContext, "lib");
     CompilationUnitElement unit = library.definingCompilationUnit;
@@ -1902,7 +1899,7 @@
     String methodName = "m";
     MethodElementImpl methodM = ElementFactory.methodElement(methodName, null);
     classA.methods = <MethodElement>[methodM];
-    InterfaceType typeA = interfaceType(classA);
+    InterfaceType typeA = interfaceTypeStar(classA);
     LibraryElementImpl library =
         ElementFactory.library(_analysisContext, "lib");
     CompilationUnitElement unit = library.definingCompilationUnit;
@@ -1920,8 +1917,8 @@
     MethodElementImpl methodM = ElementFactory.methodElement(methodName, null);
     classA.methods = <MethodElement>[methodM];
     ClassElementImpl classB =
-        ElementFactory.classElement("B", interfaceType(classA));
-    InterfaceType typeB = interfaceType(classB);
+        ElementFactory.classElement("B", interfaceTypeStar(classA));
+    InterfaceType typeB = interfaceTypeStar(classB);
     LibraryElementImpl library =
         ElementFactory.library(_analysisContext, "lib");
     CompilationUnitElement unit = library.definingCompilationUnit;
@@ -1947,16 +1944,17 @@
         ElementFactory.methodElement(methodName, null);
     classM2.methods = <MethodElement>[methodM2m];
     ClassElementImpl classC =
-        ElementFactory.classElement('C', interfaceType(classB));
+        ElementFactory.classElement('C', interfaceTypeStar(classB));
     classC.mixins = <InterfaceType>[
-      interfaceType(classM1),
-      interfaceType(classM2)
+      interfaceTypeStar(classM1),
+      interfaceTypeStar(classM2)
     ];
     LibraryElementImpl library =
         ElementFactory.library(_analysisContext, "lib");
     CompilationUnitElementImpl unit = library.definingCompilationUnit;
     unit.types = <ClassElement>[classB, classM1, classM2, classC];
-    expect(interfaceType(classC).lookUpMethod(methodName, library), methodM2m);
+    expect(
+        interfaceTypeStar(classC).lookUpMethod(methodName, library), methodM2m);
   }
 
   void test_lookUpMethod_parameterized() {
@@ -1976,7 +1974,7 @@
     var B = class_(
       name: 'B',
       typeParameters: [F],
-      superType: interfaceType(A, typeArguments: [
+      superType: interfaceTypeStar(A, typeArguments: [
         typeParameterType(F),
       ]),
     );
@@ -1987,7 +1985,7 @@
     //
     // B<I>
     //
-    InterfaceType typeI = interfaceType(class_(name: 'I'));
+    InterfaceType typeI = interfaceTypeStar(class_(name: 'I'));
     InterfaceTypeImpl typeBI =
         new InterfaceTypeImpl.explicit(B, <DartType>[typeI]);
     MethodElement method = typeBI.lookUpMethod(methodName, library);
@@ -2005,9 +2003,9 @@
     // class B extends A {}
     //
     var classA = class_(name: 'A');
-    InterfaceType typeA = interfaceType(classA);
+    InterfaceType typeA = interfaceTypeStar(classA);
     var classB = ElementFactory.classElement("B", typeA);
-    classA.supertype = interfaceType(classB);
+    classA.supertype = interfaceTypeStar(classB);
     LibraryElementImpl library =
         ElementFactory.library(_analysisContext, "lib");
     CompilationUnitElement unit = library.definingCompilationUnit;
@@ -2020,7 +2018,7 @@
     // class A {}
     //
     var classA = class_(name: 'A');
-    InterfaceType typeA = interfaceType(classA);
+    InterfaceType typeA = interfaceTypeStar(classA);
     LibraryElementImpl library =
         ElementFactory.library(_analysisContext, "lib");
     CompilationUnitElement unit = library.definingCompilationUnit;
@@ -2037,7 +2035,7 @@
     PropertyAccessorElement setterS =
         ElementFactory.setterElement(setterName, false, null);
     classA.accessors = <PropertyAccessorElement>[setterS];
-    InterfaceType typeA = interfaceType(classA);
+    InterfaceType typeA = interfaceTypeStar(classA);
     LibraryElementImpl library =
         ElementFactory.library(_analysisContext, "lib");
     CompilationUnitElement unit = library.definingCompilationUnit;
@@ -2056,8 +2054,8 @@
         ElementFactory.setterElement(setterName, false, null);
     classA.accessors = <PropertyAccessorElement>[setterS];
     ClassElementImpl classB =
-        ElementFactory.classElement("B", interfaceType(classA));
-    InterfaceType typeB = interfaceType(classB);
+        ElementFactory.classElement("B", interfaceTypeStar(classA));
+    InterfaceType typeB = interfaceTypeStar(classB);
     LibraryElementImpl library =
         ElementFactory.library(_analysisContext, "lib");
     CompilationUnitElement unit = library.definingCompilationUnit;
@@ -2084,16 +2082,17 @@
         setterName, false, typeProvider.dynamicType);
     classM2.accessors = <PropertyAccessorElement>[setterM2g];
     ClassElementImpl classC =
-        ElementFactory.classElement('C', interfaceType(classB));
+        ElementFactory.classElement('C', interfaceTypeStar(classB));
     classC.mixins = <InterfaceType>[
-      interfaceType(classM1),
-      interfaceType(classM2)
+      interfaceTypeStar(classM1),
+      interfaceTypeStar(classM2)
     ];
     LibraryElementImpl library =
         ElementFactory.library(_analysisContext, "lib");
     CompilationUnitElementImpl unit = library.definingCompilationUnit;
     unit.types = <ClassElement>[classB, classM1, classM2, classC];
-    expect(interfaceType(classC).lookUpGetter(setterName, library), setterM2g);
+    expect(
+        interfaceTypeStar(classC).lookUpGetter(setterName, library), setterM2g);
   }
 
   void test_lookUpSetter_recursive() {
@@ -2102,9 +2101,9 @@
     // class B extends A {}
     //
     var classA = class_(name: 'A');
-    InterfaceType typeA = interfaceType(classA);
+    InterfaceType typeA = interfaceTypeStar(classA);
     var classB = ElementFactory.classElement("B", typeA);
-    classA.supertype = interfaceType(classB);
+    classA.supertype = interfaceTypeStar(classB);
     LibraryElementImpl library =
         ElementFactory.library(_analysisContext, "lib");
     CompilationUnitElement unit = library.definingCompilationUnit;
@@ -2117,7 +2116,7 @@
     // class A {}
     //
     var classA = class_(name: 'A');
-    InterfaceType typeA = interfaceType(classA);
+    InterfaceType typeA = interfaceTypeStar(classA);
     LibraryElementImpl library =
         ElementFactory.library(_analysisContext, "lib");
     CompilationUnitElement unit = library.definingCompilationUnit;
@@ -2126,7 +2125,8 @@
   }
 
   void test_resolveToBound() {
-    InterfaceTypeImpl type = interfaceType(ElementFactory.classElement2('A'));
+    InterfaceTypeImpl type =
+        interfaceTypeStar(ElementFactory.classElement2('A'));
 
     // Returns this.
     expect(type.resolveToBound(null), same(type));
@@ -2137,7 +2137,7 @@
     try {
       var classA = class_(name: 'A');
       InterfaceTypeImpl type = new InterfaceTypeImpl(classA);
-      InterfaceType argumentType = interfaceType(class_(name: 'B'));
+      InterfaceType argumentType = interfaceTypeStar(class_(name: 'B'));
       type.substitute2(<DartType>[argumentType], <DartType>[]);
       fail(
           "Expected to encounter exception, argument and parameter type array lengths not equal.");
@@ -2152,14 +2152,14 @@
     // implementation.
     var classA = class_(name: 'A');
     TypeParameterElementImpl parameterElement =
-        new TypeParameterElementImpl.forNode(AstTestFactory.identifier3("E"));
+        new TypeParameterElementImpl('E', -1);
     TypeParameterTypeImpl parameter =
         new TypeParameterTypeImpl(parameterElement);
     InterfaceTypeImpl type =
         new InterfaceTypeImpl.explicit(classA, <DartType>[parameter]);
-    InterfaceType argumentType = interfaceType(class_(name: 'B'));
-    TypeParameterTypeImpl parameterType = new TypeParameterTypeImpl(
-        new TypeParameterElementImpl.forNode(AstTestFactory.identifier3("F")));
+    InterfaceType argumentType = interfaceTypeStar(class_(name: 'B'));
+    TypeParameterTypeImpl parameterType =
+        new TypeParameterTypeImpl(new TypeParameterElementImpl('F', -1));
     InterfaceType result =
         type.substitute2(<DartType>[argumentType], <DartType>[parameterType]);
     expect(result.element, classA);
@@ -2171,23 +2171,14 @@
 
 @reflectiveTest
 class LibraryElementImplTest {
-  void test_creation() {
-    expect(
-        new LibraryElementImpl.forNode(TestAnalysisContext(), null,
-            AstTestFactory.libraryIdentifier2(["l"]), true),
-        isNotNull);
-  }
-
   void test_getImportedLibraries() {
     AnalysisContext context = TestAnalysisContext();
     LibraryElementImpl library1 = ElementFactory.library(context, "l1");
     LibraryElementImpl library2 = ElementFactory.library(context, "l2");
     LibraryElementImpl library3 = ElementFactory.library(context, "l3");
     LibraryElementImpl library4 = ElementFactory.library(context, "l4");
-    PrefixElement prefixA =
-        new PrefixElementImpl.forNode(AstTestFactory.identifier3("a"));
-    PrefixElement prefixB =
-        new PrefixElementImpl.forNode(AstTestFactory.identifier3("b"));
+    PrefixElement prefixA = new PrefixElementImpl('a', -1);
+    PrefixElement prefixB = new PrefixElementImpl('b', -1);
     List<ImportElementImpl> imports = [
       ElementFactory.importFor(library2, null),
       ElementFactory.importFor(library2, prefixB),
@@ -2205,10 +2196,8 @@
   void test_getPrefixes() {
     AnalysisContext context = TestAnalysisContext();
     LibraryElementImpl library = ElementFactory.library(context, "l1");
-    PrefixElement prefixA =
-        new PrefixElementImpl.forNode(AstTestFactory.identifier3("a"));
-    PrefixElement prefixB =
-        new PrefixElementImpl.forNode(AstTestFactory.identifier3("b"));
+    PrefixElement prefixA = new PrefixElementImpl('a', -1);
+    PrefixElement prefixB = new PrefixElementImpl('b', -1);
     List<ImportElementImpl> imports = [
       ElementFactory.importFor(ElementFactory.library(context, "l2"), null),
       ElementFactory.importFor(ElementFactory.library(context, "l3"), null),
@@ -2242,8 +2231,8 @@
 
   void test_setImports() {
     AnalysisContext context = TestAnalysisContext();
-    LibraryElementImpl library = new LibraryElementImpl.forNode(
-        context, null, AstTestFactory.libraryIdentifier2(["l1"]), true);
+    LibraryElementImpl library =
+        new LibraryElementImpl(context, null, 'l1', -1, 0, true);
     List<ImportElementImpl> expectedImports = [
       ElementFactory.importFor(ElementFactory.library(context, "l2"), null),
       ElementFactory.importFor(ElementFactory.library(context, "l3"), null)
@@ -2284,33 +2273,28 @@
 @reflectiveTest
 class TypeParameterTypeImplTest extends AbstractTypeTest {
   void test_creation() {
-    expect(
-        new TypeParameterTypeImpl(new TypeParameterElementImpl.forNode(
-            AstTestFactory.identifier3("E"))),
+    expect(new TypeParameterTypeImpl(new TypeParameterElementImpl('E', -1)),
         isNotNull);
   }
 
   void test_getElement() {
-    TypeParameterElementImpl element =
-        new TypeParameterElementImpl.forNode(AstTestFactory.identifier3("E"));
+    TypeParameterElementImpl element = new TypeParameterElementImpl('E', -1);
     TypeParameterTypeImpl type = new TypeParameterTypeImpl(element);
     expect(type.element, element);
   }
 
   void test_resolveToBound_bound() {
     ClassElementImpl classS = class_(name: 'A');
-    TypeParameterElementImpl element =
-        new TypeParameterElementImpl.forNode(AstTestFactory.identifier3("E"));
-    element.bound = interfaceType(classS);
+    TypeParameterElementImpl element = new TypeParameterElementImpl('E', -1);
+    element.bound = interfaceTypeStar(classS);
     TypeParameterTypeImpl type = new TypeParameterTypeImpl(element);
-    expect(type.resolveToBound(null), interfaceType(classS));
+    expect(type.resolveToBound(null), interfaceTypeStar(classS));
   }
 
   void test_resolveToBound_bound_nullableInner() {
     ClassElementImpl classS = class_(name: 'A');
-    TypeParameterElementImpl element =
-        new TypeParameterElementImpl.forNode(AstTestFactory.identifier3("E"));
-    element.bound = (interfaceType(classS) as TypeImpl)
+    TypeParameterElementImpl element = new TypeParameterElementImpl('E', -1);
+    element.bound = (interfaceTypeStar(classS) as TypeImpl)
         .withNullability(NullabilitySuffix.question);
     TypeParameterTypeImpl type = new TypeParameterTypeImpl(element);
     expect(type.resolveToBound(null), same(element.bound));
@@ -2318,9 +2302,8 @@
 
   void test_resolveToBound_bound_nullableInnerOuter() {
     ClassElementImpl classS = class_(name: 'A');
-    TypeParameterElementImpl element =
-        new TypeParameterElementImpl.forNode(AstTestFactory.identifier3("E"));
-    element.bound = (interfaceType(classS) as TypeImpl)
+    TypeParameterElementImpl element = new TypeParameterElementImpl('E', -1);
+    element.bound = (interfaceTypeStar(classS) as TypeImpl)
         .withNullability(NullabilitySuffix.question);
     TypeParameterTypeImpl type = new TypeParameterTypeImpl(element)
         .withNullability(NullabilitySuffix.question);
@@ -2329,36 +2312,33 @@
 
   void test_resolveToBound_bound_nullableInnerStarOuter() {
     ClassElementImpl classS = class_(name: 'A');
-    TypeParameterElementImpl element =
-        new TypeParameterElementImpl.forNode(AstTestFactory.identifier3("E"));
-    element.bound = (interfaceType(classS) as TypeImpl)
+    TypeParameterElementImpl element = new TypeParameterElementImpl('E', -1);
+    element.bound = (interfaceTypeStar(classS) as TypeImpl)
         .withNullability(NullabilitySuffix.star);
     TypeParameterTypeImpl type = new TypeParameterTypeImpl(element)
         .withNullability(NullabilitySuffix.question);
     expect(
         type.resolveToBound(null),
-        equals((interfaceType(classS) as TypeImpl)
+        equals((interfaceTypeStar(classS) as TypeImpl)
             .withNullability(NullabilitySuffix.question)));
   }
 
   void test_resolveToBound_bound_nullableOuter() {
     ClassElementImpl classS = class_(name: 'A');
-    TypeParameterElementImpl element =
-        new TypeParameterElementImpl.forNode(AstTestFactory.identifier3("E"));
-    element.bound = interfaceType(classS);
+    TypeParameterElementImpl element = new TypeParameterElementImpl('E', -1);
+    element.bound = interfaceTypeStar(classS);
     TypeParameterTypeImpl type = new TypeParameterTypeImpl(element)
         .withNullability(NullabilitySuffix.question);
     expect(
         type.resolveToBound(null),
-        equals((interfaceType(classS) as TypeImpl)
+        equals((interfaceTypeStar(classS) as TypeImpl)
             .withNullability(NullabilitySuffix.question)));
   }
 
   void test_resolveToBound_bound_starInner() {
     ClassElementImpl classS = class_(name: 'A');
-    TypeParameterElementImpl element =
-        new TypeParameterElementImpl.forNode(AstTestFactory.identifier3("E"));
-    element.bound = (interfaceType(classS) as TypeImpl)
+    TypeParameterElementImpl element = new TypeParameterElementImpl('E', -1);
+    element.bound = (interfaceTypeStar(classS) as TypeImpl)
         .withNullability(NullabilitySuffix.star);
     TypeParameterTypeImpl type = new TypeParameterTypeImpl(element);
     expect(type.resolveToBound(null), same(element.bound));
@@ -2366,9 +2346,8 @@
 
   void test_resolveToBound_bound_starInnerNullableOuter() {
     ClassElementImpl classS = class_(name: 'A');
-    TypeParameterElementImpl element =
-        new TypeParameterElementImpl.forNode(AstTestFactory.identifier3("E"));
-    element.bound = (interfaceType(classS) as TypeImpl)
+    TypeParameterElementImpl element = new TypeParameterElementImpl('E', -1);
+    element.bound = (interfaceTypeStar(classS) as TypeImpl)
         .withNullability(NullabilitySuffix.question);
     TypeParameterTypeImpl type = new TypeParameterTypeImpl(element)
         .withNullability(NullabilitySuffix.star);
@@ -2377,33 +2356,30 @@
 
   void test_resolveToBound_bound_starOuter() {
     ClassElementImpl classS = class_(name: 'A');
-    TypeParameterElementImpl element =
-        new TypeParameterElementImpl.forNode(AstTestFactory.identifier3("E"));
-    element.bound = interfaceType(classS);
+    TypeParameterElementImpl element = new TypeParameterElementImpl('E', -1);
+    element.bound = interfaceTypeStar(classS);
     TypeParameterTypeImpl type = new TypeParameterTypeImpl(element)
         .withNullability(NullabilitySuffix.star);
     expect(
         type.resolveToBound(null),
-        (interfaceType(classS) as TypeImpl)
+        (interfaceTypeStar(classS) as TypeImpl)
             .withNullability(NullabilitySuffix.star));
   }
 
   void test_resolveToBound_nestedBound() {
     ClassElementImpl classS = class_(name: 'A');
-    TypeParameterElementImpl elementE =
-        new TypeParameterElementImpl.forNode(AstTestFactory.identifier3("E"));
-    elementE.bound = interfaceType(classS);
+    TypeParameterElementImpl elementE = new TypeParameterElementImpl('E', -1);
+    elementE.bound = interfaceTypeStar(classS);
     TypeParameterTypeImpl typeE = new TypeParameterTypeImpl(elementE);
-    TypeParameterElementImpl elementF =
-        new TypeParameterElementImpl.forNode(AstTestFactory.identifier3("F"));
+    TypeParameterElementImpl elementF = new TypeParameterElementImpl('F', -1);
     elementF.bound = typeE;
     TypeParameterTypeImpl typeF = new TypeParameterTypeImpl(elementE);
-    expect(typeF.resolveToBound(null), interfaceType(classS));
+    expect(typeF.resolveToBound(null), interfaceTypeStar(classS));
   }
 
   void test_resolveToBound_unbound() {
-    TypeParameterTypeImpl type = new TypeParameterTypeImpl(
-        new TypeParameterElementImpl.forNode(AstTestFactory.identifier3("E")));
+    TypeParameterTypeImpl type =
+        new TypeParameterTypeImpl(new TypeParameterElementImpl('E', -1));
     // Returns whatever type is passed to resolveToBound().
     expect(type.resolveToBound(VoidTypeImpl.instance),
         same(VoidTypeImpl.instance));
@@ -2411,11 +2387,10 @@
 
   @deprecated
   void test_substitute_equal() {
-    TypeParameterElementImpl element =
-        new TypeParameterElementImpl.forNode(AstTestFactory.identifier3("E"));
+    TypeParameterElementImpl element = new TypeParameterElementImpl('E', -1);
     TypeParameterTypeImpl type = new TypeParameterTypeImpl(element);
-    InterfaceTypeImpl argument = new InterfaceTypeImpl(
-        new ClassElementImpl.forNode(AstTestFactory.identifier3("A")));
+    InterfaceTypeImpl argument =
+        new InterfaceTypeImpl(new ClassElementImpl('A', -1));
     TypeParameterTypeImpl parameter = new TypeParameterTypeImpl(element);
     expect(type.substitute2(<DartType>[argument], <DartType>[parameter]),
         same(argument));
@@ -2423,12 +2398,12 @@
 
   @deprecated
   void test_substitute_notEqual() {
-    TypeParameterTypeImpl type = new TypeParameterTypeImpl(
-        new TypeParameterElementImpl.forNode(AstTestFactory.identifier3("E")));
-    InterfaceTypeImpl argument = new InterfaceTypeImpl(
-        new ClassElementImpl.forNode(AstTestFactory.identifier3("A")));
-    TypeParameterTypeImpl parameter = new TypeParameterTypeImpl(
-        new TypeParameterElementImpl.forNode(AstTestFactory.identifier3("F")));
+    TypeParameterTypeImpl type =
+        new TypeParameterTypeImpl(new TypeParameterElementImpl('E', -1));
+    InterfaceTypeImpl argument =
+        new InterfaceTypeImpl(new ClassElementImpl('A', -1));
+    TypeParameterTypeImpl parameter =
+        new TypeParameterTypeImpl(new TypeParameterElementImpl('F', -1));
     expect(type.substitute2(<DartType>[argument], <DartType>[parameter]),
         same(type));
   }
diff --git a/pkg/analyzer/test/src/dart/element/inheritance_manager3_test.dart b/pkg/analyzer/test/src/dart/element/inheritance_manager3_test.dart
index 9d113c6..aa2e228 100644
--- a/pkg/analyzer/test/src/dart/element/inheritance_manager3_test.dart
+++ b/pkg/analyzer/test/src/dart/element/inheritance_manager3_test.dart
@@ -2,10 +2,12 @@
 // 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/analysis/features.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/nullability_suffix.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
+import 'package:analyzer/src/generated/engine.dart';
 import 'package:meta/meta.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -15,21 +17,12 @@
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(InheritanceManager3Test);
+    defineReflectiveTests(InheritanceManager3WithNnbdTest);
   });
 }
 
 @reflectiveTest
-class InheritanceManager3Test extends DriverResolutionTest {
-  InheritanceManager3 manager;
-
-  @override
-  Future<void> resolveTestFile() async {
-    await super.resolveTestFile();
-    manager = new InheritanceManager3(
-      result.unit.declaredElement.context.typeSystem,
-    );
-  }
-
+class InheritanceManager3Test extends _InheritanceManager3Base {
   test_getInherited_closestSuper() async {
     await resolveTestCode('''
 class A {
@@ -1048,12 +1041,90 @@
       expected: 'A.foo: void Function()',
     );
   }
+}
+
+@reflectiveTest
+class InheritanceManager3WithNnbdTest extends _InheritanceManager3Base {
+  @override
+  AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+    ..contextFeatures = FeatureSet.forTesting(
+        sdkVersion: '2.6.0', additionalFeatures: [Feature.non_nullable]);
+
+  @override
+  bool get typeToStringWithNullability => true;
+
+  test_getMember_optOut_inheritsOptIn() async {
+    newFile('/test/lib/a.dart', content: r'''
+class A {
+  int foo(int a, int? b) => 0;
+}
+''');
+    await resolveTestCode('''
+// @dart = 2.6
+import 'a.dart';
+class B extends A {
+  int bar(int a) => 0;
+}
+''');
+    _assertGetMember(
+      className: 'B',
+      name: 'foo',
+      expected: 'A.foo: int Function(int, int?)',
+    );
+    _assertGetMember(
+      className: 'B',
+      name: 'bar',
+      expected: 'B.bar: int* Function(int*)*',
+    );
+  }
+
+  test_getMember_optOut_passOptIn() async {
+    newFile('/test/lib/a.dart', content: r'''
+class A {
+  int foo(int a, int? b) => 0;
+}
+''');
+    newFile('/test/lib/b.dart', content: r'''
+// @dart = 2.6
+import 'a.dart';
+class B extends A {
+  int bar(int a) => 0;
+}
+''');
+    await resolveTestCode('''
+import 'b.dart';
+class C extends B {}
+''');
+    _assertGetMember(
+      className: 'C',
+      name: 'foo',
+      expected: 'A.foo: int Function(int, int?)',
+    );
+    _assertGetMember(
+      className: 'C',
+      name: 'bar',
+      expected: 'B.bar: int* Function(int*)*',
+    );
+  }
+}
+
+class _InheritanceManager3Base extends DriverResolutionTest {
+  InheritanceManager3 manager;
+
+  @override
+  Future<void> resolveTestFile() async {
+    await super.resolveTestFile();
+    manager = new InheritanceManager3();
+  }
 
   void _assertExecutable(ExecutableElement element, String expected) {
     if (expected != null) {
-      var type = element.type;
       var enclosingElement = element.enclosingElement;
-      var actual = '${enclosingElement.name}.${element.name}: $type';
+
+      var type = element.type;
+      var typeStr = typeString(type);
+
+      var actual = '${enclosingElement.name}.${element.name}: $typeStr';
       expect(actual, expected);
     } else {
       expect(element, isNull);
diff --git a/pkg/analyzer/test/src/dart/element/least_upper_bound_helper_test.dart b/pkg/analyzer/test/src/dart/element/least_upper_bound_helper_test.dart
index d9f6283..5132ab1 100644
--- a/pkg/analyzer/test/src/dart/element/least_upper_bound_helper_test.dart
+++ b/pkg/analyzer/test/src/dart/element/least_upper_bound_helper_test.dart
@@ -40,12 +40,12 @@
     ClassElementImpl classC = ElementFactory.classElement2("C");
     ClassElementImpl classD = ElementFactory.classElement2("D");
     ClassElementImpl classE = ElementFactory.classElement2("E");
-    classB.interfaces = <InterfaceType>[interfaceType(classA)];
-    classC.interfaces = <InterfaceType>[interfaceType(classA)];
-    classD.interfaces = <InterfaceType>[interfaceType(classC)];
+    classB.interfaces = <InterfaceType>[interfaceTypeStar(classA)];
+    classC.interfaces = <InterfaceType>[interfaceTypeStar(classA)];
+    classD.interfaces = <InterfaceType>[interfaceTypeStar(classC)];
     classE.interfaces = <InterfaceType>[
-      interfaceType(classB),
-      interfaceType(classD)
+      interfaceTypeStar(classB),
+      interfaceTypeStar(classD)
     ];
     // assertion: even though the longest path to Object for typeB is 2, and
     // typeE implements typeB, the longest path for typeE is 4 since it also
@@ -68,14 +68,14 @@
     //
     ClassElement classA = ElementFactory.classElement2("A");
     ClassElement classB =
-        ElementFactory.classElement("B", interfaceType(classA));
+        ElementFactory.classElement("B", interfaceTypeStar(classA));
     ClassElement classC =
-        ElementFactory.classElement("C", interfaceType(classA));
+        ElementFactory.classElement("C", interfaceTypeStar(classA));
     ClassElement classD =
-        ElementFactory.classElement("D", interfaceType(classC));
+        ElementFactory.classElement("D", interfaceTypeStar(classC));
     ClassElementImpl classE =
-        ElementFactory.classElement("E", interfaceType(classB));
-    classE.interfaces = <InterfaceType>[interfaceType(classD)];
+        ElementFactory.classElement("E", interfaceTypeStar(classB));
+    classE.interfaces = <InterfaceType>[interfaceTypeStar(classD)];
     // assertion: even though the longest path to Object for typeB is 2, and
     // typeE extends typeB, the longest path for typeE is 4 since it also
     // implements typeD
@@ -90,8 +90,8 @@
   void test_computeLongestInheritancePathToObject_recursion() {
     ClassElementImpl classA = ElementFactory.classElement2("A");
     ClassElementImpl classB =
-        ElementFactory.classElement("B", interfaceType(classA));
-    classA.supertype = interfaceType(classB);
+        ElementFactory.classElement("B", interfaceTypeStar(classA));
+    classA.supertype = interfaceTypeStar(classB);
     expect(_longestPathToObject(classA), 2);
   }
 
@@ -108,8 +108,8 @@
     ClassElementImpl classA = ElementFactory.classElement2("A");
     ClassElementImpl classB = ElementFactory.classElement2("B");
     ClassElementImpl classC = ElementFactory.classElement2("C");
-    classB.interfaces = <InterfaceType>[interfaceType(classA)];
-    classC.interfaces = <InterfaceType>[interfaceType(classB)];
+    classB.interfaces = <InterfaceType>[interfaceTypeStar(classA)];
+    classC.interfaces = <InterfaceType>[interfaceTypeStar(classB)];
     expect(_longestPathToObject(classA), 1);
     expect(_longestPathToObject(classB), 2);
     expect(_longestPathToObject(classC), 3);
@@ -127,9 +127,9 @@
     //
     ClassElement classA = ElementFactory.classElement2("A");
     ClassElement classB =
-        ElementFactory.classElement("B", interfaceType(classA));
+        ElementFactory.classElement("B", interfaceTypeStar(classA));
     ClassElement classC =
-        ElementFactory.classElement("C", interfaceType(classB));
+        ElementFactory.classElement("C", interfaceTypeStar(classB));
     expect(_longestPathToObject(classA), 1);
     expect(_longestPathToObject(classB), 2);
     expect(_longestPathToObject(classC), 3);
@@ -181,7 +181,7 @@
     // B<D>
     expect(
       _superInterfaces(
-        InstantiatedClass(classB, [interfaceType(classD)]),
+        InstantiatedClass(classB, [interfaceTypeStar(classD)]),
       ),
       unorderedEquals([instObject, instA]),
     );
@@ -189,12 +189,12 @@
     // C<D>
     expect(
       _superInterfaces(
-        InstantiatedClass(classC, [interfaceType(classD)]),
+        InstantiatedClass(classC, [interfaceTypeStar(classD)]),
       ),
       unorderedEquals([
         instObject,
         instA,
-        InstantiatedClass(classB, [interfaceType(classD)]),
+        InstantiatedClass(classB, [interfaceTypeStar(classD)]),
       ]),
     );
   }
@@ -242,7 +242,7 @@
     // B<D>
     expect(
       _superInterfaces(
-        InstantiatedClass(classB, [interfaceType(classD)]),
+        InstantiatedClass(classB, [interfaceTypeStar(classD)]),
       ),
       unorderedEquals([instObject, instA]),
     );
@@ -250,12 +250,12 @@
     // C<D>
     expect(
       _superInterfaces(
-        InstantiatedClass(classC, [interfaceType(classD)]),
+        InstantiatedClass(classC, [interfaceTypeStar(classD)]),
       ),
       unorderedEquals([
         instObject,
         instA,
-        InstantiatedClass(classB, [interfaceType(classD)]),
+        InstantiatedClass(classB, [interfaceTypeStar(classD)]),
       ]),
     );
   }
@@ -275,7 +275,7 @@
     var classC = ElementFactory.classElement3(name: 'C');
     var instC = InstantiatedClass(classC, const []);
 
-    var mixinM = ElementFactory.mixinElement(
+    var mixinM = mixin_(
       name: 'M',
       constraints: [
         instB.withNullabilitySuffixNone,
@@ -293,7 +293,7 @@
   void test_computeSuperinterfaceSet_mixin_constraints_object() {
     var instObject = InstantiatedClass.of(typeProvider.objectType);
 
-    var mixinM = ElementFactory.mixinElement(name: 'M');
+    var mixinM = mixin_(name: 'M');
     var instM = InstantiatedClass(mixinM, const []);
 
     expect(
@@ -317,7 +317,7 @@
     var classC = ElementFactory.classElement3(name: 'C');
     var instC = InstantiatedClass(classC, const []);
 
-    var mixinM = ElementFactory.mixinElement(
+    var mixinM = mixin_(
       name: 'M',
       interfaces: [
         instB.withNullabilitySuffixNone,
diff --git a/pkg/analyzer/test/src/dart/element/nullability_eliminator_test.dart b/pkg/analyzer/test/src/dart/element/nullability_eliminator_test.dart
index b0b9091..15b1c8c 100644
--- a/pkg/analyzer/test/src/dart/element/nullability_eliminator_test.dart
+++ b/pkg/analyzer/test/src/dart/element/nullability_eliminator_test.dart
@@ -3,7 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/dart/analysis/features.dart';
-import 'package:analyzer/dart/element/nullability_suffix.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/nullability_eliminator.dart';
 import 'package:analyzer/src/dart/element/type.dart';
@@ -21,7 +20,7 @@
 }
 
 @reflectiveTest
-class NullabilityEliminatorTest with ElementsTypesMixin, TypeProviderTypes {
+class NullabilityEliminatorTest with ElementsTypesMixin {
   @override
   TypeProvider typeProvider;
 
@@ -41,17 +40,17 @@
 
   test_functionType() {
     _verify(
-      functionTypeNone(returnType: voidType),
-      functionTypeStar(returnType: voidType),
+      functionTypeNone(returnType: voidNone),
+      functionTypeStar(returnType: voidNone),
     );
 
     _verify(
-      functionTypeQuestion(returnType: voidType),
-      functionTypeStar(returnType: voidType),
+      functionTypeQuestion(returnType: voidNone),
+      functionTypeStar(returnType: voidNone),
     );
 
     _verifySame(
-      functionTypeStar(returnType: voidType),
+      functionTypeStar(returnType: voidNone),
     );
   }
 
@@ -61,13 +60,13 @@
         parameters: [
           requiredParameter(type: intNone),
         ],
-        returnType: voidType,
+        returnType: voidNone,
       ),
       functionTypeStar(
         parameters: [
           requiredParameter(type: intStar),
         ],
-        returnType: voidType,
+        returnType: voidNone,
       ),
     );
 
@@ -76,13 +75,13 @@
         parameters: [
           requiredParameter(type: intQuestion),
         ],
-        returnType: voidType,
+        returnType: voidNone,
       ),
       functionTypeStar(
         parameters: [
           requiredParameter(type: intStar),
         ],
-        returnType: voidType,
+        returnType: voidNone,
       ),
     );
 
@@ -91,7 +90,7 @@
         parameters: [
           requiredParameter(type: intStar),
         ],
-        returnType: voidType,
+        returnType: voidNone,
       ),
     );
   }
@@ -264,53 +263,3 @@
     expect(_typeToString(result), expectedStr);
   }
 }
-
-mixin TypeProviderTypes {
-  DynamicTypeImpl get dynamicType => typeProvider.dynamicType;
-
-  InterfaceType get intNone {
-    return typeProvider.intElement.instantiate(
-      typeArguments: const [],
-      nullabilitySuffix: NullabilitySuffix.none,
-    );
-  }
-
-  InterfaceType get intQuestion {
-    return typeProvider.intElement.instantiate(
-      typeArguments: const [],
-      nullabilitySuffix: NullabilitySuffix.question,
-    );
-  }
-
-  InterfaceType get intStar {
-    return typeProvider.intElement.instantiate(
-      typeArguments: const [],
-      nullabilitySuffix: NullabilitySuffix.star,
-    );
-  }
-
-  TypeProvider get typeProvider;
-
-  VoidTypeImpl get voidType => typeProvider.voidType;
-
-  InterfaceType listNone(DartType type) {
-    return typeProvider.listElement.instantiate(
-      typeArguments: [type],
-      nullabilitySuffix: NullabilitySuffix.none,
-    );
-  }
-
-  InterfaceType listQuestion(DartType type) {
-    return typeProvider.listElement.instantiate(
-      typeArguments: [type],
-      nullabilitySuffix: NullabilitySuffix.question,
-    );
-  }
-
-  InterfaceType listStar(DartType type) {
-    return typeProvider.listElement.instantiate(
-      typeArguments: [type],
-      nullabilitySuffix: NullabilitySuffix.star,
-    );
-  }
-}
diff --git a/pkg/analyzer/test/src/dart/element/subtype_test.dart b/pkg/analyzer/test/src/dart/element/subtype_test.dart
index 354f34e..d3999f4 100644
--- a/pkg/analyzer/test/src/dart/element/subtype_test.dart
+++ b/pkg/analyzer/test/src/dart/element/subtype_test.dart
@@ -277,47 +277,12 @@
     if (expectedString != null) {
       var typeStr = _typeStr(type);
 
-      var typeParameterCollector = _TypeParameterCollector();
-      DartTypeVisitor.visit(type, typeParameterCollector);
-      for (var typeParameter in typeParameterCollector.typeParameters) {
-        if (typeParameter is TypeParameterMember) {
-          var base = typeParameter.declaration;
-          var baseBound = base.bound as TypeImpl;
-          if (baseBound != null) {
-            var baseBoundStr = baseBound.toString(withNullability: true);
-            typeStr += ', ${typeParameter.name} extends ' + baseBoundStr;
-          }
-
-          var bound = typeParameter.bound as TypeImpl;
-          var boundStr = bound.toString(withNullability: true);
-          typeStr += ', ${typeParameter.name} & ' + boundStr;
-        } else {
-          var bound = typeParameter.bound as TypeImpl;
-          if (bound != null) {
-            var boundStr = bound.toString(withNullability: true);
-            typeStr += ', ${typeParameter.name} extends ' + boundStr;
-          }
-        }
-      }
+      typeStr += _typeParametersStr(type);
 
       expect(typeStr, expectedString);
     }
   }
 
-  InterfaceType comparableQuestion(DartType type) {
-    return comparableElement.instantiate(
-      typeArguments: [type],
-      nullabilitySuffix: NullabilitySuffix.question,
-    );
-  }
-
-  InterfaceType comparableStar(DartType type) {
-    return comparableElement.instantiate(
-      typeArguments: [type],
-      nullabilitySuffix: NullabilitySuffix.star,
-    );
-  }
-
   void isNotSubtype(
     DartType T0,
     DartType T1, {
@@ -365,42 +330,6 @@
     expect(typeSystem.isSubtypeOf(T0, T1), isTrue);
   }
 
-  InterfaceType iterableStar(DartType type) {
-    return typeProvider.iterableElement.instantiate(
-      typeArguments: [type],
-      nullabilitySuffix: NullabilitySuffix.star,
-    );
-  }
-
-  InterfaceType listNone(DartType type) {
-    return typeProvider.listElement.instantiate(
-      typeArguments: [type],
-      nullabilitySuffix: NullabilitySuffix.none,
-    );
-  }
-
-  InterfaceType listQuestion(DartType type) {
-    return typeProvider.listElement.instantiate(
-      typeArguments: [type],
-      nullabilitySuffix: NullabilitySuffix.question,
-    );
-  }
-
-  InterfaceType listStar(DartType type) {
-    return typeProvider.listElement.instantiate(
-      typeArguments: [type],
-      nullabilitySuffix: NullabilitySuffix.star,
-    );
-  }
-
-  TypeParameterMember promoteTypeParameter(
-    TypeParameterElement element,
-    DartType bound,
-  ) {
-    assert(element is! TypeParameterMember);
-    return TypeParameterMember(element, null, bound);
-  }
-
   @override
   void setUp() {
     super.setUp();
@@ -2846,37 +2775,7 @@
     );
   }
 
-  test_interfaceType_covariant_01() {
-    var T = typeParameter('T', variance: Variance.covariant);
-    var A = class_(name: 'A', typeParameters: [T]);
-
-    var A_num = A.instantiate(
-      typeArguments: [numNone],
-      nullabilitySuffix: NullabilitySuffix.none,
-    );
-
-    var A_int = A.instantiate(
-      typeArguments: [intNone],
-      nullabilitySuffix: NullabilitySuffix.none,
-    );
-
-    isSubtype(A_int, A_num, strT0: "A<int>", strT1: "A<num>");
-    isNotSubtype(A_num, A_int, strT0: "A<num>", strT1: "A<int>");
-  }
-
-  test_interfaceType_covariant_02() {
-    var T = typeParameter('T', variance: Variance.covariant);
-    var A = class_(name: 'A', typeParameters: [T]);
-
-    var A_num = A.instantiate(
-      typeArguments: [numNone],
-      nullabilitySuffix: NullabilitySuffix.none,
-    );
-
-    isSubtype(A_num, A_num, strT0: "A<num>", strT1: "A<num>");
-  }
-
-  test_interfaceType_contravariant_01() {
+  test_interfaceType_contravariant() {
     var T = typeParameter('T', variance: Variance.contravariant);
     var A = class_(name: 'A', typeParameters: [T]);
 
@@ -2891,11 +2790,12 @@
     );
 
     isSubtype(A_num, A_int, strT0: "A<num>", strT1: "A<int>");
+    isSubtype(A_num, A_num, strT0: "A<num>", strT1: "A<num>");
     isNotSubtype(A_int, A_num, strT0: "A<int>", strT1: "A<num>");
   }
 
-  test_interfaceType_contravariant_02() {
-    var T = typeParameter('T', variance: Variance.contravariant);
+  test_interfaceType_covariant() {
+    var T = typeParameter('T', variance: Variance.covariant);
     var A = class_(name: 'A', typeParameters: [T]);
 
     var A_num = A.instantiate(
@@ -2903,7 +2803,14 @@
       nullabilitySuffix: NullabilitySuffix.none,
     );
 
+    var A_int = A.instantiate(
+      typeArguments: [intNone],
+      nullabilitySuffix: NullabilitySuffix.none,
+    );
+
+    isSubtype(A_int, A_num, strT0: "A<int>", strT1: "A<num>");
     isSubtype(A_num, A_num, strT0: "A<num>", strT1: "A<num>");
+    isNotSubtype(A_num, A_int, strT0: "A<num>", strT1: "A<int>");
   }
 
   test_interfaceType_invariant() {
@@ -5968,6 +5875,34 @@
     return type;
   }
 
+  String _typeParametersStr(TypeImpl type) {
+    var typeStr = '';
+
+    var typeParameterCollector = _TypeParameterCollector();
+    DartTypeVisitor.visit(type, typeParameterCollector);
+    for (var typeParameter in typeParameterCollector.typeParameters) {
+      if (typeParameter is TypeParameterMember) {
+        var base = typeParameter.declaration;
+        var baseBound = base.bound as TypeImpl;
+        if (baseBound != null) {
+          var baseBoundStr = baseBound.toString(withNullability: true);
+          typeStr += ', ${typeParameter.name} extends ' + baseBoundStr;
+        }
+
+        var bound = typeParameter.bound as TypeImpl;
+        var boundStr = bound.toString(withNullability: true);
+        typeStr += ', ${typeParameter.name} & ' + boundStr;
+      } else {
+        var bound = typeParameter.bound as TypeImpl;
+        if (bound != null) {
+          var boundStr = bound.toString(withNullability: true);
+          typeStr += ', ${typeParameter.name} extends ' + boundStr;
+        }
+      }
+    }
+    return typeStr;
+  }
+
   static String _typeStr(DartType type) {
     return (type as TypeImpl).toString(withNullability: true);
   }
@@ -6146,233 +6081,12 @@
 class _SubtypingTestBase with ElementsTypesMixin {
   TypeProvider typeProvider;
 
-  Dart2TypeSystem typeSystem;
-
-  ClassElement _comparableElement;
-
-  ClassElement get comparableElement {
-    return _comparableElement ??=
-        typeProvider.intType.element.library.getType('Comparable');
-  }
-
-  InterfaceType get doubleNone {
-    var element = typeProvider.doubleType.element;
-    return element.instantiate(
-      typeArguments: const [],
-      nullabilitySuffix: NullabilitySuffix.none,
-    );
-  }
-
-  InterfaceType get doubleQuestion {
-    var element = typeProvider.doubleType.element;
-    return element.instantiate(
-      typeArguments: const [],
-      nullabilitySuffix: NullabilitySuffix.question,
-    );
-  }
-
-  InterfaceType get doubleStar {
-    var element = typeProvider.doubleType.element;
-    return element.instantiate(
-      typeArguments: const [],
-      nullabilitySuffix: NullabilitySuffix.star,
-    );
-  }
-
-  DartType get dynamicNone => typeProvider.dynamicType;
-
-  InterfaceType get functionNone {
-    var element = typeProvider.functionType.element;
-    return element.instantiate(
-      typeArguments: const [],
-      nullabilitySuffix: NullabilitySuffix.none,
-    );
-  }
-
-  InterfaceType get functionQuestion {
-    var element = typeProvider.functionType.element;
-    return element.instantiate(
-      typeArguments: const [],
-      nullabilitySuffix: NullabilitySuffix.question,
-    );
-  }
-
-  InterfaceType get functionStar {
-    var element = typeProvider.functionType.element;
-    return element.instantiate(
-      typeArguments: const [],
-      nullabilitySuffix: NullabilitySuffix.star,
-    );
-  }
-
-  InterfaceType get intNone {
-    var element = typeProvider.intType.element;
-    return element.instantiate(
-      typeArguments: const [],
-      nullabilitySuffix: NullabilitySuffix.none,
-    );
-  }
-
-  InterfaceType get intQuestion {
-    var element = typeProvider.intType.element;
-    return element.instantiate(
-      typeArguments: const [],
-      nullabilitySuffix: NullabilitySuffix.question,
-    );
-  }
-
-  InterfaceType get intStar {
-    var element = typeProvider.intType.element;
-    return element.instantiate(
-      typeArguments: const [],
-      nullabilitySuffix: NullabilitySuffix.star,
-    );
-  }
-
-  InterfaceType get nullNone {
-    var element = typeProvider.nullType.element;
-    return element.instantiate(
-      typeArguments: const [],
-      nullabilitySuffix: NullabilitySuffix.none,
-    );
-  }
-
-  InterfaceType get nullQuestion {
-    var element = typeProvider.nullType.element;
-    return element.instantiate(
-      typeArguments: const [],
-      nullabilitySuffix: NullabilitySuffix.question,
-    );
-  }
-
-  InterfaceType get nullStar {
-    var element = typeProvider.nullType.element;
-    return element.instantiate(
-      typeArguments: const [],
-      nullabilitySuffix: NullabilitySuffix.star,
-    );
-  }
-
-  InterfaceType get numNone {
-    var element = typeProvider.numType.element;
-    return element.instantiate(
-      typeArguments: const [],
-      nullabilitySuffix: NullabilitySuffix.none,
-    );
-  }
-
-  InterfaceType get numQuestion {
-    var element = typeProvider.numType.element;
-    return element.instantiate(
-      typeArguments: const [],
-      nullabilitySuffix: NullabilitySuffix.question,
-    );
-  }
-
-  InterfaceType get numStar {
-    var element = typeProvider.numType.element;
-    return element.instantiate(
-      typeArguments: const [],
-      nullabilitySuffix: NullabilitySuffix.star,
-    );
-  }
-
-  InterfaceType get objectNone {
-    var element = typeProvider.objectType.element;
-    return element.instantiate(
-      typeArguments: const [],
-      nullabilitySuffix: NullabilitySuffix.none,
-    );
-  }
-
-  InterfaceType get objectQuestion {
-    var element = typeProvider.objectType.element;
-    return element.instantiate(
-      typeArguments: const [],
-      nullabilitySuffix: NullabilitySuffix.question,
-    );
-  }
-
-  InterfaceType get objectStar {
-    var element = typeProvider.objectType.element;
-    return element.instantiate(
-      typeArguments: const [],
-      nullabilitySuffix: NullabilitySuffix.star,
-    );
-  }
-
-  InterfaceType get stringNone {
-    var element = typeProvider.stringType.element;
-    return element.instantiate(
-      typeArguments: const [],
-      nullabilitySuffix: NullabilitySuffix.none,
-    );
-  }
-
-  InterfaceType get stringQuestion {
-    var element = typeProvider.stringType.element;
-    return element.instantiate(
-      typeArguments: const [],
-      nullabilitySuffix: NullabilitySuffix.question,
-    );
-  }
-
-  InterfaceType get stringStar {
-    var element = typeProvider.stringType.element;
-    return element.instantiate(
-      typeArguments: const [],
-      nullabilitySuffix: NullabilitySuffix.star,
-    );
-  }
+  TypeSystemImpl typeSystem;
 
   FeatureSet get testFeatureSet {
     return FeatureSet.forTesting();
   }
 
-  VoidType get voidNone => typeProvider.voidType;
-
-  InterfaceTypeImpl futureNone(DartType type) {
-    return typeProvider.futureElement.instantiate(
-      typeArguments: [type],
-      nullabilitySuffix: NullabilitySuffix.none,
-    );
-  }
-
-  InterfaceTypeImpl futureOrNone(DartType type) {
-    return typeProvider.futureOrElement.instantiate(
-      typeArguments: [type],
-      nullabilitySuffix: NullabilitySuffix.none,
-    );
-  }
-
-  InterfaceTypeImpl futureOrQuestion(DartType type) {
-    return typeProvider.futureOrElement.instantiate(
-      typeArguments: [type],
-      nullabilitySuffix: NullabilitySuffix.question,
-    );
-  }
-
-  InterfaceTypeImpl futureOrStar(DartType type) {
-    return typeProvider.futureOrElement.instantiate(
-      typeArguments: [type],
-      nullabilitySuffix: NullabilitySuffix.star,
-    );
-  }
-
-  InterfaceTypeImpl futureQuestion(DartType type) {
-    return typeProvider.futureElement.instantiate(
-      typeArguments: [type],
-      nullabilitySuffix: NullabilitySuffix.question,
-    );
-  }
-
-  InterfaceTypeImpl futureStar(DartType type) {
-    return typeProvider.futureElement.instantiate(
-      typeArguments: [type],
-      nullabilitySuffix: NullabilitySuffix.star,
-    );
-  }
-
   void setUp() {
     var analysisContext = TestAnalysisContext(
       featureSet: testFeatureSet,
diff --git a/pkg/analyzer/test/src/dart/element/test_all.dart b/pkg/analyzer/test/src/dart/element/test_all.dart
index 9cccdad..1527bf0 100644
--- a/pkg/analyzer/test/src/dart/element/test_all.dart
+++ b/pkg/analyzer/test/src/dart/element/test_all.dart
@@ -12,6 +12,7 @@
 import 'subtype_test.dart' as subtype;
 import 'type_algebra_test.dart' as type_algebra;
 import 'type_parameter_element_test.dart' as type_parameter_element;
+import 'upper_bound_test.dart' as upper_bound;
 
 /// Utility for manually running all tests.
 main() {
@@ -24,5 +25,6 @@
     subtype.main();
     type_algebra.main();
     type_parameter_element.main();
+    upper_bound.main();
   }, name: 'element');
 }
diff --git a/pkg/analyzer/test/src/dart/element/type_algebra_test.dart b/pkg/analyzer/test/src/dart/element/type_algebra_test.dart
index 977b926..9f6b25e 100644
--- a/pkg/analyzer/test/src/dart/element/type_algebra_test.dart
+++ b/pkg/analyzer/test/src/dart/element/type_algebra_test.dart
@@ -33,7 +33,7 @@
     var T = typeParameter('T');
     var A = class_(name: 'A', typeParameters: [T]);
 
-    var type = interfaceType(A, typeArguments: [intType]);
+    var type = interfaceTypeStar(A, typeArguments: [intType]);
 
     var result = Substitution.empty.substituteType(type);
     expect(result, same(type));
@@ -51,11 +51,11 @@
     var U = typeParameter('U');
     var B = class_(name: 'B', typeParameters: [U]);
 
-    var BofInt = interfaceType(B, typeArguments: [intType]);
+    var BofInt = interfaceTypeStar(B, typeArguments: [intType]);
     var substitution = Substitution.fromInterfaceType(BofInt);
 
     // A<U>
-    var type = interfaceType(A, typeArguments: [typeParameterType(U)]);
+    var type = interfaceTypeStar(A, typeArguments: [typeParameterType(U)]);
     assertElementTypeString(type, 'A<U>');
 
     var result = substitution.substituteType(type);
@@ -71,7 +71,7 @@
     var U = typeParameter('U');
     var A = class_(name: 'A', typeParameters: [T, U]);
 
-    var type = interfaceType(
+    var type = interfaceTypeStar(
       A,
       typeArguments: [
         typeParameterType(T),
@@ -188,7 +188,7 @@
     var T = typeParameter('T');
     var U = typeParameter('U');
     var V = typeParameter('V');
-    T.bound = interfaceType(classTriplet, typeArguments: [
+    T.bound = interfaceTypeStar(classTriplet, typeArguments: [
       typeParameterType(T),
       typeParameterType(U),
       typeParameterType(V),
@@ -221,7 +221,7 @@
     var A = class_(name: 'A', typeParameters: [T]);
 
     var U = typeParameter('U');
-    var type = interfaceType(A, typeArguments: [
+    var type = interfaceTypeStar(A, typeArguments: [
       typeParameterType(U),
     ]);
 
@@ -234,8 +234,8 @@
     var A = class_(name: 'A', typeParameters: [T]);
 
     var U = typeParameter('U');
-    var type = interfaceType(A, typeArguments: [
-      interfaceType(
+    var type = interfaceTypeStar(A, typeArguments: [
+      interfaceTypeStar(
         typeProvider.listElement,
         typeArguments: [
           typeParameterType(U),
@@ -251,7 +251,7 @@
     // class A {}
     var A = class_(name: 'A');
 
-    var type = interfaceType(A);
+    var type = interfaceTypeStar(A);
     var T = typeParameter('T');
     _assertIdenticalType(type, {T: intType});
   }
@@ -261,7 +261,7 @@
     var T = typeParameter('T');
     var A = class_(name: 'A', typeParameters: [T]);
 
-    var type = interfaceType(A, typeArguments: [intType]);
+    var type = interfaceTypeStar(A, typeArguments: [intType]);
 
     var U = typeParameter('U');
     _assertIdenticalType(type, {U: doubleType});
@@ -387,9 +387,7 @@
   final bool useNnbd;
 
   _Base({this.useNnbd = false})
-      : typeProvider = TestTypeProvider(
-            nullabilitySuffix:
-                useNnbd ? NullabilitySuffix.none : NullabilitySuffix.question);
+      : typeProvider = TestTypeProvider(isNonNullableByDefault: useNnbd);
 
   InterfaceType get boolType => typeProvider.boolType;
 
diff --git a/pkg/analyzer/test/src/dart/element/upper_bound_test.dart b/pkg/analyzer/test/src/dart/element/upper_bound_test.dart
new file mode 100644
index 0000000..9a7c535
--- /dev/null
+++ b/pkg/analyzer/test/src/dart/element/upper_bound_test.dart
@@ -0,0 +1,1366 @@
+// Copyright (c) 2019, 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/analysis/features.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/nullability_suffix.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/member.dart';
+import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/type_visitor.dart';
+import 'package:analyzer/src/generated/resolver.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../../../generated/elements_types_mixin.dart';
+import '../../../generated/test_analysis_context.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(BoundsHelperPredicatesTest);
+    defineReflectiveTests(UpperBoundTest);
+  });
+}
+
+@reflectiveTest
+class BoundsHelperPredicatesTest extends _SubtypingTestBase {
+  static final Map<String, StackTrace> _isMoreBottomChecked = {};
+  static final Map<String, StackTrace> _isMoreTopChecked = {};
+
+  @override
+  FeatureSet get testFeatureSet {
+    return FeatureSet.forTesting(
+      additionalFeatures: [Feature.non_nullable],
+    );
+  }
+
+  void isBottom(DartType type) {
+    expect(typeSystem.isBottom(type), isTrue, reason: _typeString(type));
+  }
+
+  void isMoreBottom(DartType T, DartType S) {
+    _assertIsBottomOrNull(T);
+    _assertIsBottomOrNull(S);
+
+    var str = _typeString(T) + ' vs ' + _typeString(S);
+    _checkUniqueTypeStr(_isMoreBottomChecked, str);
+
+    expect(typeSystem.isMoreBottom(T, S), isTrue, reason: str);
+  }
+
+  void isMoreTop(DartType T, DartType S) {
+    _assertIsTopOrObject(T);
+    _assertIsTopOrObject(S);
+
+    var str = _typeString(T) + ' vs ' + _typeString(S);
+    _checkUniqueTypeStr(_isMoreTopChecked, str);
+
+    expect(typeSystem.isMoreTop(T, S), isTrue, reason: str);
+  }
+
+  void isNotBottom(DartType type) {
+    expect(typeSystem.isBottom(type), isFalse, reason: _typeString(type));
+  }
+
+  void isNotMoreBottom(DartType T, DartType S) {
+    _assertIsBottomOrNull(T);
+    _assertIsBottomOrNull(S);
+
+    var str = _typeString(T) + ' vs ' + _typeString(S);
+    _checkUniqueTypeStr(_isMoreBottomChecked, str);
+
+    expect(typeSystem.isMoreBottom(T, S), isFalse, reason: str);
+  }
+
+  void isNotMoreTop(DartType T, DartType S) {
+    _assertIsTopOrObject(T);
+    _assertIsTopOrObject(S);
+
+    var str = _typeString(T) + ' vs ' + _typeString(S);
+    _checkUniqueTypeStr(_isMoreTopChecked, str);
+
+    expect(typeSystem.isMoreTop(T, S), isFalse, reason: str);
+  }
+
+  void isNotNull(DartType type) {
+    expect(typeSystem.isNull(type), isFalse, reason: _typeString(type));
+  }
+
+  void isNotObject(DartType type) {
+    expect(typeSystem.isObject(type), isFalse, reason: _typeString(type));
+  }
+
+  void isNotTop(DartType type) {
+    expect(typeSystem.isTop(type), isFalse, reason: _typeString(type));
+  }
+
+  void isNull(DartType type) {
+    expect(typeSystem.isNull(type), isTrue, reason: _typeString(type));
+  }
+
+  void isObject(DartType type) {
+    expect(typeSystem.isObject(type), isTrue, reason: _typeString(type));
+  }
+
+  void isTop(DartType type) {
+    expect(typeSystem.isTop(type), isTrue, reason: _typeString(type));
+  }
+
+  test_isBottom() {
+    TypeParameterElement T;
+    TypeParameterMember T2;
+
+    // BOTTOM(Never) is true
+    isBottom(neverNone);
+    isNotBottom(neverQuestion);
+    isNotBottom(neverStar);
+
+    // BOTTOM(X&T) is true iff BOTTOM(T)
+    T = typeParameter('T', bound: objectQuestion);
+
+    T2 = promoteTypeParameter(T, neverNone);
+    isBottom(typeParameterTypeNone(T2));
+    isBottom(typeParameterTypeQuestion(T2));
+    isBottom(typeParameterTypeStar(T2));
+
+    T2 = promoteTypeParameter(T, neverQuestion);
+    isNotBottom(typeParameterTypeNone(T2));
+    isNotBottom(typeParameterTypeQuestion(T2));
+    isNotBottom(typeParameterTypeStar(T2));
+
+    // BOTTOM(X extends T) is true iff BOTTOM(T)
+    T = typeParameter('T', bound: neverNone);
+    isBottom(typeParameterTypeNone(T));
+    isBottom(typeParameterTypeQuestion(T));
+    isBottom(typeParameterTypeStar(T));
+
+    T = typeParameter('T', bound: neverQuestion);
+    isNotBottom(typeParameterTypeNone(T));
+    isNotBottom(typeParameterTypeQuestion(T));
+    isNotBottom(typeParameterTypeStar(T));
+
+    // BOTTOM(T) is false otherwise
+    isNotBottom(dynamicNone);
+    isNotBottom(voidNone);
+
+    isNotBottom(objectNone);
+    isNotBottom(objectQuestion);
+    isNotBottom(objectStar);
+
+    isNotBottom(intNone);
+    isNotBottom(intQuestion);
+    isNotBottom(intStar);
+
+    T = typeParameter('T', bound: numNone);
+    isNotBottom(typeParameterTypeNone(T));
+    isNotBottom(typeParameterTypeQuestion(T));
+    isNotBottom(typeParameterTypeStar(T));
+
+    T = typeParameter('T', bound: numStar);
+    isNotBottom(typeParameterTypeNone(T));
+    isNotBottom(typeParameterTypeQuestion(T));
+    isNotBottom(typeParameterTypeStar(T));
+
+    T2 = promoteTypeParameter(typeParameter('T'), intNone);
+    isNotBottom(typeParameterTypeNone(T2));
+    isNotBottom(typeParameterTypeQuestion(T2));
+    isNotBottom(typeParameterTypeStar(T2));
+  }
+
+  test_isMoreBottom() {
+    // MOREBOTTOM(Never, T) = true
+    isMoreBottom(neverNone, neverNone);
+    isMoreBottom(neverNone, neverQuestion);
+    isMoreBottom(neverNone, neverStar);
+
+    isMoreBottom(neverNone, nullNone);
+    isMoreBottom(neverNone, nullQuestion);
+    isMoreBottom(neverNone, nullStar);
+
+    // MOREBOTTOM(T, Never) = false
+    isNotMoreBottom(neverQuestion, neverNone);
+    isNotMoreBottom(neverStar, neverNone);
+
+    isNotMoreBottom(nullNone, neverNone);
+    isNotMoreBottom(nullQuestion, neverNone);
+    isNotMoreBottom(nullStar, neverNone);
+
+    // MOREBOTTOM(Null, T) = true
+    isMoreBottom(nullNone, neverQuestion);
+    isMoreBottom(nullNone, neverStar);
+
+    isMoreBottom(nullNone, nullNone);
+    isMoreBottom(nullNone, nullQuestion);
+    isMoreBottom(nullNone, nullStar);
+
+    // MOREBOTTOM(T, Null) = false
+    isNotMoreBottom(neverQuestion, nullNone);
+    isNotMoreBottom(neverStar, nullNone);
+
+    isNotMoreBottom(nullQuestion, nullNone);
+    isNotMoreBottom(nullStar, nullNone);
+
+    // MOREBOTTOM(T?, S?) = MOREBOTTOM(T, S)
+    isMoreBottom(neverQuestion, nullQuestion);
+    isNotMoreBottom(nullQuestion, neverQuestion);
+
+    // MOREBOTTOM(T, S?) = true
+    isMoreBottom(neverStar, nullQuestion);
+    isMoreBottom(nullStar, neverQuestion);
+
+    // MOREBOTTOM(T?, S) = false
+    isNotMoreBottom(neverQuestion, nullStar);
+    isNotMoreBottom(nullQuestion, neverStar);
+
+    // MOREBOTTOM(T*, S*) = MOREBOTTOM(T, S)
+    isMoreBottom(neverStar, nullStar);
+    isNotMoreBottom(nullStar, neverStar);
+
+    // MOREBOTTOM(T, S*) = true
+    isMoreBottom(
+      typeParameterTypeNone(
+        typeParameter('S', bound: neverNone),
+      ),
+      nullStar,
+    );
+
+    // MOREBOTTOM(T*, S) = false
+    isNotMoreBottom(
+      nullStar,
+      typeParameterTypeNone(
+        typeParameter('S', bound: neverNone),
+      ),
+    );
+
+    // MOREBOTTOM(X&T, Y&S) = MOREBOTTOM(T, S)
+    isMoreBottom(
+      typeParameterTypeNone(
+        promoteTypeParameter(
+          typeParameter('T', bound: objectQuestion),
+          neverNone,
+        ),
+      ),
+      typeParameterTypeQuestion(
+        promoteTypeParameter(
+          typeParameter('S', bound: objectQuestion),
+          neverNone,
+        ),
+      ),
+    );
+
+    // MOREBOTTOM(X&T, S) = true
+    isMoreBottom(
+      typeParameterTypeNone(
+        promoteTypeParameter(
+          typeParameter('T', bound: objectQuestion),
+          neverNone,
+        ),
+      ),
+      typeParameterTypeNone(
+        typeParameter('S', bound: neverNone),
+      ),
+    );
+
+    // MOREBOTTOM(T, X&S) = false
+    isNotMoreBottom(
+      typeParameterTypeNone(
+        typeParameter('T', bound: neverNone),
+      ),
+      typeParameterTypeNone(
+        promoteTypeParameter(
+          typeParameter('S', bound: objectQuestion),
+          neverNone,
+        ),
+      ),
+    );
+
+    // MOREBOTTOM(X extends T, Y extends S) = MOREBOTTOM(T, S)
+    isMoreBottom(
+      typeParameterTypeNone(
+        typeParameter('T', bound: neverNone),
+      ),
+      typeParameterTypeQuestion(
+        typeParameter('S', bound: neverNone),
+      ),
+    );
+  }
+
+  test_isMoreTop() {
+    // MORETOP(void, T) = true
+    isMoreTop(voidNone, voidNone);
+    isMoreTop(voidNone, dynamicNone);
+    isMoreTop(voidNone, objectNone);
+    isMoreTop(voidNone, objectQuestion);
+    isMoreTop(voidNone, objectStar);
+    isMoreTop(voidNone, futureOrNone(objectNone));
+    isMoreTop(voidNone, futureOrNone(objectQuestion));
+    isMoreTop(voidNone, futureOrNone(objectStar));
+
+    // MORETOP(T, void) = false
+    isNotMoreTop(dynamicNone, voidNone);
+    isNotMoreTop(objectNone, voidNone);
+    isNotMoreTop(objectQuestion, voidNone);
+    isNotMoreTop(objectStar, voidNone);
+    isNotMoreTop(futureOrNone(objectNone), voidNone);
+    isNotMoreTop(futureOrNone(objectQuestion), voidNone);
+    isNotMoreTop(futureOrNone(objectStar), voidNone);
+
+    // MORETOP(dynamic, T) = true
+    isMoreTop(dynamicNone, dynamicNone);
+    isMoreTop(dynamicNone, objectNone);
+    isMoreTop(dynamicNone, objectQuestion);
+    isMoreTop(dynamicNone, objectStar);
+    isMoreTop(dynamicNone, futureOrNone(objectNone));
+    isMoreTop(dynamicNone, futureOrNone(objectQuestion));
+    isMoreTop(dynamicNone, futureOrNone(objectStar));
+
+    // MORETOP(T, dynamic) = false
+    isNotMoreTop(objectNone, dynamicNone);
+    isNotMoreTop(objectQuestion, dynamicNone);
+    isNotMoreTop(objectStar, dynamicNone);
+    isNotMoreTop(futureOrNone(objectNone), dynamicNone);
+    isNotMoreTop(futureOrNone(objectQuestion), dynamicNone);
+    isNotMoreTop(futureOrNone(objectStar), dynamicNone);
+
+    // MORETOP(Object, T) = true
+    isMoreTop(objectNone, objectNone);
+    isMoreTop(objectNone, objectQuestion);
+    isMoreTop(objectNone, objectStar);
+    isMoreTop(objectNone, futureOrNone(objectNone));
+    isMoreTop(objectNone, futureOrQuestion(objectNone));
+    isMoreTop(objectNone, futureOrStar(objectNone));
+
+    // MORETOP(T, Object) = false
+    isNotMoreTop(objectQuestion, objectNone);
+    isNotMoreTop(objectStar, objectNone);
+    isNotMoreTop(futureOrNone(objectNone), objectNone);
+    isNotMoreTop(futureOrQuestion(objectNone), objectNone);
+    isNotMoreTop(futureOrStar(objectNone), objectNone);
+
+    // MORETOP(T*, S*) = MORETOP(T, S)
+    isMoreTop(objectStar, objectStar);
+    isMoreTop(objectStar, futureOrStar(objectNone));
+    isMoreTop(objectStar, futureOrStar(objectQuestion));
+    isMoreTop(objectStar, futureOrStar(objectStar));
+    isMoreTop(futureOrStar(objectNone), futureOrStar(objectNone));
+
+    // MORETOP(T, S*) = true
+    isMoreTop(futureOrNone(objectNone), futureOrStar(voidNone));
+    isMoreTop(futureOrNone(objectNone), futureOrStar(dynamicNone));
+    isMoreTop(futureOrNone(objectNone), futureOrStar(objectNone));
+    isMoreTop(futureOrQuestion(objectNone), futureOrStar(voidNone));
+    isMoreTop(futureOrQuestion(objectNone), futureOrStar(dynamicNone));
+    isMoreTop(futureOrQuestion(objectNone), futureOrStar(objectNone));
+
+    // MORETOP(T*, S) = false
+    isNotMoreTop(futureOrStar(voidNone), futureOrNone(objectNone));
+    isNotMoreTop(futureOrStar(dynamicNone), futureOrNone(objectNone));
+    isNotMoreTop(futureOrStar(objectNone), futureOrNone(objectNone));
+    isNotMoreTop(futureOrStar(voidNone), futureOrQuestion(objectNone));
+    isNotMoreTop(futureOrStar(dynamicNone), futureOrQuestion(objectNone));
+    isNotMoreTop(futureOrStar(objectNone), futureOrQuestion(objectNone));
+
+    // MORETOP(T?, S?) = MORETOP(T, S)
+    isMoreTop(objectQuestion, objectQuestion);
+    isMoreTop(futureOrQuestion(voidNone), futureOrQuestion(voidNone));
+    isMoreTop(futureOrQuestion(voidNone), futureOrQuestion(dynamicNone));
+    isMoreTop(futureOrQuestion(voidNone), futureOrQuestion(objectNone));
+
+    // MORETOP(T, S?) = true
+    isMoreTop(futureOrNone(objectNone), futureOrQuestion(voidNone));
+    isMoreTop(futureOrNone(objectNone), futureOrQuestion(dynamicNone));
+    isMoreTop(futureOrNone(objectNone), futureOrQuestion(objectNone));
+
+    // MORETOP(T?, S) = false
+    isNotMoreTop(futureOrQuestion(voidNone), futureOrNone(objectNone));
+    isNotMoreTop(futureOrQuestion(dynamicNone), futureOrNone(objectNone));
+    isNotMoreTop(futureOrQuestion(objectNone), futureOrNone(objectNone));
+
+    // MORETOP(FutureOr<T>, FutureOr<S>) = MORETOP(T, S)
+    isMoreTop(futureOrNone(voidNone), futureOrNone(voidNone));
+    isMoreTop(futureOrNone(voidNone), futureOrNone(dynamicNone));
+    isMoreTop(futureOrNone(voidNone), futureOrNone(objectNone));
+    isNotMoreTop(futureOrNone(dynamicNone), futureOrNone(voidNone));
+    isNotMoreTop(futureOrNone(objectNone), futureOrNone(voidNone));
+  }
+
+  test_isNull() {
+    // NULL(Null) is true
+    isNull(nullNone);
+
+    // NULL(T?) is true iff NULL(T) or BOTTOM(T)
+    isNull(nullQuestion);
+    isNull(neverQuestion);
+    isNull(
+      typeParameterTypeQuestion(
+        typeParameter('T', bound: neverNone),
+      ),
+    );
+
+    // NULL(T*) is true iff NULL(T) or BOTTOM(T)
+    isNull(nullStar);
+    isNull(neverStar);
+    isNull(
+      typeParameterTypeStar(
+        typeParameter('T', bound: neverNone),
+      ),
+    );
+
+    // NULL(T) is false otherwise
+    isNotNull(dynamicNone);
+    isNotNull(voidNone);
+
+    isNotNull(objectNone);
+    isNotNull(objectQuestion);
+    isNotNull(objectStar);
+
+    isNotNull(intNone);
+    isNotNull(intQuestion);
+    isNotNull(intStar);
+
+    isNotNull(futureOrNone(nullNone));
+    isNotNull(futureOrNone(nullQuestion));
+    isNotNull(futureOrNone(nullStar));
+
+    isNotNull(futureOrQuestion(nullNone));
+    isNotNull(futureOrQuestion(nullQuestion));
+    isNotNull(futureOrQuestion(nullStar));
+
+    isNotNull(futureOrStar(nullNone));
+    isNotNull(futureOrStar(nullQuestion));
+    isNotNull(futureOrStar(nullStar));
+  }
+
+  test_isObject() {
+    // OBJECT(Object) is true
+    isObject(objectNone);
+    isNotObject(objectQuestion);
+    isNotObject(objectStar);
+
+    // OBJECT(FutureOr<T>) is OBJECT(T)
+    isObject(futureOrNone(objectNone));
+    isNotObject(futureOrNone(objectQuestion));
+    isNotObject(futureOrNone(objectStar));
+
+    isNotObject(futureOrQuestion(objectNone));
+    isNotObject(futureOrQuestion(objectQuestion));
+    isNotObject(futureOrQuestion(objectStar));
+
+    isNotObject(futureOrStar(objectNone));
+    isNotObject(futureOrStar(objectQuestion));
+    isNotObject(futureOrStar(objectStar));
+
+    // OBJECT(T) is false otherwise
+    isNotObject(dynamicNone);
+    isNotObject(voidNone);
+    isNotObject(intNone);
+  }
+
+  test_isTop() {
+    // TOP(T?) is true iff TOP(T) or OBJECT(T)
+    isTop(objectQuestion);
+    isTop(futureOrQuestion(dynamicNone));
+    isTop(futureOrQuestion(voidNone));
+
+    isTop(futureOrQuestion(objectNone));
+    isTop(futureOrQuestion(objectQuestion));
+    isTop(futureOrQuestion(objectStar));
+
+    isNotTop(futureOrQuestion(intNone));
+    isNotTop(futureOrQuestion(intQuestion));
+    isNotTop(futureOrQuestion(intStar));
+
+    // TOP(T*) is true iff TOP(T) or OBJECT(T)
+    isTop(objectStar);
+    isTop(futureOrStar(dynamicNone));
+    isTop(futureOrStar(voidNone));
+
+    isTop(futureOrStar(objectNone));
+    isTop(futureOrStar(objectQuestion));
+    isTop(futureOrStar(objectStar));
+
+    isNotTop(futureOrStar(intNone));
+    isNotTop(futureOrStar(intQuestion));
+    isNotTop(futureOrStar(intStar));
+
+    // TOP(dynamic) is true
+    isTop(dynamicNone);
+
+    // TOP(void) is true
+    isTop(voidNone);
+
+    // TOP(FutureOr<T>) is TOP(T)
+    isTop(futureOrNone(dynamicNone));
+    isTop(futureOrNone(voidNone));
+
+    isNotTop(futureOrNone(objectNone));
+    isTop(futureOrNone(objectQuestion));
+    isTop(futureOrNone(objectStar));
+
+    // TOP(T) is false otherwise
+    isNotTop(objectNone);
+
+    isNotTop(intNone);
+    isNotTop(intQuestion);
+    isNotTop(intStar);
+
+    isNotTop(neverNone);
+    isNotTop(neverQuestion);
+    isNotTop(neverStar);
+  }
+
+  /// [TypeSystemImpl.isMoreBottom] can be used only for `BOTTOM` or `NULL`
+  /// types. No need to check other types.
+  void _assertIsBottomOrNull(DartType type) {
+    expect(typeSystem.isBottom(type) || typeSystem.isNull(type), isTrue,
+        reason: _typeString(type));
+  }
+
+  /// [TypeSystemImpl.isMoreTop] can be used only for `TOP` or `OBJECT`
+  /// types. No need to check other types.
+  void _assertIsTopOrObject(DartType type) {
+    expect(typeSystem.isTop(type) || typeSystem.isObject(type), isTrue,
+        reason: _typeString(type));
+  }
+
+  void _checkUniqueTypeStr(Map<String, StackTrace> map, String str) {
+    var previousStack = map[str];
+    if (previousStack != null) {
+      fail('Not unique: $str\n$previousStack');
+    } else {
+      map[str] = StackTrace.current;
+    }
+  }
+
+  String _typeParametersStr(TypeImpl type) {
+    var typeStr = '';
+
+    var typeParameterCollector = _TypeParameterCollector();
+    DartTypeVisitor.visit(type, typeParameterCollector);
+    for (var typeParameter in typeParameterCollector.typeParameters) {
+      if (typeParameter is TypeParameterMember) {
+        var base = typeParameter.declaration;
+        var baseBound = base.bound as TypeImpl;
+        if (baseBound != null) {
+          var baseBoundStr = baseBound.toString(withNullability: true);
+          typeStr += ', ${typeParameter.name} extends ' + baseBoundStr;
+        }
+
+        var bound = typeParameter.bound as TypeImpl;
+        var boundStr = bound.toString(withNullability: true);
+        typeStr += ', ${typeParameter.name} & ' + boundStr;
+      } else {
+        var bound = typeParameter.bound as TypeImpl;
+        if (bound != null) {
+          var boundStr = bound.toString(withNullability: true);
+          typeStr += ', ${typeParameter.name} extends ' + boundStr;
+        }
+      }
+    }
+    return typeStr;
+  }
+}
+
+@reflectiveTest
+class UpperBoundTest extends _SubtypingTestBase {
+  test_bottom_any() {
+    void check(DartType T1, DartType T2) {
+      expect(typeSystem.isBottom(T1), isTrue, reason: _typeString(T1));
+      expect(typeSystem.isBottom(T2), isFalse, reason: _typeString(T2));
+      _checkLeastUpperBound(T1, T2, T2);
+    }
+
+    check(neverNone, objectNone);
+    check(neverNone, objectStar);
+    check(neverNone, objectQuestion);
+
+    check(neverNone, intNone);
+    check(neverNone, intQuestion);
+    check(neverNone, intStar);
+
+    check(neverNone, listNone(intNone));
+    check(neverNone, listQuestion(intNone));
+    check(neverNone, listStar(intNone));
+
+    check(neverNone, futureOrNone(intNone));
+    check(neverNone, futureOrQuestion(intNone));
+    check(neverNone, futureOrStar(intNone));
+
+    {
+      var T = typeParameterTypeNone(
+        typeParameter('T', bound: neverNone),
+      );
+      check(T, intNone);
+      check(T, intQuestion);
+      check(T, intStar);
+    }
+
+    {
+      var T = typeParameterTypeNone(
+        promoteTypeParameter(
+          typeParameter('T', bound: objectQuestion),
+          neverNone,
+        ),
+      );
+      check(T, intNone);
+      check(T, intQuestion);
+      check(T, intStar);
+    }
+  }
+
+  test_bottom_bottom() {
+    void check(DartType T1, DartType T2) {
+      expect(typeSystem.isBottom(T1), isTrue, reason: _typeString(T1));
+      expect(typeSystem.isBottom(T2), isTrue, reason: _typeString(T2));
+      _checkLeastUpperBound(T1, T2, T2);
+    }
+
+    check(
+      neverNone,
+      typeParameterTypeNone(
+        typeParameter('T', bound: neverNone),
+      ),
+    );
+
+    check(
+      neverNone,
+      typeParameterTypeNone(
+        promoteTypeParameter(
+          typeParameter('T', bound: objectQuestion),
+          neverNone,
+        ),
+      ),
+    );
+  }
+
+  test_functionType2_parameters_named() {
+    FunctionType build(Map<String, DartType> namedTypes) {
+      return functionTypeNone(
+        returnType: voidNone,
+        parameters: namedTypes.entries.map((entry) {
+          return namedParameter(name: entry.key, type: entry.value);
+        }).toList(),
+      );
+    }
+
+    void check(Map<String, DartType> T1_named, Map<String, DartType> T2_named,
+        Map<String, DartType> expected_named) {
+      var T1 = build(T1_named);
+      var T2 = build(T2_named);
+      var expected = build(expected_named);
+      _checkLeastUpperBound(T1, T2, expected);
+    }
+
+    check({'a': intNone}, {}, {});
+    check({'a': intNone}, {'b': intNone}, {});
+
+    check({'a': intNone}, {'a': intNone}, {'a': intNone});
+    check({'a': intNone}, {'a': intQuestion}, {'a': intNone});
+
+    check({'a': intNone, 'b': doubleNone}, {'a': intNone}, {'a': intNone});
+  }
+
+  test_functionType2_parameters_optionalPositional() {
+    FunctionType build(List<DartType> positionalTypes) {
+      return functionTypeNone(
+        returnType: voidNone,
+        parameters: positionalTypes.map((type) {
+          return positionalParameter(type: type);
+        }).toList(),
+      );
+    }
+
+    void check(List<DartType> T1_positional, List<DartType> T2_positional,
+        DartType expected) {
+      var T1 = build(T1_positional);
+      var T2 = build(T2_positional);
+      _checkLeastUpperBound(T1, T2, expected);
+    }
+
+    check([intNone], [], build([]));
+    check([intNone, doubleNone], [intNone], build([intNone]));
+
+    check([intNone], [intNone], build([intNone]));
+    check([intNone], [intQuestion], build([intNone]));
+
+    // TODO(scheglov) Uncomment when DOWN is NNBD based.
+//    check([intNone], [intStar], build([intNone]));
+//    check([intNone], [doubleNone], build([neverNone]));
+
+    check([intNone], [numNone], build([intNone]));
+
+    check(
+      [doubleNone, numNone],
+      [numNone, intNone],
+      build([doubleNone, intNone]),
+    );
+  }
+
+  test_functionType2_parameters_required() {
+    FunctionType build(List<DartType> requiredTypes) {
+      return functionTypeNone(
+        returnType: voidNone,
+        parameters: requiredTypes.map((type) {
+          return requiredParameter(type: type);
+        }).toList(),
+      );
+    }
+
+    void check(List<DartType> T1_required, List<DartType> T2_required,
+        DartType expected) {
+      var T1 = build(T1_required);
+      var T2 = build(T2_required);
+      _checkLeastUpperBound(T1, T2, expected);
+    }
+
+    check([intNone], [], functionNone);
+
+    check([intNone], [intNone], build([intNone]));
+    check([intNone], [intQuestion], build([intNone]));
+
+    // TODO(scheglov) Uncomment when DOWN is NNBD based.
+//    check([intNone], [intStar], build([intNone]));
+//    check([intNone], [doubleNone], build([neverNone]));
+
+    check([intNone], [numNone], build([intNone]));
+
+    check(
+      [doubleNone, numNone],
+      [numNone, intNone],
+      build([doubleNone, intNone]),
+    );
+  }
+
+  test_functionType2_returnType() {
+    void check(DartType T1_ret, DartType T2_ret, DartType expected_ret) {
+      _checkLeastUpperBound(
+        functionTypeNone(returnType: T1_ret),
+        functionTypeNone(returnType: T2_ret),
+        functionTypeNone(returnType: expected_ret),
+      );
+    }
+
+    check(intNone, intNone, intNone);
+    check(intNone, intQuestion, intQuestion);
+    check(intNone, intStar, intStar);
+
+    check(intNone, numNone, numNone);
+    check(intQuestion, numNone, numQuestion);
+    check(intStar, numNone, numStar);
+
+    check(intNone, dynamicNone, dynamicNone);
+    check(intNone, neverNone, intNone);
+  }
+
+  test_functionType2_typeParameters() {
+    void check(FunctionType T1, FunctionType T2, DartType expected) {
+      _assertNullabilityNone(T1);
+      _assertNullabilityNone(T2);
+
+      _checkLeastUpperBound(T1, T2, expected);
+    }
+
+    check(
+      functionTypeNone(
+        returnType: voidNone,
+        typeFormals: [
+          typeParameter('T'),
+        ],
+      ),
+      functionTypeNone(returnType: voidNone),
+      functionNone,
+    );
+
+    check(
+      functionTypeNone(
+        returnType: voidNone,
+        typeFormals: [
+          typeParameter('T', bound: intNone),
+        ],
+      ),
+      functionTypeNone(
+        returnType: voidNone,
+        typeFormals: [
+          typeParameter('T', bound: numNone),
+        ],
+      ),
+      functionNone,
+    );
+
+    {
+      var T = typeParameter('T', bound: numNone);
+      var U = typeParameter('U', bound: numNone);
+      var R = typeParameter('R', bound: numNone);
+      check(
+        functionTypeNone(
+          returnType: typeParameterTypeNone(T),
+          typeFormals: [T],
+        ),
+        functionTypeNone(
+          returnType: typeParameterTypeNone(U),
+          typeFormals: [U],
+        ),
+        functionTypeNone(
+          returnType: typeParameterTypeNone(R),
+          typeFormals: [R],
+        ),
+      );
+    }
+  }
+
+  test_functionType_interfaceType() {
+    void check(FunctionType T1, InterfaceType T2, InterfaceType expected) {
+      _checkLeastUpperBound(T1, T2, expected);
+    }
+
+    check(
+      functionTypeNone(returnType: voidNone),
+      intNone,
+      objectNone,
+    );
+  }
+
+  test_functionType_interfaceType_Function() {
+    void check(FunctionType T1, InterfaceType T2, InterfaceType expected) {
+      _checkLeastUpperBound(T1, T2, expected);
+    }
+
+    void checkNone(FunctionType T1) {
+      _assertNullabilityNone(T1);
+      check(T1, functionNone, functionNone);
+    }
+
+    checkNone(functionTypeNone(returnType: voidNone));
+
+    checkNone(
+      functionTypeNone(
+        returnType: intNone,
+        parameters: [
+          requiredParameter(type: numQuestion),
+        ],
+      ),
+    );
+
+    check(
+      functionTypeQuestion(returnType: voidNone),
+      functionNone,
+      functionQuestion,
+    );
+  }
+
+  test_identical() {
+    void check(DartType type) {
+      _checkLeastUpperBound(type, type, type);
+    }
+
+    check(intNone);
+    check(intQuestion);
+    check(intStar);
+    check(listNone(intNone));
+  }
+
+  test_none_question() {
+    void check(DartType T1, DartType T2, DartType expected) {
+      _assertNullabilityNone(T1);
+      _assertNullabilityQuestion(T2);
+
+      _assertNotSpecial(T1);
+      _assertNotSpecial(T2);
+
+      _checkLeastUpperBound(T1, T2, expected);
+    }
+
+    check(doubleNone, intQuestion, numQuestion);
+    check(numNone, doubleQuestion, numQuestion);
+    check(numNone, intQuestion, numQuestion);
+  }
+
+  test_none_star() {
+    void check(DartType T1, DartType T2, DartType expected) {
+      _assertNullabilityNone(T1);
+      _assertNullabilityStar(T2);
+
+      _assertNotSpecial(T1);
+      _assertNotSpecial(T2);
+
+      _checkLeastUpperBound(T1, T2, expected);
+    }
+
+    check(doubleNone, intStar, numStar);
+    check(numNone, doubleStar, numStar);
+    check(numNone, intStar, numStar);
+  }
+
+  test_null_any() {
+    void check(DartType T1, DartType T2, DartType expected) {
+      var T1_str = _typeString(T1);
+      var T2_str = _typeString(T2);
+
+      expect(typeSystem.isNull(T1), isTrue, reason: 'isNull: $T1_str');
+      expect(typeSystem.isNull(T2), isFalse, reason: 'isNull: $T2_str');
+
+      expect(typeSystem.isTop(T1), isFalse, reason: 'isTop: $T1_str');
+      expect(typeSystem.isTop(T2), isFalse, reason: 'isTop: $T2_str');
+
+      expect(typeSystem.isBottom(T1), isFalse, reason: 'isBottom: $T1_str');
+      expect(typeSystem.isBottom(T2), isFalse, reason: 'isBottom: $T2_str');
+
+      _checkLeastUpperBound(T1, T2, expected);
+    }
+
+    check(nullNone, objectNone, objectQuestion);
+
+    check(nullNone, intNone, intQuestion);
+    check(nullNone, intQuestion, intQuestion);
+    check(nullNone, intStar, intQuestion);
+
+    check(nullQuestion, intNone, intQuestion);
+    check(nullQuestion, intQuestion, intQuestion);
+    check(nullQuestion, intStar, intQuestion);
+
+    check(nullStar, intNone, intQuestion);
+    check(nullStar, intQuestion, intQuestion);
+    check(nullStar, intStar, intQuestion);
+
+    check(nullNone, listNone(intNone), listQuestion(intNone));
+    check(nullNone, listQuestion(intNone), listQuestion(intNone));
+    check(nullNone, listStar(intNone), listQuestion(intNone));
+
+    check(nullNone, futureOrNone(intNone), futureOrQuestion(intNone));
+    check(nullNone, futureOrQuestion(intNone), futureOrQuestion(intNone));
+    check(nullNone, futureOrStar(intNone), futureOrQuestion(intNone));
+
+    check(nullNone, futureOrNone(intQuestion), futureOrNone(intQuestion));
+    check(nullNone, futureOrStar(intQuestion), futureOrStar(intQuestion));
+
+    check(
+      nullNone,
+      functionTypeNone(returnType: intNone),
+      functionTypeQuestion(returnType: intNone),
+    );
+  }
+
+  test_null_null() {
+    void check(DartType T1, DartType T2) {
+      var T1_str = _typeString(T1);
+      var T2_str = _typeString(T2);
+
+      expect(typeSystem.isNull(T1), isTrue, reason: 'isNull: $T1_str');
+      expect(typeSystem.isNull(T2), isTrue, reason: 'isNull: $T2_str');
+
+      expect(typeSystem.isBottom(T1), isFalse, reason: 'isBottom: $T1_str');
+      expect(typeSystem.isBottom(T2), isFalse, reason: 'isBottom: $T2_str');
+
+      _checkLeastUpperBound(T1, T2, T2);
+    }
+
+    check(nullNone, nullQuestion);
+    check(nullNone, nullStar);
+  }
+
+  test_object_any() {
+    void check(DartType T1, DartType T2, DartType expected) {
+      var T1_str = _typeString(T1);
+      var T2_str = _typeString(T2);
+
+      expect(typeSystem.isObject(T1), isTrue, reason: 'isObject: $T1_str');
+      expect(typeSystem.isObject(T2), isFalse, reason: 'isObject: $T2_str');
+
+      _checkLeastUpperBound(T1, T2, expected);
+    }
+
+    check(objectNone, intNone, objectNone);
+    check(objectNone, intQuestion, objectQuestion);
+    check(objectNone, intStar, objectNone);
+
+    check(objectNone, futureOrNone(intQuestion), objectQuestion);
+
+    check(futureOrNone(objectNone), intNone, futureOrNone(objectNone));
+    check(futureOrNone(objectNone), intQuestion, futureOrQuestion(objectNone));
+    check(futureOrNone(objectNone), intStar, futureOrNone(objectNone));
+  }
+
+  test_object_object() {
+    void check(DartType T1, DartType T2) {
+      var T1_str = _typeString(T1);
+      var T2_str = _typeString(T2);
+
+      expect(typeSystem.isObject(T1), isTrue, reason: 'isObject: $T1_str');
+      expect(typeSystem.isObject(T2), isTrue, reason: 'isObject: $T2_str');
+
+      _checkLeastUpperBound(T1, T2, T2);
+    }
+
+    check(futureOrNone(objectNone), objectNone);
+
+    check(
+      futureOrNone(
+        futureOrNone(objectNone),
+      ),
+      futureOrNone(objectNone),
+    );
+  }
+
+  test_question_question() {
+    void check(DartType T1, DartType T2, DartType expected) {
+      _assertNullabilityQuestion(T1);
+      _assertNullabilityQuestion(T2);
+
+      _assertNotSpecial(T1);
+      _assertNotSpecial(T2);
+
+      _checkLeastUpperBound(T1, T2, expected);
+    }
+
+    check(doubleQuestion, intQuestion, numQuestion);
+    check(numQuestion, doubleQuestion, numQuestion);
+    check(numQuestion, intQuestion, numQuestion);
+  }
+
+  test_question_star() {
+    void check(DartType T1, DartType T2, DartType expected) {
+      _assertNullabilityQuestion(T1);
+      _assertNullabilityStar(T2);
+
+      _assertNotSpecial(T1);
+      _assertNotSpecial(T2);
+
+      _checkLeastUpperBound(T1, T2, expected);
+    }
+
+    check(doubleQuestion, intStar, numQuestion);
+    check(numQuestion, doubleStar, numQuestion);
+    check(numQuestion, intStar, numQuestion);
+  }
+
+  test_star_star() {
+    void check(DartType T1, DartType T2, DartType expected) {
+      _assertNullabilityStar(T1);
+      _assertNullabilityStar(T2);
+
+      _assertNotSpecial(T1);
+      _assertNotSpecial(T2);
+
+      _checkLeastUpperBound(T1, T2, expected);
+    }
+
+    check(doubleStar, intStar, numStar);
+    check(numStar, doubleStar, numStar);
+    check(numStar, intStar, numStar);
+  }
+
+  test_top_any() {
+    void check(DartType T1, DartType T2) {
+      expect(typeSystem.isTop(T1), isTrue, reason: _typeString(T1));
+      expect(typeSystem.isTop(T2), isFalse, reason: _typeString(T2));
+      _checkLeastUpperBound(T1, T2, T1);
+    }
+
+    check(voidNone, objectNone);
+    check(voidNone, intNone);
+    check(voidNone, intQuestion);
+    check(voidNone, intStar);
+    check(voidNone, listNone(intNone));
+    check(voidNone, futureOrNone(intNone));
+
+    check(dynamicNone, objectNone);
+    check(dynamicNone, intNone);
+    check(dynamicNone, intQuestion);
+    check(dynamicNone, intStar);
+    check(dynamicNone, listNone(intNone));
+    check(dynamicNone, futureOrNone(intNone));
+
+    check(objectQuestion, objectNone);
+    check(objectQuestion, intNone);
+    check(objectQuestion, intQuestion);
+    check(objectQuestion, intStar);
+    check(objectQuestion, listNone(intNone));
+    check(objectQuestion, futureOrNone(intNone));
+
+    check(objectStar, objectNone);
+    check(objectStar, intNone);
+    check(objectStar, intQuestion);
+    check(objectStar, intStar);
+    check(objectStar, listNone(intNone));
+    check(objectStar, futureOrNone(intNone));
+
+    check(futureOrNone(voidNone), intNone);
+    check(futureOrQuestion(voidNone), intNone);
+    check(futureOrStar(voidNone), intNone);
+  }
+
+  test_top_top() {
+    void check(DartType T1, DartType T2) {
+      expect(typeSystem.isTop(T1), isTrue, reason: _typeString(T1));
+      expect(typeSystem.isTop(T2), isTrue, reason: _typeString(T2));
+      _checkLeastUpperBound(T1, T2, T1);
+    }
+
+    check(voidNone, dynamicNone);
+    check(voidNone, objectStar);
+    check(voidNone, objectQuestion);
+    check(voidNone, futureOrNone(voidNone));
+    check(voidNone, futureOrNone(dynamicNone));
+    check(voidNone, futureOrNone(objectQuestion));
+    check(voidNone, futureOrNone(objectStar));
+
+    check(dynamicNone, objectStar);
+    check(dynamicNone, objectQuestion);
+    check(dynamicNone, futureOrNone(voidNone));
+    check(dynamicNone, futureOrNone(dynamicNone));
+    check(dynamicNone, futureOrNone(objectQuestion));
+    check(dynamicNone, futureOrNone(objectStar));
+    check(
+      dynamicNone,
+      futureOrStar(objectStar),
+    );
+
+    check(objectQuestion, futureOrQuestion(voidNone));
+    check(objectQuestion, futureOrQuestion(dynamicNone));
+    check(objectQuestion, futureOrQuestion(objectNone));
+    check(objectQuestion, futureOrQuestion(objectQuestion));
+    check(objectQuestion, futureOrQuestion(objectStar));
+
+    check(objectQuestion, futureOrStar(voidNone));
+    check(objectQuestion, futureOrStar(dynamicNone));
+    check(objectQuestion, futureOrStar(objectNone));
+    check(objectQuestion, futureOrStar(objectQuestion));
+    check(objectQuestion, futureOrStar(objectStar));
+
+    check(objectStar, futureOrStar(voidNone));
+    check(objectStar, futureOrStar(dynamicNone));
+    check(objectStar, futureOrStar(objectNone));
+    check(objectStar, futureOrStar(objectQuestion));
+    check(objectStar, futureOrStar(objectStar));
+
+    check(futureOrNone(voidNone), objectQuestion);
+    check(futureOrNone(dynamicNone), objectQuestion);
+    check(futureOrNone(objectQuestion), objectQuestion);
+    check(futureOrNone(objectStar), objectQuestion);
+
+    check(futureOrNone(voidNone), futureOrNone(dynamicNone));
+    check(futureOrNone(voidNone), futureOrNone(objectQuestion));
+    check(futureOrNone(voidNone), futureOrNone(objectStar));
+    check(futureOrNone(dynamicNone), futureOrNone(objectQuestion));
+    check(futureOrNone(dynamicNone), futureOrNone(objectStar));
+  }
+
+  test_typeParameter_bound() {
+    void check(TypeParameterType T1, DartType T2, DartType expected) {
+      _assertNullabilityNone(T1);
+      _assertNullabilityNone(T2);
+
+      _assertNotSpecial(T1);
+      _assertNotSpecial(T2);
+
+      _checkLeastUpperBound(T1, T2, expected);
+    }
+
+    {
+      var T = typeParameter('T', bound: intNone);
+      check(typeParameterTypeNone(T), numNone, numNone);
+    }
+
+    {
+      var T = typeParameter('T', bound: intNone);
+      var U = typeParameter('U', bound: numNone);
+      check(typeParameterTypeNone(T), typeParameterTypeNone(U), numNone);
+    }
+
+    {
+      var T = typeParameter('T', bound: intNone);
+      var U = typeParameter('U', bound: numQuestion);
+      check(typeParameterTypeNone(T), typeParameterTypeNone(U), numQuestion);
+    }
+
+    {
+      var T = typeParameter('T', bound: intQuestion);
+      var U = typeParameter('U', bound: numNone);
+      check(typeParameterTypeNone(T), typeParameterTypeNone(U), numQuestion);
+    }
+
+    {
+      var T = typeParameter('T', bound: numNone);
+      var T_none = typeParameterTypeNone(T);
+      var U = typeParameter('U', bound: T_none);
+      check(T_none, typeParameterTypeNone(U), T_none);
+    }
+  }
+
+  void _assertNotBottom(DartType type) {
+    if (typeSystem.isBottom(type)) {
+      fail('isBottom must be false: ' + _typeString(type));
+    }
+  }
+
+  void _assertNotNull(DartType type) {
+    if (typeSystem.isNull(type)) {
+      fail('isNull must be false: ' + _typeString(type));
+    }
+  }
+
+  void _assertNotObject(DartType type) {
+    if (typeSystem.isObject(type)) {
+      fail('isObject must be false: ' + _typeString(type));
+    }
+  }
+
+  void _assertNotSpecial(DartType type) {
+    _assertNotBottom(type);
+    _assertNotNull(type);
+    _assertNotObject(type);
+    _assertNotTop(type);
+  }
+
+  void _assertNotTop(DartType type) {
+    if (typeSystem.isTop(type)) {
+      fail('isTop must be false: ' + _typeString(type));
+    }
+  }
+
+  void _assertNullability(DartType type, NullabilitySuffix expected) {
+    if ((type as TypeImpl).nullabilitySuffix != expected) {
+      fail('Expected $expected in ' + _typeString(type));
+    }
+  }
+
+  void _assertNullabilityNone(DartType type) {
+    _assertNullability(type, NullabilitySuffix.none);
+  }
+
+  void _assertNullabilityQuestion(DartType type) {
+    _assertNullability(type, NullabilitySuffix.question);
+  }
+
+  void _assertNullabilityStar(DartType type) {
+    _assertNullability(type, NullabilitySuffix.star);
+  }
+
+  void _checkLeastUpperBound(DartType T1, DartType T2, DartType expected) {
+    var expectedStr = _typeString(expected);
+
+    var result = typeSystem.getLeastUpperBound(T1, T2);
+    var resultStr = _typeString(result);
+    expect(result, expected, reason: '''
+expected: $expectedStr
+actual: $resultStr
+''');
+
+    // Check that the result is an upper bound.
+    expect(typeSystem.isSubtypeOf(T1, result), true);
+    expect(typeSystem.isSubtypeOf(T2, result), true);
+
+    // Check for symmetry.
+    result = typeSystem.getLeastUpperBound(T2, T1);
+    resultStr = _typeString(result);
+    expect(result, expected, reason: '''
+expected: $expectedStr
+actual: $resultStr
+''');
+  }
+}
+
+@reflectiveTest
+class _SubtypingTestBase with ElementsTypesMixin {
+  TypeProvider typeProvider;
+
+  TypeSystemImpl typeSystem;
+
+  FeatureSet get testFeatureSet {
+    return FeatureSet.forTesting();
+  }
+
+  void setUp() {
+    var analysisContext = TestAnalysisContext(
+      featureSet: testFeatureSet,
+    );
+    typeProvider = analysisContext.typeProvider;
+    typeSystem = analysisContext.typeSystem;
+  }
+
+  String _typeParametersStr(TypeImpl type) {
+    var typeStr = '';
+
+    var typeParameterCollector = _TypeParameterCollector();
+    DartTypeVisitor.visit(type, typeParameterCollector);
+    for (var typeParameter in typeParameterCollector.typeParameters) {
+      if (typeParameter is TypeParameterMember) {
+        var base = typeParameter.declaration;
+        var baseBound = base.bound as TypeImpl;
+        if (baseBound != null) {
+          var baseBoundStr = baseBound.toString(withNullability: true);
+          typeStr += ', ${typeParameter.name} extends ' + baseBoundStr;
+        }
+
+        var bound = typeParameter.bound as TypeImpl;
+        var boundStr = bound.toString(withNullability: true);
+        typeStr += ', ${typeParameter.name} & ' + boundStr;
+      } else {
+        var bound = typeParameter.bound as TypeImpl;
+        if (bound != null) {
+          var boundStr = bound.toString(withNullability: true);
+          typeStr += ', ${typeParameter.name} extends ' + boundStr;
+        }
+      }
+    }
+    return typeStr;
+  }
+
+  String _typeString(TypeImpl type) {
+    if (type == null) return null;
+    return type.toString(withNullability: true) + _typeParametersStr(type);
+  }
+}
+
+class _TypeParameterCollector extends DartTypeVisitor<void> {
+  final Set<TypeParameterElement> typeParameters = Set();
+
+  /// We don't need to print bounds for these type parameters, because
+  /// they are already included into the function type itself, and cannot
+  /// be promoted.
+  final Set<TypeParameterElement> functionTypeParameters = Set();
+
+  @override
+  void defaultDartType(DartType type) {
+    throw UnimplementedError('(${type.runtimeType}) $type');
+  }
+
+  @override
+  void visitDynamicType(DynamicTypeImpl type) {}
+
+  @override
+  void visitFunctionType(FunctionType type) {
+    functionTypeParameters.addAll(type.typeFormals);
+    for (var typeParameter in type.typeFormals) {
+      var bound = typeParameter.bound;
+      if (bound != null) {
+        DartTypeVisitor.visit(bound, this);
+      }
+    }
+    for (var parameter in type.parameters) {
+      DartTypeVisitor.visit(parameter.type, this);
+    }
+    DartTypeVisitor.visit(type.returnType, this);
+  }
+
+  @override
+  void visitInterfaceType(InterfaceType type) {
+    for (var typeArgument in type.typeArguments) {
+      DartTypeVisitor.visit(typeArgument, this);
+    }
+  }
+
+  @override
+  void visitNeverType(NeverTypeImpl type) {}
+
+  @override
+  void visitTypeParameterType(TypeParameterType type) {
+    if (!functionTypeParameters.contains(type.element)) {
+      typeParameters.add(type.element);
+    }
+  }
+
+  @override
+  void visitVoidType(VoidType type) {}
+}
diff --git a/pkg/analyzer/test/src/dart/resolution/class_test.dart b/pkg/analyzer/test/src/dart/resolution/class_test.dart
index 752cb6f..57da4e7 100644
--- a/pkg/analyzer/test/src/dart/resolution/class_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/class_test.dart
@@ -154,28 +154,6 @@
     assertElement(findNode.simple('foo = 0;'), findElement.setter('foo'));
   }
 
-  test_conflictingGenericInterfaces_simple() async {
-    await resolveTestCode('''
-class I<T> {}
-class A implements I<int> {}
-class B implements I<String> {}
-class C extends A implements B {}
-''');
-    assertTestErrorsWithCodes(
-        [CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES]);
-  }
-
-  test_conflictingGenericInterfaces_viaMixin() async {
-    await resolveTestCode('''
-class I<T> {}
-class A implements I<int> {}
-class B implements I<String> {}
-class C extends A with B {}
-''');
-    assertTestErrorsWithCodes(
-        [CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES]);
-  }
-
   test_element_allSupertypes() async {
     await resolveTestCode(r'''
 class A {}
@@ -198,11 +176,11 @@
     var d = findElement.class_('D');
     var e = findElement.class_('E');
 
-    var typeA = interfaceType(a);
-    var typeB = interfaceType(b);
-    var typeC = interfaceType(c);
-    var typeD = interfaceType(d);
-    var typeE = interfaceType(e);
+    var typeA = interfaceTypeStar(a);
+    var typeB = interfaceTypeStar(b);
+    var typeC = interfaceTypeStar(c);
+    var typeD = interfaceTypeStar(d);
+    var typeE = interfaceTypeStar(e);
 
     assertElementTypes(
       findElement.class_('X1').allSupertypes,
@@ -244,16 +222,16 @@
     assertElementTypes(
       findElement.class_('X1').allSupertypes,
       [
-        interfaceType(a, typeArguments: [stringType]),
+        interfaceTypeStar(a, typeArguments: [stringType]),
         objectType
       ],
     );
     assertElementTypes(
       findElement.class_('X2').allSupertypes,
       [
-        interfaceType(b, typeArguments: [
+        interfaceTypeStar(b, typeArguments: [
           stringType,
-          interfaceType(listElement, typeArguments: [intType])
+          interfaceTypeStar(listElement, typeArguments: [intType])
         ]),
         objectType
       ],
@@ -261,8 +239,8 @@
     assertElementTypes(
       findElement.class_('X3').allSupertypes,
       [
-        interfaceType(c, typeArguments: [doubleType]),
-        interfaceType(b, typeArguments: [intType, doubleType]),
+        interfaceTypeStar(c, typeArguments: [doubleType]),
+        interfaceTypeStar(b, typeArguments: [intType, doubleType]),
         objectType
       ],
     );
@@ -283,7 +261,7 @@
     var c = findElement.class_('C');
     assertElementTypes(
       findElement.class_('X').allSupertypes,
-      [interfaceType(a), interfaceType(b), interfaceType(c)],
+      [interfaceTypeStar(a), interfaceTypeStar(b), interfaceTypeStar(c)],
     );
   }
 
diff --git a/pkg/analyzer/test/src/dart/resolution/constant_test.dart b/pkg/analyzer/test/src/dart/resolution/constant_test.dart
index d09efd3..cacc3459 100644
--- a/pkg/analyzer/test/src/dart/resolution/constant_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/constant_test.dart
@@ -116,4 +116,69 @@
     expect(typeArgument.element.enclosingElement, elementF);
     assertElementTypeStrings(typeArgument.typeArguments, ['double']);
   }
+
+  test_imported_prefixedIdentifier_staticField_class() async {
+    newFile('/test/lib/a.dart', content: r'''
+const a = C.f;
+
+class C {
+  static const int f = 42;
+}
+''');
+    await resolveTestCode(r'''
+import 'a.dart';
+''');
+
+    var import_ = findElement.importFind('package:test/a.dart');
+    var a = import_.topVar('a') as ConstVariableElement;
+    expect(a.computeConstantValue().toIntValue(), 42);
+  }
+
+  test_imported_prefixedIdentifier_staticField_extension() async {
+    newFile('/test/lib/a.dart', content: r'''
+const a = E.f;
+
+extension E on int {
+  static const int f = 42;
+}
+''');
+    await resolveTestCode(r'''
+import 'a.dart';
+''');
+
+    var import_ = findElement.importFind('package:test/a.dart');
+    var a = import_.topVar('a') as ConstVariableElement;
+    expect(a.computeConstantValue().toIntValue(), 42);
+  }
+
+  test_imported_prefixedIdentifier_staticField_mixin() async {
+    newFile('/test/lib/a.dart', content: r'''
+const a = M.f;
+
+class C {}
+
+mixin M on C {
+  static const int f = 42;
+}
+''');
+    await resolveTestCode(r'''
+import 'a.dart';
+''');
+
+    var import_ = findElement.importFind('package:test/a.dart');
+    var a = import_.topVar('a') as ConstVariableElement;
+    expect(a.computeConstantValue().toIntValue(), 42);
+  }
+
+  test_local_prefixedIdentifier_staticField_extension() async {
+    await assertNoErrorsInCode(r'''
+const a = E.f;
+
+extension E on int {
+  static const int f = 42;
+}
+''');
+    var a = findElement.topVar('a') as ConstVariableElement;
+    expect(a.computeConstantValue().toIntValue(), 42);
+  }
 }
diff --git a/pkg/analyzer/test/src/dart/resolution/for_element_test.dart b/pkg/analyzer/test/src/dart/resolution/for_element_test.dart
index b8b7e2a..abc3a93 100644
--- a/pkg/analyzer/test/src/dart/resolution/for_element_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/for_element_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 'package:analyzer/dart/analysis/features.dart';
+import 'package:analyzer/src/generated/engine.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import 'driver_resolution.dart';
@@ -9,13 +11,14 @@
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(ForEachElementTest);
+    defineReflectiveTests(ForEachElementWithNnbdTest);
     defineReflectiveTests(ForLoopElementTest);
   });
 }
 
 @reflectiveTest
 class ForEachElementTest extends DriverResolutionTest {
-  test_declaredIdentifierScope() async {
+  test_withDeclaration_scope() async {
     await resolveTestCode(r'''
 main() {
   <int>[for (var i in [1, 2, 3]) i]; // 1
@@ -33,6 +36,27 @@
       findNode.simple('i in [1.1').staticElement,
     );
   }
+
+  test_withIdentifier_topLevelVariable() async {
+    await assertNoErrorsInCode(r'''
+int v = 0;
+main() {
+  <int>[for (v in [1, 2, 3]) v];
+}
+''');
+    assertElement(
+      findNode.simple('v];'),
+      findElement.topGet('v'),
+    );
+  }
+}
+
+@reflectiveTest
+class ForEachElementWithNnbdTest extends ForEachElementTest {
+  @override
+  AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+    ..contextFeatures = FeatureSet.forTesting(
+        sdkVersion: '2.6.0', additionalFeatures: [Feature.non_nullable]);
 }
 
 @reflectiveTest
diff --git a/pkg/analyzer/test/src/dart/resolution/function_type_alias_test.dart b/pkg/analyzer/test/src/dart/resolution/function_type_alias_test.dart
index 3d89872..774f965 100644
--- a/pkg/analyzer/test/src/dart/resolution/function_type_alias_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/function_type_alias_test.dart
@@ -25,7 +25,7 @@
     FunctionType type = findElement.topVar('g').type;
     assertElementTypeString(type, 'int Function()');
 
-    var typedefG = findElement.genericTypeAlias('G');
+    var typedefG = findElement.functionTypeAlias('G');
     var functionG = typedefG.function;
 
     expect(type.element, functionG);
diff --git a/pkg/analyzer/test/src/dart/resolution/generic_function_type_test.dart b/pkg/analyzer/test/src/dart/resolution/generic_function_type_test.dart
index ae124eb..e1ff7a0 100644
--- a/pkg/analyzer/test/src/dart/resolution/generic_function_type_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/generic_function_type_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/dart/ast/ast.dart';
+import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import 'driver_resolution.dart';
@@ -47,6 +48,17 @@
 ''');
   }
 
+  test_metadata_typeParameter() async {
+    await assertNoErrorsInCode(r'''
+const a = 42;
+
+Function<@a T>() x;
+''');
+    var T = findNode.typeParameter('T');
+    var annotation = T.declaredElement.metadata[0];
+    expect(annotation.element, findElement.topGet('a'));
+  }
+
   /// Test that when multiple [GenericFunctionType]s are used in a
   /// [FunctionDeclaration], all of them are resolved correctly.
   test_typeAnnotation_function() async {
diff --git a/pkg/analyzer/test/src/dart/resolution/generic_type_alias_test.dart b/pkg/analyzer/test/src/dart/resolution/generic_type_alias_test.dart
index 36c3d81..2760699 100644
--- a/pkg/analyzer/test/src/dart/resolution/generic_type_alias_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/generic_type_alias_test.dart
@@ -152,7 +152,7 @@
     FunctionType type = findElement.topVar('g').type;
     assertElementTypeString(type, 'int Function(double)');
 
-    var typedefG = findElement.genericTypeAlias('G');
+    var typedefG = findElement.functionTypeAlias('G');
     var functionG = typedefG.function;
 
     expect(type.element, functionG);
@@ -169,7 +169,7 @@
 
 typedef F<T extends A> = B<T> Function<U extends B>(T a, U b);
 ''');
-    var f = findElement.genericTypeAlias('F');
+    var f = findElement.functionTypeAlias('F');
     expect(f.typeParameters, hasLength(1));
 
     var t = f.typeParameters[0];
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 9ca7b0d..f521fdb 100644
--- a/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/method_invocation_test.dart
@@ -1160,7 +1160,7 @@
 
     var foo = invocation.function as PrefixedIdentifier;
     assertType(foo, 'T Function<T>(T, T)');
-    assertElement(foo.identifier, import.topGetter('foo'));
+    assertElement(foo.identifier, import.topGet('foo'));
     assertType(foo.identifier, 'T Function<T>(T, T)');
 
     assertImportPrefix(foo.prefix, import.prefix);
diff --git a/pkg/analyzer/test/src/dart/resolution/mixin_test.dart b/pkg/analyzer/test/src/dart/resolution/mixin_test.dart
index 942563e..e84b1ab 100644
--- a/pkg/analyzer/test/src/dart/resolution/mixin_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/mixin_test.dart
@@ -95,7 +95,7 @@
     var mElement = findElement.mixin('M');
 
     var aElement = findElement.class_('A');
-    assertElementTypes(aElement.mixins, [interfaceType(mElement)]);
+    assertElementTypes(aElement.mixins, [interfaceTypeStar(mElement)]);
 
     var mRef = findNode.typeName('M {} // A');
     assertTypeName(mRef, mElement, 'M');
@@ -110,7 +110,7 @@
     var mElement = findElement.mixin('M');
 
     var aElement = findElement.class_('A');
-    assertElementTypes(aElement.mixins, [interfaceType(mElement)]);
+    assertElementTypes(aElement.mixins, [interfaceTypeStar(mElement)]);
 
     var mRef = findNode.typeName('M;');
     assertTypeName(mRef, mElement, 'M');
@@ -129,17 +129,6 @@
     assertTypeNull(aRef);
   }
 
-  test_conflictingGenericInterfaces() async {
-    await assertErrorsInCode('''
-class I<T> {}
-class A implements I<int> {}
-class B implements I<String> {}
-mixin M on A implements B {}
-''', [
-      error(CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES, 75, 28),
-    ]);
-  }
-
   test_element() async {
     await assertNoErrorsInCode(r'''
 mixin M {}
@@ -156,7 +145,7 @@
     expect(element.isEnum, isFalse);
     expect(element.isMixin, isTrue);
     expect(element.isMixinApplication, isFalse);
-    expect(interfaceType(element).isObject, isFalse);
+    expect(interfaceTypeStar(element).isObject, isFalse);
     expect(element.isDartCoreObject, isFalse);
 
     assertElementTypes(element.superclassConstraints, [objectType]);
@@ -178,11 +167,16 @@
     var c = findElement.class_('C');
     assertElementTypes(
       findElement.mixin('M1').allSupertypes,
-      [interfaceType(a), interfaceType(b), objectType],
+      [interfaceTypeStar(a), interfaceTypeStar(b), objectType],
     );
     assertElementTypes(
       findElement.mixin('M2').allSupertypes,
-      [interfaceType(a), objectType, interfaceType(b), interfaceType(c)],
+      [
+        interfaceTypeStar(a),
+        objectType,
+        interfaceTypeStar(b),
+        interfaceTypeStar(c)
+      ],
     );
   }
 
@@ -200,15 +194,15 @@
     assertElementTypes(
       findElement.mixin('M1').allSupertypes,
       [
-        interfaceType(a, typeArguments: [intType, doubleType]),
+        interfaceTypeStar(a, typeArguments: [intType, doubleType]),
         objectType
       ],
     );
     assertElementTypes(
       findElement.mixin('M2').allSupertypes,
       [
-        interfaceType(b, typeArguments: [stringType]),
-        interfaceType(a, typeArguments: [intType, stringType]),
+        interfaceTypeStar(b, typeArguments: [stringType]),
+        interfaceTypeStar(a, typeArguments: [intType, stringType]),
         objectType
       ],
     );
@@ -357,7 +351,7 @@
     var randomElement = mathImport.importedLibrary.getType('Random');
 
     var element = findElement.mixin('M');
-    assertElementTypes(element.interfaces, [interfaceType(randomElement)]);
+    assertElementTypes(element.interfaces, [interfaceTypeStar(randomElement)]);
 
     var typeRef = findNode.typeName('Random {}');
     assertTypeName(typeRef, randomElement, 'Random',
@@ -920,7 +914,7 @@
 
     var element = findElement.mixin('M');
     assertElementTypes(element.superclassConstraints, [
-      interfaceType(randomElement),
+      interfaceTypeStar(randomElement),
     ]);
 
     var typeRef = findNode.typeName('Random {}');
@@ -999,7 +993,7 @@
     var a = findElement.mixin('A');
     var b = findElement.mixin('B');
     assertElementTypes(b.superclassConstraints, [
-      interfaceType(a),
+      interfaceTypeStar(a),
     ]);
   }
 
diff --git a/pkg/analyzer/test/src/dart/resolution/non_nullable_test.dart b/pkg/analyzer/test/src/dart/resolution/non_nullable_test.dart
index 3190200..86ebbb9 100644
--- a/pkg/analyzer/test/src/dart/resolution/non_nullable_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/non_nullable_test.dart
@@ -5,6 +5,8 @@
 import 'package:analyzer/src/dart/analysis/experiments.dart';
 import 'package:analyzer/src/dart/error/syntactic_errors.dart';
 import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/type_system.dart';
+import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import 'driver_resolution.dart';
@@ -70,6 +72,26 @@
     );
   }
 
+  test_library_typeProvider_typeSystem() async {
+    newFile('/test/lib/a.dart', content: r'''
+class A {}
+''');
+    await resolveTestCode(r'''
+// @dart = 2.5
+import 'a.dart';
+''');
+    var testLibrary = result.libraryElement;
+    var testTypeSystem = testLibrary.typeSystem as TypeSystemImpl;
+    assertElementTypeString(testLibrary.typeProvider.intType, 'int*');
+    expect(testTypeSystem.isNonNullableByDefault, isFalse);
+
+    var aImport = findElement.importFind('package:test/a.dart');
+    var aLibrary = aImport.importedLibrary;
+    var aTypeSystem = aLibrary.typeSystem as TypeSystemImpl;
+    assertElementTypeString(aLibrary.typeProvider.intType, 'int');
+    expect(aTypeSystem.isNonNullableByDefault, isTrue);
+  }
+
   test_local_getterNullAwareAccess_interfaceType() async {
     await resolveTestCode(r'''
 main() {
diff --git a/pkg/analyzer/test/src/dart/resolution/resolution.dart b/pkg/analyzer/test/src/dart/resolution/resolution.dart
index efd4af8..803474c 100644
--- a/pkg/analyzer/test/src/dart/resolution/resolution.dart
+++ b/pkg/analyzer/test/src/dart/resolution/resolution.dart
@@ -13,6 +13,7 @@
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/member.dart';
 import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/type_algebra.dart';
 import 'package:analyzer/src/dart/error/hint_codes.dart';
 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
 import 'package:analyzer/src/test_utilities/find_element.dart';
@@ -84,10 +85,7 @@
 
     expect(actual.declaration, same(expectedBase));
 
-    var actualMapString = actual.substitution.map.map(
-      (k, v) => MapEntry(k.name, '$v'),
-    );
-    expect(actualMapString, expectedSubstitution);
+    assertSubstitution(actual.substitution, expectedSubstitution);
   }
 
   /// Assert that the given [identifier] is a reference to a class, in the
@@ -154,9 +152,7 @@
   }
 
   void assertElementTypeString(DartType type, String expected) {
-    TypeImpl typeImpl = type;
-    expect(typeImpl.toString(withNullability: typeToStringWithNullability),
-        expected);
+    expect(typeString(type), expected);
   }
 
   void assertElementTypeStrings(List<DartType> types, List<String> expected) {
@@ -275,8 +271,15 @@
         expectedPrefix: expectedPrefix);
   }
 
-  void assertInvokeType(InvocationExpression node, String expected) {
-    TypeImpl actual = node.staticInvokeType;
+  void assertInvokeType(Expression node, String expected) {
+    DartType actual;
+    if (node is BinaryExpression) {
+      actual = node.staticInvokeType;
+    } else if (node is InvocationExpression) {
+      actual = node.staticInvokeType;
+    } else {
+      fail('Unsupported node: (${node.runtimeType}) $node');
+    }
     expect(typeString(actual), expected);
   }
 
@@ -307,10 +310,7 @@
     var actual = actualElement as Member;
     expect(actual.declaration, same(expectedBase));
 
-    var actualMapString = actual.substitution.map.map(
-      (k, v) => MapEntry(k.name, '$v'),
-    );
-    expect(actualMapString, expectedSubstitution);
+    assertSubstitution(actual.substitution, expectedSubstitution);
   }
 
   void assertMethodInvocation(
@@ -373,6 +373,15 @@
     expect(expression.staticParameterElement, expected);
   }
 
+  void assertParameterType(Expression expression, String expected) {
+    var parameterElement = expression.staticParameterElement;
+    if (expected == null) {
+      expect(parameterElement, isNull);
+    } else {
+      assertElementTypeString(parameterElement.type, expected);
+    }
+  }
+
   void assertPropertyAccess(
     PropertyAccess access,
     Element expectedElement,
@@ -382,6 +391,16 @@
     assertType(access, expectedType);
   }
 
+  void assertSubstitution(
+    MapSubstitution substitution,
+    Map<String, String> expected,
+  ) {
+    var actualMapString = substitution.map.map(
+      (k, v) => MapEntry(k.name, '$v'),
+    );
+    expect(actualMapString, expected);
+  }
+
   void assertSuperExpression(SuperExpression superExpression) {
     // TODO(scheglov) I think `super` does not have type itself.
     // It is just a signal to look for implemented method in the supertype.
diff --git a/pkg/analyzer/test/src/dart/resolution/type_inference/conditional_expression_test.dart b/pkg/analyzer/test/src/dart/resolution/type_inference/conditional_expression_test.dart
index ec7660c..2e27d71 100644
--- a/pkg/analyzer/test/src/dart/resolution/type_inference/conditional_expression_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/type_inference/conditional_expression_test.dart
@@ -49,4 +49,13 @@
 ''');
     assertInvokeType(findNode.methodInvocation('d)'), 'bool Function()');
   }
+
+  test_type() async {
+    await assertNoErrorsInCode('''
+main(bool b) {
+  return b ? 42 : null;
+}
+''');
+    assertType(findNode.conditionalExpression('b ?'), 'int?');
+  }
 }
diff --git a/pkg/analyzer/test/src/dart/resolution/type_inference/function_expression_test.dart b/pkg/analyzer/test/src/dart/resolution/type_inference/function_expression_test.dart
new file mode 100644
index 0000000..0b63163
--- /dev/null
+++ b/pkg/analyzer/test/src/dart/resolution/type_inference/function_expression_test.dart
@@ -0,0 +1,73 @@
+// Copyright (c) 2019, 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/analysis/features.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../driver_resolution.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(FunctionExpressionTest);
+    defineReflectiveTests(FunctionExpressionWithNnbdTest);
+  });
+}
+
+@reflectiveTest
+class FunctionExpressionTest extends DriverResolutionTest {
+  test_returnType_notNullable() async {
+    await resolveTestCode('''
+var v = (bool b) {
+  if (b) return 0;
+  return 1.2;
+};
+''');
+    var element = findNode.functionExpression('(bool').declaredElement;
+    assertElementTypeString(element.returnType, 'num');
+  }
+
+  test_returnType_null_hasReturn() async {
+    await resolveTestCode('''
+var v = (bool b) {
+  if (b) return;
+};
+''');
+    var element = findNode.functionExpression('(bool').declaredElement;
+    assertElementTypeString(element.returnType, 'Null');
+  }
+
+  test_returnType_null_noReturn() async {
+    await resolveTestCode('''
+var v = () {};
+''');
+    var element = findNode.functionExpression('() {}').declaredElement;
+    assertElementTypeString(element.returnType, 'Null');
+  }
+
+  test_returnType_nullable() async {
+    await resolveTestCode('''
+var v = (bool b) {
+  if (b) return 0;
+};
+''');
+    var element = findNode.functionExpression('(bool').declaredElement;
+    if (typeToStringWithNullability) {
+      assertElementTypeString(element.returnType, 'int?');
+    } else {
+      assertElementTypeString(element.returnType, 'int');
+    }
+  }
+}
+
+@reflectiveTest
+class FunctionExpressionWithNnbdTest extends FunctionExpressionTest {
+  @override
+  AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+    ..contextFeatures = new FeatureSet.forTesting(
+        sdkVersion: '2.6.0', additionalFeatures: [Feature.non_nullable]);
+
+  @override
+  bool get typeToStringWithNullability => true;
+}
diff --git a/pkg/analyzer/test/src/dart/resolution/type_inference/list_literal_test.dart b/pkg/analyzer/test/src/dart/resolution/type_inference/list_literal_test.dart
index a2f10f6..d5ebe59 100644
--- a/pkg/analyzer/test/src/dart/resolution/type_inference/list_literal_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/type_inference/list_literal_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 'package:analyzer/dart/analysis/features.dart';
+import 'package:analyzer/src/generated/engine.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import '../driver_resolution.dart';
@@ -9,6 +11,7 @@
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(ListLiteralTest);
+    defineReflectiveTests(ListLiteralWithNnbdTest);
   });
 }
 
@@ -283,3 +286,35 @@
     assertType(findNode.listLiteral('['), 'List<num>');
   }
 }
+
+@reflectiveTest
+class ListLiteralWithNnbdTest extends DriverResolutionTest {
+  @override
+  AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+    ..contextFeatures = new FeatureSet.forTesting(
+        sdkVersion: '2.6.0', additionalFeatures: [Feature.non_nullable]);
+
+  @override
+  bool get typeToStringWithNullability => true;
+
+  test_nested_hasNull_1() async {
+    await assertNoErrorsInCode('''
+main() {
+  [[0], null];
+}
+''');
+    assertType(findNode.listLiteral('[0'), 'List<int>');
+    assertType(findNode.listLiteral('[[0'), 'List<List<int>?>');
+  }
+
+  test_nested_hasNull_2() async {
+    await assertNoErrorsInCode('''
+main() {
+  [[0], [1, null]];
+}
+''');
+    assertType(findNode.listLiteral('[0'), 'List<int>');
+    assertType(findNode.listLiteral('[1,'), 'List<int?>');
+    assertType(findNode.listLiteral('[[0'), 'List<List<int?>>');
+  }
+}
diff --git a/pkg/analyzer/test/src/dart/resolution/type_inference/test_all.dart b/pkg/analyzer/test/src/dart/resolution/type_inference/test_all.dart
index baeec95..05e682f 100644
--- a/pkg/analyzer/test/src/dart/resolution/type_inference/test_all.dart
+++ b/pkg/analyzer/test/src/dart/resolution/type_inference/test_all.dart
@@ -8,6 +8,7 @@
 import 'conditional_expression_test.dart' as conditional_expression;
 import 'equality_expressions_test.dart' as equality_expressions;
 import 'extension_methods_test.dart' as extension_methods;
+import 'function_expression_test.dart' as function_expression;
 import 'list_literal_test.dart' as list_literal;
 import 'logical_boolean_expressions_test.dart' as logical_boolean_expressions;
 import 'map_literal_test.dart' as map_literal;
@@ -24,6 +25,7 @@
     conditional_expression.main();
     equality_expressions.main();
     extension_methods.main();
+    function_expression.main();
     list_literal.main();
     logical_boolean_expressions.main();
     map_literal.main();
diff --git a/pkg/analyzer/test/src/diagnostics/conflicting_generic_interfaces_test.dart b/pkg/analyzer/test/src/diagnostics/conflicting_generic_interfaces_test.dart
new file mode 100644
index 0000000..b9a0264
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/conflicting_generic_interfaces_test.dart
@@ -0,0 +1,127 @@
+// Copyright (c) 2019, 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/analysis/features.dart';
+import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/driver_resolution.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(ConflictingGenericInterfacesTest);
+    defineReflectiveTests(ConflictingGenericInterfacesWithNnbdTest);
+  });
+}
+
+@reflectiveTest
+class ConflictingGenericInterfacesTest extends DriverResolutionTest {
+  disabled_test_hierarchyLoop_infinite() async {
+    // There is an interface conflict here due to a loop in the class
+    // hierarchy leading to an infinite set of implemented types; this loop
+    // shouldn't cause non-termination.
+
+    // TODO(paulberry): this test is currently disabled due to non-termination
+    // bugs elsewhere in the analyzer.
+    await assertErrorsInCode('''
+class A<T> implements B<List<T>> {}
+class B<T> implements A<List<T>> {}
+''', [
+      error(CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES, 0, 0),
+    ]);
+  }
+
+  test_class_extends_implements() async {
+    await assertErrorsInCode('''
+class I<T> {}
+class A implements I<int> {}
+class B implements I<String> {}
+class C extends A implements B {}
+''', [
+      error(CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES, 75, 33),
+    ]);
+  }
+
+  test_class_extends_with() async {
+    await assertErrorsInCode('''
+class I<T> {}
+class A implements I<int> {}
+class B implements I<String> {}
+class C extends A with B {}
+''', [
+      error(CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES, 75, 27),
+    ]);
+  }
+
+  test_classTypeAlias_extends_with() async {
+    await assertErrorsInCode('''
+class I<T> {}
+class A implements I<int> {}
+mixin M implements I<String> {}
+class C = A with M;
+''', [
+      error(CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES, 75, 19),
+    ]);
+  }
+
+  test_mixin_on_implements() async {
+    await assertErrorsInCode('''
+class I<T> {}
+class A implements I<int> {}
+class B implements I<String> {}
+mixin M on A implements B {}
+''', [
+      error(CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES, 75, 28),
+    ]);
+  }
+}
+
+@reflectiveTest
+class ConflictingGenericInterfacesWithNnbdTest
+    extends ConflictingGenericInterfacesTest {
+  @override
+  AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
+    ..contextFeatures = new FeatureSet.forTesting(
+        sdkVersion: '2.6.0', additionalFeatures: [Feature.non_nullable]);
+
+  test_class_extends_implements_nullability() async {
+    await assertErrorsInCode('''
+class I<T> {}
+class A implements I<int> {}
+class B implements I<int?> {}
+class C extends A implements B {}
+''', [
+      error(CompileTimeErrorCode.CONFLICTING_GENERIC_INTERFACES, 73, 33),
+    ]);
+  }
+
+  test_class_extends_implements_optOut() async {
+    newFile('/test/lib/a.dart', content: r'''
+class I<T> {}
+class A implements I<int> {}
+class B implements I<int?> {}
+''');
+    await assertNoErrorsInCode('''
+// @dart = 2.5
+import 'a.dart';
+
+class C extends A implements B {}
+''');
+  }
+
+  test_class_extends_optIn_implements_optOut() async {
+    newFile('/test/lib/a.dart', content: r'''
+class A<T> {}
+
+class B extends A<int> {}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+class C extends B implements A<int> {}
+''');
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/default_list_constructor_mismatch_test.dart b/pkg/analyzer/test/src/diagnostics/default_list_constructor_mismatch_test.dart
index 0ed9acc..5e19d96 100644
--- a/pkg/analyzer/test/src/diagnostics/default_list_constructor_mismatch_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/default_list_constructor_mismatch_test.dart
@@ -51,9 +51,6 @@
 ''');
   }
 
-  @FailingTest(
-    reason: 'The type of the parameterElement for `3` is non-nullable',
-  )
   test_optOut() async {
     await assertNoErrorsInCode('''
 // @dart = 2.2
diff --git a/pkg/analyzer/test/src/diagnostics/deferred_import_of_extension_test.dart b/pkg/analyzer/test/src/diagnostics/deferred_import_of_extension_test.dart
index 39ae942..bfd4e14 100644
--- a/pkg/analyzer/test/src/diagnostics/deferred_import_of_extension_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/deferred_import_of_extension_test.dart
@@ -71,4 +71,12 @@
 }
 ''');
   }
+
+  test_invalidUri() {
+    assertErrorsInCode('''
+import '' deferred as foo;
+''', [
+      error(CompileTimeErrorCode.INVALID_URI, 7, 2),
+    ]);
+  }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/mixed_return_types_test.dart b/pkg/analyzer/test/src/diagnostics/mixed_return_types_test.dart
deleted file mode 100644
index 8cbb93f..0000000
--- a/pkg/analyzer/test/src/diagnostics/mixed_return_types_test.dart
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) 2019, 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/driver_resolution.dart';
-
-main() {
-  defineReflectiveSuite(() {
-    defineReflectiveTests(MixedReturnTypesTest);
-  });
-}
-
-@reflectiveTest
-class MixedReturnTypesTest extends DriverResolutionTest {
-  test_method() async {
-    await assertErrorsInCode('''
-class C {
-  m(int x) {
-    if (x < 0) {
-      return;
-    }
-    return 0;
-  }
-}
-''', [
-      error(StaticWarningCode.MIXED_RETURN_TYPES, 46, 6),
-      error(StaticWarningCode.MIXED_RETURN_TYPES, 64, 6),
-    ]);
-  }
-
-  test_topLevelFunction() async {
-    await assertErrorsInCode('''
-f(int x) {
-  if (x < 0) {
-    return;
-  }
-  return 0;
-}
-''', [
-      error(StaticWarningCode.MIXED_RETURN_TYPES, 30, 6),
-      error(StaticWarningCode.MIXED_RETURN_TYPES, 44, 6),
-    ]);
-  }
-}
diff --git a/pkg/analyzer/test/src/diagnostics/non_null_opt_out_test.dart b/pkg/analyzer/test/src/diagnostics/non_null_opt_out_test.dart
index 45a9406..546aea3 100644
--- a/pkg/analyzer/test/src/diagnostics/non_null_opt_out_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/non_null_opt_out_test.dart
@@ -4,8 +4,13 @@
 
 //import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/dart/analysis/features.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/member.dart';
 import 'package:analyzer/src/dart/error/syntactic_errors.dart';
 import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/test_utilities/find_element.dart';
+import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import '../dart/resolution/driver_resolution.dart';
@@ -21,7 +26,736 @@
   @override
   AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
     ..contextFeatures = new FeatureSet.forTesting(
-        sdkVersion: '2.3.0', additionalFeatures: [Feature.non_nullable]);
+        sdkVersion: '2.6.0', additionalFeatures: [Feature.non_nullable]);
+
+  @override
+  bool get typeToStringWithNullability => true;
+
+  ImportFindElement get _import_a {
+    return findElement.importFind('package:test/a.dart');
+  }
+
+  test_assignment_indexExpression() async {
+    newFile('/test/lib/a.dart', content: r'''
+class A {
+  void operator[]=(int a, int b) {}
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+main(A a) {
+  a[null] = null;
+}
+''');
+    var assignment = findNode.assignment('= null;');
+    assertType(assignment, 'Null*');
+
+    var indexExpression = assignment.leftHandSide as IndexExpression;
+    assertType(indexExpression, 'int*');
+
+    var element = indexExpression.staticElement;
+    _assertLegacyMember(element, _import_a.method('[]='));
+  }
+
+  test_assignment_prefixedIdentifier_instanceTarget_class_field() async {
+    newFile('/test/lib/a.dart', content: r'''
+class A {
+  int foo = 0;
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+main(A a) {
+  a.foo = 0;
+}
+''');
+    var assignment = findNode.assignment('foo = 0');
+    assertType(assignment, 'int*');
+
+    PrefixedIdentifier prefixedIdentifier = assignment.leftHandSide;
+    assertType(prefixedIdentifier, 'int*');
+
+    var identifier = prefixedIdentifier.identifier;
+    assertType(identifier, 'int*');
+
+    PropertyAccessorElement setter = identifier.staticElement;
+    _assertLegacyMember(setter, _import_a.setter('foo'));
+  }
+
+  test_assignment_prefixedIdentifier_instanceTarget_extension_setter() async {
+    newFile('/test/lib/a.dart', content: r'''
+class A {}
+extension E on A {
+  void set foo(int _) {}
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+main(A a) {
+  a.foo = 0;
+}
+''');
+    var assignment = findNode.assignment('foo = 0');
+    assertType(assignment, 'int*');
+
+    PrefixedIdentifier prefixedIdentifier = assignment.leftHandSide;
+    assertType(prefixedIdentifier, 'int*');
+
+    var identifier = prefixedIdentifier.identifier;
+    assertType(identifier, 'int*');
+
+    PropertyAccessorElement setter = identifier.staticElement;
+    _assertLegacyMember(setter, _import_a.setter('foo'));
+  }
+
+  test_assignment_prefixedIdentifier_staticTarget_class_field() async {
+    newFile('/test/lib/a.dart', content: r'''
+class A {
+  static int foo = 0;
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+main() {
+  A.foo = 0;
+}
+''');
+    var assignment = findNode.assignment('foo = 0');
+    assertType(assignment, 'int*');
+
+    PrefixedIdentifier prefixedIdentifier = assignment.leftHandSide;
+    assertType(prefixedIdentifier, 'int*');
+
+    var identifier = prefixedIdentifier.identifier;
+    assertType(identifier, 'int*');
+
+    PropertyAccessorElement setter = identifier.staticElement;
+    _assertLegacyMember(setter, _import_a.setter('foo'));
+  }
+
+  test_assignment_prefixedIdentifier_staticTarget_extension_field() async {
+    newFile('/test/lib/a.dart', content: r'''
+extension E on int {
+  static int foo = 0;
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+main() {
+  E.foo = 0;
+}
+''');
+    var assignment = findNode.assignment('foo = 0');
+    assertType(assignment, 'int*');
+
+    PrefixedIdentifier prefixedIdentifier = assignment.leftHandSide;
+    assertType(prefixedIdentifier, 'int*');
+
+    var identifier = prefixedIdentifier.identifier;
+    assertType(identifier, 'int*');
+
+    PropertyAccessorElement setter = identifier.staticElement;
+    _assertLegacyMember(setter, _import_a.setter('foo'));
+  }
+
+  test_assignment_prefixedIdentifier_topLevelVariable() async {
+    newFile('/test/lib/a.dart', content: r'''
+int foo = 0;
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart' as p;
+
+main() {
+  p.foo = 0;
+}
+''');
+    var assignment = findNode.assignment('foo = 0');
+    assertType(assignment, 'int*');
+
+    PrefixedIdentifier prefixedIdentifier = assignment.leftHandSide;
+    assertType(prefixedIdentifier, 'int*');
+
+    PropertyAccessorElement setter = prefixedIdentifier.staticElement;
+    _assertLegacyMember(setter, _import_a.topSet('foo'));
+  }
+
+  test_assignment_propertyAccess_class_field() async {
+    newFile('/test/lib/a.dart', content: r'''
+class A {
+  int foo = 0;
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+main() {
+  A().foo = 0;
+}
+''');
+    var assignment = findNode.assignment('foo = 0');
+    assertType(assignment, 'int*');
+
+    PropertyAccess propertyAccess = assignment.leftHandSide;
+    assertType(propertyAccess, 'int*');
+
+    PropertyAccessorElement setter = propertyAccess.propertyName.staticElement;
+    _assertLegacyMember(setter, _import_a.setter('foo'));
+  }
+
+  test_assignment_propertyAccess_extension_setter() async {
+    newFile('/test/lib/a.dart', content: r'''
+class A {}
+extension E on A {
+  void set foo(int a) {}
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+main() {
+  A().foo = 0;
+}
+''');
+    var assignment = findNode.assignment('foo = 0');
+    assertType(assignment, 'int*');
+
+    PropertyAccess propertyAccess = assignment.leftHandSide;
+    assertType(propertyAccess, 'int*');
+
+    PropertyAccessorElement setter = propertyAccess.propertyName.staticElement;
+    _assertLegacyMember(setter, _import_a.setter('foo'));
+  }
+
+  test_assignment_propertyAccess_extensionOverride_setter() async {
+    newFile('/test/lib/a.dart', content: r'''
+class A {}
+extension E on A {
+  void set foo(int a) {}
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+main(A a) {
+  E(a).foo = 0;
+}
+''');
+    var assignment = findNode.assignment('foo = 0');
+    assertType(assignment, 'int*');
+
+    PropertyAccess propertyAccess = assignment.leftHandSide;
+    assertType(propertyAccess, 'int*');
+
+    PropertyAccessorElement setter = propertyAccess.propertyName.staticElement;
+    _assertLegacyMember(setter, _import_a.setter('foo'));
+  }
+
+  test_assignment_propertyAccess_superTarget() async {
+    newFile('/test/lib/a.dart', content: r'''
+class A {
+  int foo = 0;
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+class B extends A {
+  void bar() {
+    super.foo = 0;
+  }
+}
+''');
+    var assignment = findNode.assignment('foo = 0');
+    assertType(assignment, 'int*');
+
+    PropertyAccess propertyAccess = assignment.leftHandSide;
+    assertType(propertyAccess, 'int*');
+
+    PropertyAccessorElement setter = propertyAccess.propertyName.staticElement;
+    _assertLegacyMember(setter, _import_a.setter('foo'));
+  }
+
+  test_assignment_simpleIdentifier_topLevelVariable() async {
+    newFile('/test/lib/a.dart', content: r'''
+int foo = 0;
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+main() {
+  foo = null;
+}
+''');
+    var assignment = findNode.assignment('foo =');
+    assertType(assignment, 'Null*');
+
+    SimpleIdentifier identifier = assignment.leftHandSide;
+    assertType(identifier, 'int*');
+
+    PropertyAccessorElement setter = identifier.staticElement;
+    _assertLegacyMember(setter, _import_a.topSet('foo'));
+  }
+
+  test_binaryExpression() async {
+    newFile('/test/lib/a.dart', content: r'''
+class A {
+  int operator+(int a) => 0;
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+main(A a) {
+  a + null;
+}
+''');
+    var binaryExpression = findNode.binary('a +');
+    assertInvokeType(binaryExpression, 'int* Function(int*)*');
+    assertType(binaryExpression, 'int*');
+
+    MethodElement element = binaryExpression.staticElement;
+    _assertLegacyMember(element, _import_a.method('+'));
+  }
+
+  test_functionExpressionInvocation() async {
+    newFile('/test/lib/a.dart', content: r'''
+int Function(int, int?)? foo;
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+main() {
+  foo(null, null);
+}
+''');
+    var invocation = findNode.functionExpressionInvocation('foo');
+    assertInvokeType(invocation, 'int* Function(int*, int*)*');
+    assertType(invocation, 'int*');
+
+    var identifier = findNode.simple('foo');
+    assertType(identifier, 'int* Function(int*, int*)*');
+
+    PropertyAccessorElement element = identifier.staticElement;
+    _assertLegacyMember(element, _import_a.topGet('foo'));
+  }
+
+  test_functionExpressionInvocation_call() async {
+    newFile('/test/lib/a.dart', content: r'''
+class A {
+  int call(int a, int? b) => 0;
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+main(A a) {
+  a(null, null);
+}
+''');
+    var invocation = findNode.functionExpressionInvocation('a(null');
+    assertInvokeType(invocation, 'int* Function(int*, int*)*');
+    assertType(invocation, 'int*');
+
+    var identifier = invocation.function;
+    assertType(identifier, 'A*');
+
+    MethodElement element = invocation.staticElement;
+    _assertLegacyMember(element, _import_a.method('call'));
+  }
+
+  test_functionExpressionInvocation_extension_staticTarget() async {
+    newFile('/test/lib/a.dart', content: r'''
+extension E on int {
+  static int Function(int) get foo => (_) => 0;
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+main() {
+  E.foo(null);
+}
+''');
+    var invocation = findNode.functionExpressionInvocation('foo');
+    assertInvokeType(invocation, 'int* Function(int*)*');
+    assertType(invocation, 'int*');
+
+    var identifier = findNode.simple('foo');
+    assertType(identifier, 'int* Function(int*)*');
+
+    PropertyAccessorElement element = identifier.staticElement;
+    _assertLegacyMember(element, _import_a.getter('foo'));
+  }
+
+  test_instanceCreation() async {
+    newFile('/test/lib/a.dart', content: r'''
+class A {
+  A(int a, int? b);
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+main() {
+  A(null, null);
+}
+''');
+    var instanceCreation = findNode.instanceCreation('A(null');
+    assertType(instanceCreation, 'A*');
+
+    _assertLegacyMember(
+      instanceCreation.staticElement,
+      _import_a.unnamedConstructor('A'),
+    );
+  }
+
+  test_instanceCreation_generic() async {
+    newFile('/test/lib/a.dart', content: r'''
+class A<T> {
+  A(T a, T? b);
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+main() {
+  A<int>(null, null);
+}
+''');
+    var instanceCreation = findNode.instanceCreation('A<int>(null');
+    assertType(instanceCreation, 'A<int*>*');
+
+    _assertLegacyMember(
+      instanceCreation.staticElement,
+      _import_a.unnamedConstructor('A'),
+      expectedSubstitution: {'T': 'int'},
+    );
+  }
+
+  test_methodInvocation_extension_functionTarget() async {
+    newFile('/test/lib/a.dart', content: r'''
+extension E on void Function() {
+  int foo(int a) => 0;
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+main(void Function() a) {
+  a.foo(null);
+}
+''');
+    var invocation = findNode.methodInvocation('foo');
+    assertInvokeType(invocation, 'int* Function(int*)*');
+    assertType(invocation, 'int*');
+
+    var identifier = findNode.simple('foo');
+    assertType(identifier, 'int* Function(int*)*');
+
+    MethodElement element = identifier.staticElement;
+    _assertLegacyMember(element, _import_a.method('foo'));
+  }
+
+  test_methodInvocation_extension_interfaceTarget() async {
+    newFile('/test/lib/a.dart', content: r'''
+extension E on int {
+  int foo(int a) => 0;
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+main() {
+  0.foo(null);
+}
+''');
+    var invocation = findNode.methodInvocation('foo');
+    assertInvokeType(invocation, 'int* Function(int*)*');
+    assertType(invocation, 'int*');
+
+    var identifier = findNode.simple('foo');
+    assertType(identifier, 'int* Function(int*)*');
+
+    MethodElement element = identifier.staticElement;
+    _assertLegacyMember(element, _import_a.method('foo'));
+  }
+
+  test_methodInvocation_extension_nullTarget() async {
+    newFile('/test/lib/a.dart', content: r'''
+class A {}
+extension E on A {
+  int foo(int a) => 0;
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+class B extends A {
+  void bar() {
+    foo(null);
+  }
+}
+''');
+    var invocation = findNode.methodInvocation('foo');
+    assertInvokeType(invocation, 'int* Function(int*)*');
+    assertType(invocation, 'int*');
+
+    var identifier = findNode.simple('foo');
+    assertType(identifier, 'int* Function(int*)*');
+
+    MethodElement element = identifier.staticElement;
+    _assertLegacyMember(element, _import_a.method('foo'));
+  }
+
+  test_methodInvocation_extension_staticTarget() async {
+    newFile('/test/lib/a.dart', content: r'''
+extension E on int {
+  static int foo(int a) => 0;
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+main() {
+  E.foo(null);
+}
+''');
+    var invocation = findNode.methodInvocation('foo');
+    assertInvokeType(invocation, 'int* Function(int*)*');
+    assertType(invocation, 'int*');
+
+    var identifier = findNode.simple('foo');
+    assertType(identifier, 'int* Function(int*)*');
+
+    MethodElement element = identifier.staticElement;
+    _assertLegacyMember(element, _import_a.method('foo'));
+  }
+
+  test_methodInvocation_extensionOverride() async {
+    newFile('/test/lib/a.dart', content: r'''
+extension E on int {
+  int foo(int a) => 0;
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+main() {
+  E(0).foo(null);
+}
+''');
+    var invocation = findNode.methodInvocation('foo');
+    assertInvokeType(invocation, 'int* Function(int*)*');
+    assertType(invocation, 'int*');
+
+    var identifier = findNode.simple('foo');
+    assertType(identifier, 'int* Function(int*)*');
+
+    MethodElement element = identifier.staticElement;
+    _assertLegacyMember(element, _import_a.method('foo'));
+  }
+
+  test_methodInvocation_function() async {
+    newFile('/test/lib/a.dart', content: r'''
+int foo(int a, int? b) => 0;
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+main() {
+  foo(null, null);
+}
+''');
+    var invocation = findNode.methodInvocation('foo');
+    assertInvokeType(invocation, 'int* Function(int*, int*)*');
+    assertType(invocation, 'int*');
+
+    var identifier = findNode.simple('foo');
+    assertType(identifier, 'int* Function(int*, int*)*');
+
+    FunctionElement element = identifier.staticElement;
+    _assertLegacyMember(element, _import_a.topFunction('foo'));
+  }
+
+  test_methodInvocation_function_prefixed() async {
+    newFile('/test/lib/a.dart', content: r'''
+int foo(int a, int? b) => 0;
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart' as p;
+
+main() {
+  p.foo(null, null);
+}
+''');
+    var invocation = findNode.methodInvocation('foo');
+    assertInvokeType(invocation, 'int* Function(int*, int*)*');
+    assertType(invocation, 'int*');
+
+    var identifier = findNode.simple('foo');
+    assertType(identifier, 'int* Function(int*, int*)*');
+
+    FunctionElement element = identifier.staticElement;
+    _assertLegacyMember(element, _import_a.topFunction('foo'));
+  }
+
+  test_methodInvocation_method_cascade() async {
+    newFile('/test/lib/a.dart', content: r'''
+class A {
+  int foo(int a, int? b) => 0;
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+main(A a) {
+  a..foo(null, null);
+}
+''');
+    var invocation = findNode.methodInvocation('foo(');
+    assertInvokeType(invocation, 'int* Function(int*, int*)*');
+    assertType(invocation, 'int*');
+
+    var identifier = findNode.simple('foo');
+    assertType(identifier, 'int* Function(int*, int*)*');
+
+    MethodElement element = identifier.staticElement;
+    assertElementTypeString(element.type, 'int* Function(int*, int*)*');
+  }
+
+  test_methodInvocation_method_interfaceTarget() async {
+    newFile('/test/lib/a.dart', content: r'''
+class A {
+  int foo(int a, int? b) => 0;
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+main(A a) {
+  a.foo(null, null);
+}
+''');
+    var invocation = findNode.methodInvocation('a.foo');
+    assertInvokeType(invocation, 'int* Function(int*, int*)*');
+    assertType(invocation, 'int*');
+
+    var identifier = findNode.simple('foo');
+    assertType(identifier, 'int* Function(int*, int*)*');
+
+    MethodElement element = identifier.staticElement;
+    assertElementTypeString(element.type, 'int* Function(int*, int*)*');
+  }
+
+  test_methodInvocation_method_nullTarget() async {
+    newFile('/test/lib/a.dart', content: r'''
+class A {
+  int foo(int a, int? b) => 0;
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+class B extends A {
+  m() {
+    foo(null, null);
+  }
+}
+''');
+    var invocation = findNode.methodInvocation('foo');
+    assertInvokeType(invocation, 'int* Function(int*, int*)*');
+    assertType(invocation, 'int*');
+
+    var identifier = findNode.simple('foo');
+    assertType(identifier, 'int* Function(int*, int*)*');
+
+    MethodElement element = identifier.staticElement;
+    assertElementTypeString(element.type, 'int* Function(int*, int*)*');
+  }
+
+  test_methodInvocation_method_staticTarget() async {
+    newFile('/test/lib/a.dart', content: r'''
+class A {
+  static int foo(int a, int? b) => 0;
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+main() {
+  A.foo(null, null);
+}
+''');
+    var invocation = findNode.methodInvocation('A.foo');
+    assertInvokeType(invocation, 'int* Function(int*, int*)*');
+    assertType(invocation, 'int*');
+
+    var identifier = findNode.simple('foo');
+    assertType(identifier, 'int* Function(int*, int*)*');
+
+    MethodElement element = identifier.staticElement;
+    assertElementTypeString(element.type, 'int* Function(int*, int*)*');
+  }
+
+  test_methodInvocation_method_superTarget() async {
+    newFile('/test/lib/a.dart', content: r'''
+class A {
+  int foo(int a, int? b) => 0;
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+class B extends A {
+  m() {
+    super.foo(null, null);
+  }
+}
+''');
+    var invocation = findNode.methodInvocation('foo');
+    assertInvokeType(invocation, 'int* Function(int*, int*)*');
+    assertType(invocation, 'int*');
+
+    var identifier = findNode.simple('foo');
+    assertType(identifier, 'int* Function(int*, int*)*');
+
+    MethodElement element = identifier.staticElement;
+    assertElementTypeString(element.type, 'int* Function(int*, int*)*');
+  }
 
   test_nnbd_optOut_invalidSyntax() async {
     await assertErrorsInCode('''
@@ -41,9 +775,7 @@
 ''');
   }
 
-  @failingTest
   test_nnbd_optOut_transformsOptedInSignatures() async {
-    // Failing because we don't transform opted out signatures.
     await assertNoErrorsInCode('''
 // @dart = 2.2
 f(String x) {
@@ -51,4 +783,479 @@
 }
 ''');
   }
+
+  test_postfixExpression() async {
+    newFile('/test/lib/a.dart', content: r'''
+class A {
+  A operator+(int a) => this;
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+main(A a) {
+  a++;
+}
+''');
+    var prefixExpression = findNode.postfix('a++');
+    assertType(prefixExpression, 'A*');
+
+    MethodElement element = prefixExpression.staticElement;
+    _assertLegacyMember(element, _import_a.method('+'));
+  }
+
+  test_prefixExpression() async {
+    newFile('/test/lib/a.dart', content: r'''
+class A {
+  int operator-() => 0;
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+main(A a) {
+  -a;
+}
+''');
+    var prefixExpression = findNode.prefix('-a');
+    assertType(prefixExpression, 'int*');
+
+    MethodElement element = prefixExpression.staticElement;
+    _assertLegacyMember(element, _import_a.method('unary-'));
+  }
+
+  test_read_indexExpression_class() async {
+    newFile('/test/lib/a.dart', content: r'''
+class A {
+  int operator[](int a) => 0;
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+main(A a) {
+  a[null];
+}
+''');
+    var indexExpression = findNode.index('a[');
+    assertType(indexExpression, 'int*');
+
+    MethodElement element = indexExpression.staticElement;
+    _assertLegacyMember(element, _import_a.method('[]'));
+  }
+
+  test_read_prefixedIdentifier_instanceTarget_class_field() async {
+    newFile('/test/lib/a.dart', content: r'''
+class A {
+  int foo;
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+main(A a) {
+  a.foo;
+}
+''');
+    var prefixedIdentifier = findNode.prefixed('a.foo');
+    assertType(prefixedIdentifier, 'int*');
+
+    var identifier = prefixedIdentifier.identifier;
+    assertType(identifier, 'int*');
+
+    PropertyAccessorElement element = identifier.staticElement;
+    _assertLegacyMember(element, _import_a.getter('foo'));
+  }
+
+  test_read_prefixedIdentifier_instanceTarget_extension_getter() async {
+    newFile('/test/lib/a.dart', content: r'''
+class A {}
+extension E on A {
+  int get foo => 0;
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+main(A a) {
+  a.foo;
+}
+''');
+    var prefixedIdentifier = findNode.prefixed('a.foo');
+    assertType(prefixedIdentifier, 'int*');
+
+    var identifier = prefixedIdentifier.identifier;
+    assertType(identifier, 'int*');
+
+    PropertyAccessorElement element = identifier.staticElement;
+    _assertLegacyMember(element, _import_a.getter('foo'));
+  }
+
+  test_read_prefixedIdentifier_staticTarget_class_field() async {
+    newFile('/test/lib/a.dart', content: r'''
+class A {
+  static int foo;
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+main() {
+  A.foo;
+}
+''');
+    var prefixedIdentifier = findNode.prefixed('A.foo');
+    assertType(prefixedIdentifier, 'int*');
+
+    var identifier = prefixedIdentifier.identifier;
+    assertType(identifier, 'int*');
+
+    PropertyAccessorElement element = identifier.staticElement;
+    _assertLegacyMember(element, _import_a.getter('foo'));
+  }
+
+  test_read_prefixedIdentifier_staticTarget_class_method() async {
+    newFile('/test/lib/a.dart', content: r'''
+class A {
+  static int foo(int a) => 0;
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+main() {
+  A.foo;
+}
+''');
+    var prefixedIdentifier = findNode.prefixed('A.foo');
+    assertType(prefixedIdentifier, 'int* Function(int*)*');
+
+    var identifier = prefixedIdentifier.identifier;
+    assertType(identifier, 'int* Function(int*)*');
+
+    MethodElement element = identifier.staticElement;
+    _assertLegacyMember(element, _import_a.method('foo'));
+  }
+
+  test_read_prefixedIdentifier_staticTarget_extension_field() async {
+    newFile('/test/lib/a.dart', content: r'''
+extension E {
+  static int foo;
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+main() {
+  E.foo;
+}
+''');
+    var prefixedIdentifier = findNode.prefixed('E.foo');
+    assertType(prefixedIdentifier, 'int*');
+
+    var identifier = prefixedIdentifier.identifier;
+    assertType(identifier, 'int*');
+
+    PropertyAccessorElement element = identifier.staticElement;
+    _assertLegacyMember(element, _import_a.getter('foo'));
+  }
+
+  test_read_prefixedIdentifier_staticTarget_extension_method() async {
+    newFile('/test/lib/a.dart', content: r'''
+extension E {
+  static int foo(int a) => 0;
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+main() {
+  E.foo;
+}
+''');
+    var prefixedIdentifier = findNode.prefixed('E.foo');
+    assertType(prefixedIdentifier, 'int* Function(int*)*');
+
+    var identifier = prefixedIdentifier.identifier;
+    assertType(identifier, 'int* Function(int*)*');
+
+    MethodElement element = identifier.staticElement;
+    _assertLegacyMember(element, _import_a.method('foo'));
+  }
+
+  test_read_prefixedIdentifier_topLevelVariable() async {
+    newFile('/test/lib/a.dart', content: r'''
+int foo = 0;
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart' as p;
+
+main() {
+  p.foo;
+}
+''');
+    var prefixedIdentifier = findNode.prefixed('p.foo');
+    assertType(prefixedIdentifier, 'int*');
+
+    var identifier = prefixedIdentifier.identifier;
+    assertType(identifier, 'int*');
+
+    PropertyAccessorElement element = identifier.staticElement;
+    _assertLegacyMember(element, _import_a.topGet('foo'));
+  }
+
+  test_read_propertyAccessor_class_field() async {
+    newFile('/test/lib/a.dart', content: r'''
+class A {
+  int foo = 0;
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+main() {
+  A().foo;
+}
+''');
+    var propertyAccess = findNode.propertyAccess('foo');
+    assertType(propertyAccess, 'int*');
+
+    var identifier = propertyAccess.propertyName;
+    assertType(identifier, 'int*');
+
+    PropertyAccessorElement element = identifier.staticElement;
+    _assertLegacyMember(element, _import_a.getter('foo'));
+  }
+
+  test_read_propertyAccessor_class_method() async {
+    newFile('/test/lib/a.dart', content: r'''
+class A {
+  int foo() => 0;
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+main() {
+  A().foo;
+}
+''');
+    var propertyAccess = findNode.propertyAccess('foo');
+    assertType(propertyAccess, 'int* Function()*');
+
+    var identifier = propertyAccess.propertyName;
+    assertType(identifier, 'int* Function()*');
+
+    MethodElement element = identifier.staticElement;
+    _assertLegacyMember(element, _import_a.method('foo'));
+  }
+
+  test_read_propertyAccessor_extensionOverride_getter() async {
+    newFile('/test/lib/a.dart', content: r'''
+class A {}
+extension E on A {
+  int get foo => 0;
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+main(A a) {
+  E(a).foo;
+}
+''');
+    var propertyAccess = findNode.propertyAccess('foo');
+    assertType(propertyAccess, 'int*');
+
+    var identifier = propertyAccess.propertyName;
+    assertType(identifier, 'int*');
+
+    PropertyAccessorElement element = identifier.staticElement;
+    _assertLegacyMember(element, _import_a.getter('foo'));
+  }
+
+  test_read_propertyAccessor_superTarget() async {
+    newFile('/test/lib/a.dart', content: r'''
+class A {
+  int foo = 0;
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+class B extends A {
+  void bar() {
+    super.foo;
+  }
+}
+''');
+    var propertyAccess = findNode.propertyAccess('foo');
+    assertType(propertyAccess, 'int*');
+
+    var identifier = propertyAccess.propertyName;
+    assertType(identifier, 'int*');
+
+    PropertyAccessorElement element = identifier.staticElement;
+    _assertLegacyMember(element, _import_a.getter('foo'));
+  }
+
+  test_read_simpleIdentifier_class_field() async {
+    newFile('/test/lib/a.dart', content: r'''
+class A {
+  int foo = 0;
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+class B extends A {
+  void bar() {
+    foo;
+  }
+}
+''');
+    var identifier = findNode.simple('foo');
+    assertType(identifier, 'int*');
+
+    PropertyAccessorElement element = identifier.staticElement;
+    _assertLegacyMember(element, _import_a.getter('foo'));
+  }
+
+  test_read_simpleIdentifier_class_method() async {
+    newFile('/test/lib/a.dart', content: r'''
+class A {
+  int foo(int a) => 0;
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+class B extends A {
+  void bar() {
+    foo;
+  }
+}
+''');
+    var identifier = findNode.simple('foo');
+    assertType(identifier, 'int* Function(int*)*');
+
+    MethodElement element = identifier.staticElement;
+    _assertLegacyMember(element, _import_a.method('foo'));
+  }
+
+  test_read_simpleIdentifier_extension_getter() async {
+    newFile('/test/lib/a.dart', content: r'''
+class A {}
+extension E on A {
+  int get foo => 0;
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+class B extends A {
+  void bar() {
+    foo;
+  }
+}
+''');
+    var identifier = findNode.simple('foo');
+    assertType(identifier, 'int*');
+
+    PropertyAccessorElement element = identifier.staticElement;
+    _assertLegacyMember(element, _import_a.getter('foo'));
+  }
+
+  test_read_simpleIdentifier_extension_method() async {
+    newFile('/test/lib/a.dart', content: r'''
+class A {}
+extension E on A {
+  int foo(int a) => 0;
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+class B extends A {
+  void bar() {
+    foo;
+  }
+}
+''');
+    var identifier = findNode.simple('foo');
+    assertType(identifier, 'int* Function(int*)*');
+
+    MethodElement element = identifier.staticElement;
+    _assertLegacyMember(element, _import_a.method('foo'));
+  }
+
+  test_read_simpleIdentifier_topLevelVariable() async {
+    newFile('/test/lib/a.dart', content: r'''
+int foo = 0;
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+main() {
+  foo;
+}
+''');
+    var identifier = findNode.simple('foo');
+    assertType(identifier, 'int*');
+
+    PropertyAccessorElement element = identifier.staticElement;
+    _assertLegacyMember(element, _import_a.topGet('foo'));
+  }
+
+  test_superConstructorInvocation() async {
+    newFile('/test/lib/a.dart', content: r'''
+class A {
+  A(int a, int? b);
+}
+''');
+    await assertNoErrorsInCode(r'''
+// @dart = 2.5
+import 'a.dart';
+
+class B extends A {
+  B() : super(null, null);
+}
+''');
+    var instanceCreation = findNode.superConstructorInvocation('super(');
+
+    _assertLegacyMember(
+      instanceCreation.staticElement,
+      _import_a.unnamedConstructor('A'),
+    );
+  }
+
+  void _assertLegacyMember(
+    Element actualElement,
+    Element declaration, {
+    Map<String, String> expectedSubstitution = const {},
+  }) {
+    var actualMember = actualElement as Member;
+    expect(actualMember.declaration, same(declaration));
+    expect(actualMember.isLegacy, isTrue);
+    assertSubstitution(actualMember.substitution, expectedSubstitution);
+  }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart
index d003c07..d7b3a4f 100644
--- a/pkg/analyzer/test/src/diagnostics/test_all.dart
+++ b/pkg/analyzer/test/src/diagnostics/test_all.dart
@@ -30,6 +30,8 @@
 import 'cast_to_non_type_test.dart' as cast_to_non_type;
 import 'concrete_class_with_abstract_member_test.dart'
     as concrete_class_with_abstract_member;
+import 'conflicting_generic_interfaces_test.dart'
+    as conflicting_generic_interfaces;
 import 'conflicting_static_and_instance_test.dart'
     as conflicting_static_and_instance;
 import 'const_constructor_param_type_mismatch_test.dart'
@@ -193,7 +195,6 @@
 import 'missing_js_lib_annotation_test.dart' as missing_js_lib_annotation;
 import 'missing_required_param_test.dart' as missing_required_param;
 import 'missing_return_test.dart' as missing_return;
-import 'mixed_return_types_test.dart' as mixed_return_types;
 import 'mixin_of_disallowed_class_test.dart' as mixin_of_disallowed_class;
 import 'mixin_of_non_class_test.dart' as mixin_of_non_class;
 import 'mixin_on_sealed_class_test.dart' as mixin_on_sealed_class;
@@ -388,6 +389,7 @@
     case_block_not_terminated.main();
     cast_to_non_type.main();
     concrete_class_with_abstract_member.main();
+    conflicting_generic_interfaces.main();
     conflicting_static_and_instance.main();
     const_constructor_param_type_mismatch.main();
     const_constructor_with_mixin_with_field.main();
@@ -497,7 +499,6 @@
     missing_js_lib_annotation.main();
     missing_required_param.main();
     missing_return.main();
-    mixed_return_types.main();
     mixin_of_disallowed_class.main();
     mixin_of_non_class.main();
     mixin_on_sealed_class.main();
diff --git a/pkg/analyzer/test/src/diagnostics/undefined_identifier_test.dart b/pkg/analyzer/test/src/diagnostics/undefined_identifier_test.dart
index 84a31f0..502c6a3 100644
--- a/pkg/analyzer/test/src/diagnostics/undefined_identifier_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/undefined_identifier_test.dart
@@ -157,11 +157,4 @@
   AnalysisOptionsImpl get analysisOptions => AnalysisOptionsImpl()
     ..contextFeatures = new FeatureSet.forTesting(
         sdkVersion: '2.6.0', additionalFeatures: [Feature.non_nullable]);
-
-  @failingTest
-  @override
-  test_forElement_inList_insideElement() async {
-    // todo: fails w/ StaticWarningCode.LIST_ELEMENT_TYPE_NOT_ASSIGNABLE
-    await super.test_forElement_inList_insideElement();
-  }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/unused_element_test.dart b/pkg/analyzer/test/src/diagnostics/unused_element_test.dart
index ef38d33..66f4f04 100644
--- a/pkg/analyzer/test/src/diagnostics/unused_element_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/unused_element_test.dart
@@ -164,6 +164,15 @@
     ]);
   }
 
+  test_fieldImplicitGetter_isUsed() async {
+    await assertNoErrorsInCode(r'''
+class A {
+  int _g;
+  int get g => this._g;
+}
+''');
+  }
+
   test_functionLocal_isUsed_closure() async {
     await assertNoErrorsInCode(r'''
 main() {
@@ -303,6 +312,27 @@
     ]);
   }
 
+  test_getter_isUsed_invocation_deepSubclass() async {
+    await assertNoErrorsInCode(r'''
+abstract class A {
+  String get _debugName;
+
+  String toString() {
+    return _debugName;
+  }
+}
+
+class B extends A {
+  @override
+  String get _debugName => "B";
+}
+
+class C extends B {
+  String get _debugName => "C";
+}
+''');
+  }
+
   test_getter_isUsed_invocation_implicitThis() async {
     await assertNoErrorsInCode(r'''
 class A {
@@ -314,6 +344,42 @@
 ''');
   }
 
+  test_getter_isUsed_invocation_parameterized() async {
+    await assertNoErrorsInCode(r'''
+class A<T> {
+  List<int> _list = List(1);
+  int get _item => _list.first;
+  set _item(int item) => _list[0] = item;
+}
+class B<T> {
+  A<T> a;
+}
+void main() {
+  B<int> b = B();
+  b.a._item = 3;
+  print(b.a._item == 7);
+}
+''');
+  }
+
+  test_getter_isUsed_invocation_parameterized_subclass() async {
+    await assertNoErrorsInCode(r'''
+abstract class A<T> {
+  T get _defaultThing;
+  T _thing;
+
+  void main() {
+    _thing ??= _defaultThing;
+    print(_thing);
+  }
+}
+class B extends A<int> {
+  @override
+  int get _defaultThing => 7;
+}
+''');
+  }
+
   test_getter_isUsed_invocation_PrefixedIdentifier() async {
     await assertNoErrorsInCode(r'''
 class A {
@@ -336,6 +402,43 @@
 ''');
   }
 
+  test_getter_isUsed_invocation_subclass_plusPlus() async {
+    await assertNoErrorsInCode(r'''
+class A {
+  int __a = 0;
+  int get _a => __a;
+  void set _a(int val) {
+    __a = val;
+  }
+  int b() => _a++;
+}
+class B extends A {
+  @override
+  int get _a => 3;
+}
+''');
+  }
+
+  test_getter_notUsed_invocation_subclass() async {
+    await assertErrorsInCode(r'''
+class A {
+  int __a = 0;
+  int get _a => __a;
+  void set _a(int val) {
+    __a = val;
+  }
+  int b() => _a = 7;
+}
+class B extends A {
+  @override
+  int get _a => 3;
+}
+''', [
+      error(HintCode.UNUSED_ELEMENT, 35, 2),
+      error(HintCode.UNUSED_ELEMENT, 155, 2),
+    ]);
+  }
+
   test_getter_notUsed_noReference() async {
     await assertErrorsInCode(r'''
 class A {
@@ -358,6 +461,20 @@
     ]);
   }
 
+  test_method_isNotUsed_hasSameNameAsUsed() async {
+    await assertErrorsInCode(r'''
+class A {
+  void _m1() {}
+}
+class B {
+  void public() => _m1();
+  void _m1() {}
+}
+''', [
+      error(HintCode.UNUSED_ELEMENT, 17, 3),
+    ]);
+  }
+
   test_method_isUsed_hasReference_implicitThis() async {
     await assertNoErrorsInCode(r'''
 class A {
@@ -407,6 +524,32 @@
 ''');
   }
 
+  test_method_isUsed_invocation_fromMixinApplication() async {
+    await assertNoErrorsInCode(r'''
+mixin A {
+  _m() {}
+}
+class C with A {
+  useMethod() {
+    _m();
+  }
+}
+''');
+  }
+
+  test_method_isUsed_invocation_fromMixinWithConstraint() async {
+    await assertNoErrorsInCode(r'''
+class A {
+  _m() {}
+}
+mixin M on A {
+  useMethod() {
+    _m();
+  }
+}
+''');
+  }
+
   test_method_isUsed_invocation_implicitThis() async {
     await assertNoErrorsInCode(r'''
 class A {
diff --git a/pkg/analyzer/test/src/diagnostics/unused_field_test.dart b/pkg/analyzer/test/src/diagnostics/unused_field_test.dart
index fa17061..2bb674f 100644
--- a/pkg/analyzer/test/src/diagnostics/unused_field_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/unused_field_test.dart
@@ -18,7 +18,7 @@
   @override
   bool get enableUnusedElement => true;
 
-  test_unusedField_isUsed_argument() async {
+  test_isUsed_argument() async {
     await assertNoErrorsInCode(r'''
 class A {
   int _f = 0;
@@ -30,7 +30,23 @@
 ''');
   }
 
-  test_unusedField_isUsed_reference_implicitThis() async {
+  test_isUsed_parameterized_subclass() async {
+    await assertNoErrorsInCode(r'''
+class A<T extends num> {
+  T _f;
+  A._(this._f);
+}
+class B extends A<int> {
+  B._(int f) : super._(f);
+}
+void main() {
+  B b = B._(7);
+  print(b._f == 7);
+}
+''');
+  }
+
+  test_isUsed_reference_implicitThis() async {
     await assertNoErrorsInCode(r'''
 class A {
   int _f;
@@ -42,7 +58,7 @@
 ''');
   }
 
-  test_unusedField_isUsed_reference_implicitThis_expressionFunctionBody() async {
+  test_isUsed_reference_implicitThis_expressionFunctionBody() async {
     await assertNoErrorsInCode(r'''
 class A {
   int _f;
@@ -51,7 +67,7 @@
 ''');
   }
 
-  test_unusedField_isUsed_reference_implicitThis_subclass() async {
+  test_isUsed_reference_implicitThis_subclass() async {
     await assertNoErrorsInCode(r'''
 class A {
   int _f;
@@ -66,7 +82,7 @@
 ''');
   }
 
-  test_unusedField_isUsed_reference_qualified_propagatedElement() async {
+  test_isUsed_reference_qualified_propagatedElement() async {
     await assertNoErrorsInCode(r'''
 class A {
   int _f;
@@ -79,7 +95,7 @@
 ''');
   }
 
-  test_unusedField_isUsed_reference_qualified_staticElement() async {
+  test_isUsed_reference_qualified_staticElement() async {
     await assertNoErrorsInCode(r'''
 class A {
   int _f;
@@ -92,7 +108,7 @@
 ''');
   }
 
-  test_unusedField_isUsed_reference_qualified_unresolved() async {
+  test_isUsed_reference_qualified_unresolved() async {
     await assertNoErrorsInCode(r'''
 class A {
   int _f;
@@ -104,7 +120,7 @@
 ''');
   }
 
-  test_unusedField_notUsed_compoundAssign() async {
+  test_notUsed_compoundAssign() async {
     await assertErrorsInCode(r'''
 class A {
   int _f;
@@ -117,7 +133,7 @@
     ]);
   }
 
-  test_unusedField_notUsed_constructorFieldInitializers() async {
+  test_notUsed_constructorFieldInitializers() async {
     await assertErrorsInCode(r'''
 class A {
   int _f;
@@ -128,7 +144,7 @@
     ]);
   }
 
-  test_unusedField_notUsed_fieldFormalParameter() async {
+  test_notUsed_fieldFormalParameter() async {
     await assertErrorsInCode(r'''
 class A {
   int _f;
@@ -139,7 +155,7 @@
     ]);
   }
 
-  test_unusedField_notUsed_noReference() async {
+  test_notUsed_noReference() async {
     await assertErrorsInCode(r'''
 class A {
   int _f;
@@ -149,7 +165,7 @@
     ]);
   }
 
-  test_unusedField_notUsed_nullAssign() async {
+  test_notUsed_nullAssign() async {
     await assertNoErrorsInCode(r'''
 class A {
   var _f;
@@ -161,7 +177,7 @@
 ''');
   }
 
-  test_unusedField_notUsed_postfixExpr() async {
+  test_notUsed_postfixExpr() async {
     await assertErrorsInCode(r'''
 class A {
   int _f = 0;
@@ -174,7 +190,7 @@
     ]);
   }
 
-  test_unusedField_notUsed_prefixExpr() async {
+  test_notUsed_prefixExpr() async {
     await assertErrorsInCode(r'''
 class A {
   int _f = 0;
@@ -187,7 +203,7 @@
     ]);
   }
 
-  test_unusedField_notUsed_simpleAssignment() async {
+  test_notUsed_simpleAssignment() async {
     await assertErrorsInCode(r'''
 class A {
   int _f;
diff --git a/pkg/analyzer/test/src/diagnostics/use_of_void_result_test.dart b/pkg/analyzer/test/src/diagnostics/use_of_void_result_test.dart
index 99fd027..7efa6ae 100644
--- a/pkg/analyzer/test/src/diagnostics/use_of_void_result_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/use_of_void_result_test.dart
@@ -529,7 +529,7 @@
   return x;
 }
 ''', [
-      error(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE, 36, 1),
+      error(StaticTypeWarningCode.RETURN_OF_INVALID_TYPE_FROM_FUNCTION, 36, 1),
     ]);
   }
 
diff --git a/pkg/analyzer/test/src/lint/linter/linter_context_impl_test.dart b/pkg/analyzer/test/src/lint/linter/linter_context_impl_test.dart
index 8e48671..754b7ad 100644
--- a/pkg/analyzer/test/src/lint/linter/linter_context_impl_test.dart
+++ b/pkg/analyzer/test/src/lint/linter/linter_context_impl_test.dart
@@ -16,6 +16,7 @@
   defineReflectiveSuite(() {
     defineReflectiveTests(CanBeConstConstructorTest);
     defineReflectiveTests(CanBeConstTest);
+    defineReflectiveTests(EvaluateExpressionTest);
   });
 }
 
@@ -41,7 +42,7 @@
       result.session.declaredVariables,
       result.typeProvider,
       result.typeSystem,
-      InheritanceManager3(result.typeSystem),
+      InheritanceManager3(),
       analysisOptions,
       // todo (pq): test package or consider passing in null
       workspacePackage,
@@ -243,3 +244,38 @@
     assertCanBeConst("A();", true);
   }
 }
+
+@reflectiveTest
+class EvaluateExpressionTest extends AbstractLinterContextTest {
+  test_hasError_methodInvocation() async {
+    await resolve('''
+var x = 42.abs();
+''');
+    var result = _evaluateX();
+    expect(result.errors, isNotNull);
+    expect(result.value, isNull);
+  }
+
+  test_hasValue_binaryExpression() async {
+    await resolve('''
+var x = 1 + 2;
+''');
+    var result = _evaluateX();
+    expect(result.errors, isEmpty);
+    expect(result.value.toIntValue(), 3);
+  }
+
+  test_hasValue_intLiteral() async {
+    await resolve('''
+var x = 42;
+''');
+    var result = _evaluateX();
+    expect(result.errors, isEmpty);
+    expect(result.value.toIntValue(), 42);
+  }
+
+  LinterConstantEvaluationResult _evaluateX() {
+    var node = findNode.topVariableDeclarationByName('x').initializer;
+    return context.evaluateConstant(node);
+  }
+}
diff --git a/pkg/analyzer/test/src/summary/element_text.dart b/pkg/analyzer/test/src/summary/element_text.dart
index 8ecf7ea..0555d63 100644
--- a/pkg/analyzer/test/src/summary/element_text.dart
+++ b/pkg/analyzer/test/src/summary/element_text.dart
@@ -1078,6 +1078,12 @@
 
   void writeTypeParameterElement(TypeParameterElement e) {
     writeMetadata(e, '', '\n');
+    // TODO (kallentu) : Clean up TypeParameterElementImpl casting once
+    // variance is added to the interface.
+    if (!(e as TypeParameterElementImpl).isLegacyCovariant) {
+      buffer.write(
+          (e as TypeParameterElementImpl).variance.toKeywordString() + ' ');
+    }
     writeName(e);
     writeCodeRange(e);
     if (e.bound != null && !e.bound.isObject) {
diff --git a/pkg/analyzer/test/src/summary/in_summary_source_test.dart b/pkg/analyzer/test/src/summary/in_summary_source_test.dart
index c6d5879..1ce0664 100644
--- a/pkg/analyzer/test/src/summary/in_summary_source_test.dart
+++ b/pkg/analyzer/test/src/summary/in_summary_source_test.dart
@@ -4,8 +4,6 @@
 
 import 'package:analyzer/file_system/physical_file_system.dart';
 import 'package:analyzer/src/generated/source_io.dart';
-import 'package:analyzer/src/summary/format.dart';
-import 'package:analyzer/src/summary/idl.dart';
 import 'package:analyzer/src/summary/package_bundle_reader.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -44,19 +42,12 @@
 }
 
 class MockSummaryDataStore implements SummaryDataStore {
-  final Map<String, LinkedLibrary> linkedMap;
-  final Map<String, UnlinkedUnit> unlinkedMap;
   final Map<String, String> uriToSummaryPath;
 
-  MockSummaryDataStore(this.linkedMap, this.unlinkedMap, this.uriToSummaryPath);
+  MockSummaryDataStore(this.uriToSummaryPath);
 
   factory MockSummaryDataStore.fake(Map<String, String> uriToSummary) {
-    // Create fake unlinked map.
-    // We don't populate the values as it is not needed for the test.
-    var unlinkedMap = new Map<String, UnlinkedUnit>.fromIterable(
-        uriToSummary.keys,
-        value: (uri) => new UnlinkedUnitBuilder());
-    return new MockSummaryDataStore(null, unlinkedMap, uriToSummary);
+    return new MockSummaryDataStore(uriToSummary);
   }
 
   noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
diff --git a/pkg/analyzer/test/src/summary/resolved_ast_printer.dart b/pkg/analyzer/test/src/summary/resolved_ast_printer.dart
index ed41fb1..11739dc 100644
--- a/pkg/analyzer/test/src/summary/resolved_ast_printer.dart
+++ b/pkg/analyzer/test/src/summary/resolved_ast_printer.dart
@@ -7,6 +7,7 @@
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/ast/ast.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/member.dart';
 import 'package:analyzer/src/generated/source.dart';
@@ -1316,6 +1317,12 @@
     _writeln('TypeParameter');
     _withIndent(() {
       var properties = _Properties();
+      // TODO (kallentu) : Clean up TypeParameterImpl casting once variance is
+      // added to the interface.
+      if ((node as TypeParameterImpl).varianceKeyword != null) {
+        properties.addToken(
+            'variance', (node as TypeParameterImpl).varianceKeyword);
+      }
       properties.addNode('bound', node.bound);
       properties.addNode('name', node.name);
       _addDeclaration(properties, node);
diff --git a/pkg/analyzer/test/src/summary/resynthesize_ast2_test.dart b/pkg/analyzer/test/src/summary/resynthesize_ast2_test.dart
index f9edcbf..28c0898 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_ast2_test.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_ast2_test.dart
@@ -5,10 +5,9 @@
 import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/analysis/session.dart';
 import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/src/dart/analysis/restricted_analysis_context.dart';
+import 'package:analyzer/src/context/context.dart';
 import 'package:analyzer/src/dart/analysis/session.dart';
 import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/dart/element/type_provider.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/summary/idl.dart';
@@ -62,7 +61,7 @@
     }
 
     var elementFactory = LinkedElementFactory(
-      RestrictedAnalysisContext(
+      AnalysisContextImpl(
         SynchronousSession(
           AnalysisOptionsImpl(),
           declaredVariables,
@@ -92,7 +91,7 @@
     var inputLibraries = <LinkInputLibrary>[];
     _addNonDartLibraries(Set(), inputLibraries, source);
 
-    var analysisContext = RestrictedAnalysisContext(
+    var analysisContext = AnalysisContextImpl(
       SynchronousSession(
         AnalysisOptionsImpl()..contextFeatures = featureSet,
         declaredVariables,
@@ -138,11 +137,7 @@
     if (analysisContext.typeProvider == null) {
       var dartCore = elementFactory.libraryOfUri('dart:core');
       var dartAsync = elementFactory.libraryOfUri('dart:async');
-      var typeProvider = TypeProviderImpl(dartCore, dartAsync);
-      analysisContext.typeProvider = typeProvider;
-
-      dartCore.createLoadLibraryFunction(typeProvider);
-      dartAsync.createLoadLibraryFunction(typeProvider);
+      elementFactory.createTypeProviders(dartCore, dartAsync);
     }
 
     return elementFactory.libraryOfUri('${source.uri}');
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index 41ac8c8..d0f08cd 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -1643,6 +1643,38 @@
 ''');
   }
 
+  test_class_type_parameters_variance_covariant() async {
+    var library = await checkLibrary('class C<out T> {}');
+    checkElementText(library, r'''
+class C<out T> {
+}
+''');
+  }
+
+  test_class_type_parameters_variance_contravariant() async {
+    var library = await checkLibrary('class C<in T> {}');
+    checkElementText(library, r'''
+class C<in T> {
+}
+''');
+  }
+
+  test_class_type_parameters_variance_invariant() async {
+    var library = await checkLibrary('class C<inout T> {}');
+    checkElementText(library, r'''
+class C<inout T> {
+}
+''');
+  }
+
+  test_class_type_parameters_variance_multiple() async {
+    var library = await checkLibrary('class C<inout T, in U, out V> {}');
+    checkElementText(library, r'''
+class C<inout T, in U, out V> {
+}
+''');
+  }
+
   test_classes() async {
     var library = await checkLibrary('class C {} class D {}');
     checkElementText(library, r'''
@@ -9137,6 +9169,38 @@
 ''');
   }
 
+  test_mixin_type_parameters_variance_covariant() async {
+    var library = await checkLibrary('mixin M<out T> {}');
+    checkElementText(library, r'''
+mixin M<out T> on Object {
+}
+''');
+  }
+
+  test_mixin_type_parameters_variance_contravariant() async {
+    var library = await checkLibrary('mixin M<in T> {}');
+    checkElementText(library, r'''
+mixin M<in T> on Object {
+}
+''');
+  }
+
+  test_mixin_type_parameters_variance_invariant() async {
+    var library = await checkLibrary('mixin M<inout T> {}');
+    checkElementText(library, r'''
+mixin M<inout T> on Object {
+}
+''');
+  }
+
+  test_mixin_type_parameters_variance_multiple() async {
+    var library = await checkLibrary('mixin M<inout T, in U, out V> {}');
+    checkElementText(library, r'''
+mixin M<inout T, in U, out V> on Object {
+}
+''');
+  }
+
   test_nameConflict_exportedAndLocal() async {
     addLibrarySource('/a.dart', 'class C {}');
     addLibrarySource('/c.dart', '''
diff --git a/pkg/analyzer/test/src/summary/test_strategies.dart b/pkg/analyzer/test/src/summary/test_strategies.dart
index 5f16bb4..0d3d18e 100644
--- a/pkg/analyzer/test/src/summary/test_strategies.dart
+++ b/pkg/analyzer/test/src/summary/test_strategies.dart
@@ -12,7 +12,6 @@
 import 'package:analyzer/src/dart/scanner/scanner.dart';
 import 'package:analyzer/src/generated/parser.dart';
 import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/summary/format.dart';
 import 'package:analyzer/src/summary/summarize_elements.dart';
 
 import 'resynthesize_common.dart';
@@ -76,8 +75,5 @@
 
   final Set<Source> serializedSources = new Set<Source>();
 
-  final Map<String, UnlinkedUnitBuilder> uriToUnit =
-      <String, UnlinkedUnitBuilder>{};
-
   PackageBundleAssembler bundleAssembler = new PackageBundleAssembler();
 }
diff --git a/pkg/analyzer/test/src/task/strong/checker_test.dart b/pkg/analyzer/test/src/task/strong/checker_test.dart
index 50455ea..d080c3b 100644
--- a/pkg/analyzer/test/src/task/strong/checker_test.dart
+++ b/pkg/analyzer/test/src/task/strong/checker_test.dart
@@ -184,7 +184,7 @@
     m(A a);
 }
 
-class /*error:NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE*/Base
+class /*error:NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER*/Base
     implements I1 {}
 
 class T1 extends Base {
@@ -752,7 +752,7 @@
   dynamic get /*error:INVALID_OVERRIDE*/f4 => null;
 }
 
-class /*error:NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FOUR*/Child2 implements Base {
+class /*error:NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER*/Child2 implements Base {
   A get /*error:INVALID_OVERRIDE*/f1 => null;
   C get f2 => null;
   get f3 => null;
@@ -2605,15 +2605,15 @@
   B /*error:INVALID_OVERRIDE, error:INVALID_OVERRIDE*/f;
 }
 
-class /*error:NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE*/T5 implements Base {
+class /*error:NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER*/T5 implements Base {
   /**/B get /*error:INVALID_OVERRIDE, error:MISMATCHED_GETTER_AND_SETTER_TYPES*/f => null;
 }
 
-class /*error:NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE*/T6 implements Base {
+class /*error:NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER*/T6 implements Base {
   set /*error:INVALID_OVERRIDE, error:MISMATCHED_GETTER_AND_SETTER_TYPES*/f(B b) => null;
 }
 
-class /*error:NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE*/T7 implements Base {
+class /*error:NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER*/T7 implements Base {
   final B /*error:INVALID_OVERRIDE, error:MISMATCHED_GETTER_AND_SETTER_TYPES*/f = null;
 }
 class T8 implements Base {
@@ -3433,7 +3433,7 @@
     m(A a);
 }
 
-class /*error:NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE*/Base
+class /*error:NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER*/Base
     implements I1 {}
 
 class M {
diff --git a/pkg/analyzer/test/src/task/strong/strong_test_helper.dart b/pkg/analyzer/test/src/task/strong/strong_test_helper.dart
index fc52165..5068c51 100644
--- a/pkg/analyzer/test/src/task/strong/strong_test_helper.dart
+++ b/pkg/analyzer/test/src/task/strong/strong_test_helper.dart
@@ -279,8 +279,10 @@
     analysisOptions.strictRawTypes = strictRawTypes;
     analysisOptions.enabledExperiments = enabledExperiments;
 
-    var mockSdk = new MockSdk(resourceProvider: resourceProvider);
-    mockSdk.context.analysisOptions = analysisOptions;
+    var mockSdk = new MockSdk(
+      resourceProvider: resourceProvider,
+      analysisOptions: analysisOptions,
+    );
 
     SourceFactory sourceFactory = new SourceFactory([
       new DartUriResolver(mockSdk),
diff --git a/pkg/analyzer/test/src/workspace/basic_test.dart b/pkg/analyzer/test/src/workspace/basic_test.dart
index a4d4752..8fb66aa 100644
--- a/pkg/analyzer/test/src/workspace/basic_test.dart
+++ b/pkg/analyzer/test/src/workspace/basic_test.dart
@@ -33,6 +33,7 @@
     newFolder('/workspace');
     workspace = BasicWorkspace.find(
         resourceProvider, convertPath('/workspace'), contextBuilder);
+    expect(workspace.isBazel, isFalse);
   }
 
   void test_contains_differentWorkspace() {
@@ -94,6 +95,7 @@
     BasicWorkspace workspace = BasicWorkspace.find(
         resourceProvider, convertPath('/workspace'), new MockContextBuilder());
     expect(workspace.root, convertPath('/workspace'));
+    expect(workspace.isBazel, isFalse);
   }
 
   void test_find_fail_notAbsolute() {
@@ -109,6 +111,7 @@
         convertPath('/workspace/project/lib/lib1.dart'),
         new MockContextBuilder());
     expect(workspace.root, convertPath('/workspace/project/lib'));
+    expect(workspace.isBazel, isFalse);
   }
 }
 
diff --git a/pkg/analyzer/test/src/workspace/bazel_test.dart b/pkg/analyzer/test/src/workspace/bazel_test.dart
index f2080c5..5a9a643 100644
--- a/pkg/analyzer/test/src/workspace/bazel_test.dart
+++ b/pkg/analyzer/test/src/workspace/bazel_test.dart
@@ -35,6 +35,7 @@
     newFile('/workspace/test.dart');
     newFile('/workspace/bazel-bin/gen1.dart');
     newFile('/workspace/bazel-genfiles/gen2.dart');
+    expect(workspace.isBazel, isTrue);
   }
 
   void test_resolveAbsolute_doesNotExist() {
@@ -573,7 +574,22 @@
     expect(package, isNull);
   }
 
-  void test_findPackageFor_packagesFileInBinExists() {
+  void test_findPackageFor_packagesFileExistsInOneOfSeveralBinPaths() {
+    _addResources([
+      '/ws/blaze-out/host/bin/some/code/code.packages',
+      '/ws/blaze-out/k8-opt/bin/some/code/',
+      '/ws/some/code/lib/code.dart',
+    ]);
+    workspace =
+        BazelWorkspace.find(resourceProvider, convertPath('/ws/some/code'));
+
+    package = workspace.findPackageFor('/ws/some/code/lib/code.dart');
+    expect(package, isNotNull);
+    expect(package.root, convertPath('/ws/some/code'));
+    expect(package.workspace, equals(workspace));
+  }
+
+  void test_findPackageFor_packagesFileExistsInOnlyBinPath() {
     _addResources([
       '/ws/blaze-out/host/bin/some/code/code.packages',
       '/ws/some/code/lib/code.dart',
@@ -650,7 +666,8 @@
         resourceProvider, convertPath('/workspace/my/module'));
     expect(workspace.root, convertPath('/workspace'));
     expect(workspace.readonly, isNull);
-    expect(workspace.bin, convertPath('/workspace/blaze-out/host/bin'));
+    expect(workspace.binPaths.single,
+        convertPath('/workspace/blaze-out/host/bin'));
     expect(workspace.genfiles, convertPath('/workspace/blaze-genfiles'));
   }
 
@@ -664,7 +681,25 @@
         resourceProvider, convertPath('/workspace/my/module'));
     expect(workspace.root, convertPath('/workspace'));
     expect(workspace.readonly, isNull);
-    expect(workspace.bin, convertPath('/workspace/blaze-bin'));
+    expect(workspace.binPaths.single, convertPath('/workspace/blaze-bin'));
+    expect(workspace.genfiles, convertPath('/workspace/blaze-genfiles'));
+  }
+
+  void test_find_hasMultipleBlazeBinFolderInOutFolder() {
+    _addResources([
+      '/workspace/blaze-out/host/bin/',
+      '/workspace/blaze-out/k8-fastbuild/bin/',
+      '/workspace/my/module/',
+    ]);
+    BazelWorkspace workspace = BazelWorkspace.find(
+        resourceProvider, convertPath('/workspace/my/module'));
+    expect(workspace.root, convertPath('/workspace'));
+    expect(workspace.readonly, isNull);
+    expect(workspace.binPaths, hasLength(2));
+    expect(workspace.binPaths,
+        contains(convertPath('/workspace/blaze-out/host/bin')));
+    expect(workspace.binPaths,
+        contains(convertPath('/workspace/blaze-out/k8-fastbuild/bin')));
     expect(workspace.genfiles, convertPath('/workspace/blaze-genfiles'));
   }
 
@@ -678,7 +713,8 @@
         resourceProvider, convertPath('/Users/user/test/prime/my/module'));
     expect(workspace.root, convertPath('/Users/user/test/prime'));
     expect(workspace.readonly, convertPath('/Users/user/test/READONLY/prime'));
-    expect(workspace.bin, convertPath('/Users/user/test/prime/bazel-bin'));
+    expect(workspace.binPaths.single,
+        convertPath('/Users/user/test/prime/bazel-bin'));
     expect(workspace.genfiles,
         convertPath('/Users/user/test/prime/bazel-genfiles'));
   }
@@ -693,7 +729,8 @@
         resourceProvider, convertPath('/Users/user/test/prime/my/module'));
     expect(workspace.root, convertPath('/Users/user/test/prime'));
     expect(workspace.readonly, isNull);
-    expect(workspace.bin, convertPath('/Users/user/test/prime/bazel-bin'));
+    expect(workspace.binPaths.single,
+        convertPath('/Users/user/test/prime/bazel-bin'));
     expect(workspace.genfiles,
         convertPath('/Users/user/test/prime/bazel-genfiles'));
   }
@@ -708,7 +745,8 @@
         resourceProvider, convertPath('/Users/user/test/prime/my/module'));
     expect(workspace.root, convertPath('/Users/user/test/prime'));
     expect(workspace.readonly, convertPath('/Users/user/test/READONLY/prime'));
-    expect(workspace.bin, convertPath('/Users/user/test/prime/blaze-bin'));
+    expect(workspace.binPaths.single,
+        convertPath('/Users/user/test/prime/blaze-bin'));
     expect(workspace.genfiles,
         convertPath('/Users/user/test/prime/blaze-genfiles'));
   }
@@ -722,7 +760,7 @@
         resourceProvider, convertPath('/workspace/my/module'));
     expect(workspace.root, convertPath('/workspace'));
     expect(workspace.readonly, isNull);
-    expect(workspace.bin, convertPath('/workspace/bazel-bin'));
+    expect(workspace.binPaths.single, convertPath('/workspace/bazel-bin'));
     expect(workspace.genfiles, convertPath('/workspace/bazel-genfiles'));
   }
 
@@ -735,7 +773,7 @@
         resourceProvider, convertPath('/workspace/my/module'));
     expect(workspace.root, convertPath('/workspace'));
     expect(workspace.readonly, isNull);
-    expect(workspace.bin, convertPath('/workspace/bazel-bin'));
+    expect(workspace.binPaths.single, convertPath('/workspace/bazel-bin'));
     expect(workspace.genfiles, convertPath('/workspace/bazel-genfiles'));
   }
 
@@ -748,7 +786,7 @@
         BazelWorkspace.find(resourceProvider, convertPath('/workspace'));
     expect(workspace.root, convertPath('/workspace'));
     expect(workspace.readonly, isNull);
-    expect(workspace.bin, convertPath('/workspace/bazel-bin'));
+    expect(workspace.binPaths.single, convertPath('/workspace/bazel-bin'));
     expect(workspace.genfiles, convertPath('/workspace/bazel-genfiles'));
   }
 
@@ -761,7 +799,7 @@
         BazelWorkspace.find(resourceProvider, convertPath('/workspace'));
     expect(workspace.root, convertPath('/workspace'));
     expect(workspace.readonly, isNull);
-    expect(workspace.bin, convertPath('/workspace/blaze-bin'));
+    expect(workspace.binPaths.single, convertPath('/workspace/blaze-bin'));
     expect(workspace.genfiles, convertPath('/workspace/blaze-genfiles'));
   }
 
@@ -784,7 +822,7 @@
         resourceProvider, convertPath('/workspace/my/module'));
     expect(workspace.root, convertPath('/workspace'));
     expect(workspace.readonly, isNull);
-    expect(workspace.bin, convertPath('/workspace/$prefix-bin'));
+    expect(workspace.binPaths.single, convertPath('/workspace/$prefix-bin'));
     expect(workspace.genfiles, convertPath('/workspace/$prefix-genfiles'));
   }
 
diff --git a/pkg/analyzer/test/src/workspace/gn_test.dart b/pkg/analyzer/test/src/workspace/gn_test.dart
index b3348de..0ed21d5 100644
--- a/pkg/analyzer/test/src/workspace/gn_test.dart
+++ b/pkg/analyzer/test/src/workspace/gn_test.dart
@@ -99,7 +99,10 @@
     newFile('/ws/.fx-build-dir', content: '$buildDir\n');
     newFile('/ws/out/debug-x87_128/dartlang/gen/some/code/foo.packages');
     newFolder('/ws/some/code');
-    return GnWorkspace.find(resourceProvider, convertPath('/ws/some/code'));
+    var gnWorkspace =
+        GnWorkspace.find(resourceProvider, convertPath('/ws/some/code'));
+    expect(gnWorkspace.isBazel, isFalse);
+    return gnWorkspace;
   }
 }
 
diff --git a/pkg/analyzer/test/src/workspace/package_build_test.dart b/pkg/analyzer/test/src/workspace/package_build_test.dart
index 6045fb1..0a25d2c 100644
--- a/pkg/analyzer/test/src/workspace/package_build_test.dart
+++ b/pkg/analyzer/test/src/workspace/package_build_test.dart
@@ -66,6 +66,7 @@
     resolver = new PackageBuildFileUriResolver(workspace);
     newFile('/workspace/test.dart');
     newFile('/workspace/.dart_tool/build/generated/project/gen.dart');
+    expect(workspace.isBazel, isFalse);
   }
 
   void test_resolveAbsolute_doesNotExist() {
diff --git a/pkg/analyzer/test/src/workspace/pub_test.dart b/pkg/analyzer/test/src/workspace/pub_test.dart
index 7d7e987..5257ee9 100644
--- a/pkg/analyzer/test/src/workspace/pub_test.dart
+++ b/pkg/analyzer/test/src/workspace/pub_test.dart
@@ -51,6 +51,7 @@
     newFileWithBytes('/workspace/pubspec.yaml', 'name: project'.codeUnits);
     workspace = PubWorkspace.find(
         resourceProvider, convertPath('/workspace'), contextBuilder);
+    expect(workspace.isBazel, isFalse);
   }
 
   void test_contains_differentWorkspace() {
@@ -108,6 +109,7 @@
     newFileWithBytes('/workspace/pubspec.yaml', 'name: project'.codeUnits);
     PubWorkspace workspace = PubWorkspace.find(
         resourceProvider, convertPath('/workspace'), new MockContextBuilder());
+    expect(workspace.isBazel, isFalse);
     expect(workspace.root, convertPath('/workspace'));
   }
 
diff --git a/pkg/analyzer/test/verify_diagnostics_test.dart b/pkg/analyzer/test/verify_diagnostics_test.dart
index e829ba7..280363c 100644
--- a/pkg/analyzer/test/verify_diagnostics_test.dart
+++ b/pkg/analyzer/test/verify_diagnostics_test.dart
@@ -36,7 +36,12 @@
   /// A list of the diagnostic codes that are not being verified. These should
   /// ony include docs that cannot be verified because of missing support in the
   /// verifier.
-  static const List<String> unverifiedDocs = ['HintCode.DEPRECATED_MEMBER_USE'];
+  static const List<String> unverifiedDocs = [
+    // The code has been replaced but is not yet removed.
+    'HintCode.DEPRECATED_MEMBER_USE',
+    // Needs two expected errors.
+    'StaticWarningCode.AMBIGUOUS_IMPORT',
+  ];
 
   /// The prefix used on directive lines to indicate the uri of an auxiliary
   /// file that is needed for testing purposes.
@@ -231,14 +236,24 @@
 
               List<_SnippetData> exampleSnippets =
                   _extractSnippets(docs, exampleStart + 1, fixesStart, true);
-              for (_SnippetData snippet in exampleSnippets) {
-                await _validateSnippet(snippet);
+              _SnippetData firstExample;
+              if (exampleSnippets.isEmpty) {
+                _reportProblem('No example.');
+              } else {
+                firstExample = exampleSnippets[0];
+              }
+              for (int i = 0; i < exampleSnippets.length; i++) {
+                await _validateSnippet('example', i, exampleSnippets[i]);
               }
 
               List<_SnippetData> fixesSnippets =
                   _extractSnippets(docs, fixesStart + 1, docs.length, false);
-              for (_SnippetData snippet in fixesSnippets) {
-                await _validateSnippet(snippet);
+              for (int i = 0; i < fixesSnippets.length; i++) {
+                _SnippetData snippet = fixesSnippets[i];
+                if (firstExample != null) {
+                  snippet.auxiliaryFiles.addAll(firstExample.auxiliaryFiles);
+                }
+                await _validateSnippet('fixes', i, snippet);
               }
             }
           }
@@ -251,7 +266,8 @@
   /// verify that no diagnostics are reported. If the offset is greater than or
   /// equal to zero, verify that one error whose name matches the current code
   /// is reported at that offset with the expected length.
-  Future<void> _validateSnippet(_SnippetData snippet) async {
+  Future<void> _validateSnippet(
+      String section, int index, _SnippetData snippet) async {
     _SnippetTest test = _SnippetTest(snippet);
     test.setUp();
     await test.resolveTestFile();
@@ -259,28 +275,30 @@
     int errorCount = errors.length;
     if (snippet.offset < 0) {
       if (errorCount > 0) {
-        _reportProblem('Expected no errors but found $errorCount:',
+        _reportProblem(
+            'Expected no errors but found $errorCount ($section $index):',
             errors: errors);
       }
     } else {
       if (errorCount == 0) {
-        _reportProblem('Expected one error but found none.');
+        _reportProblem('Expected one error but found none ($section $index).');
       } else if (errorCount == 1) {
         AnalysisError error = errors[0];
         if (error.errorCode.uniqueName != codeName) {
-          _reportProblem(
-              'Expected an error with code $codeName, found ${error.errorCode}.');
+          _reportProblem('Expected an error with code $codeName, '
+              'found ${error.errorCode} ($section $index).');
         }
         if (error.offset != snippet.offset) {
-          _reportProblem(
-              'Expected an error at ${snippet.offset}, found ${error.offset}.');
+          _reportProblem('Expected an error at ${snippet.offset}, '
+              'found ${error.offset} ($section $index).');
         }
         if (error.length != snippet.length) {
-          _reportProblem(
-              'Expected an error of length ${snippet.length}, found ${error.length}.');
+          _reportProblem('Expected an error of length ${snippet.length}, '
+              'found ${error.length} ($section $index).');
         }
       } else {
-        _reportProblem('Expected one error but found $errorCount:',
+        _reportProblem(
+            'Expected one error but found $errorCount ($section $index):',
             errors: errors);
       }
     }
diff --git a/pkg/analyzer/tool/diagnostics/diagnostics.md b/pkg/analyzer/tool/diagnostics/diagnostics.md
index 3df5e19..107a489 100644
--- a/pkg/analyzer/tool/diagnostics/diagnostics.md
+++ b/pkg/analyzer/tool/diagnostics/diagnostics.md
@@ -74,7 +74,8 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because `B` doesn't inherit a
+concrete implementation of `a`:
 
 {% prettify dart %}
 abstract class A {
@@ -150,6 +151,72 @@
 }
 {% endprettify %}
 
+### ambiguous_import
+
+_The name '{0}' is defined in the libraries {1}._
+
+#### Description
+
+The analyzer produces this diagnostic when a name is referenced that is
+declared in two or more imported libraries.
+
+#### Example
+
+Given a library (`a.dart`) that defines a class (`C` in this example):
+
+{% prettify dart %}
+class A {}
+class C {}
+{% endprettify %}
+
+And a library (`b.dart`) that defines a different class with the same name:
+
+{% prettify dart %}
+class B {}
+class C {}
+{% endprettify %}
+
+The following code produces this diagnostic:
+
+{% prettify dart %}
+import 'a.dart';
+import 'b.dart';
+
+void f([!C!] c1, [!C!] c2) {}
+{% endprettify %}
+
+#### Common fixes
+
+If any of the libraries aren't needed, then remove the import directives
+for them:
+
+{% prettify dart %}
+import 'a.dart';
+
+void f(C c1, C c2) {}
+{% endprettify %}
+
+If the name is still defined by more than one library, then add a `hide`
+clause to the import directives for all except one library:
+
+{% prettify dart %}
+import 'a.dart' hide C;
+import 'b.dart';
+
+void f(C c1, C c2) {}
+{% endprettify %}
+
+If you must be able to reference more than one of these types, then add a
+prefix to each of the import directives, and qualify the references with
+the appropriate prefix:
+
+{% prettify dart %}
+import 'a.dart' as a;
+import 'b.dart' as b;
+
+void f(a.C c1, b.C c2) {}
+{% endprettify %}
+
 ### ambiguous_set_or_map_literal_both
 
 _This literal contains both 'Map' and 'Iterable' spreads, which makes it
@@ -288,7 +355,8 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because a `num` can't be
+assigned to a `String`:
 
 {% prettify dart %}
 String f(String x) => x;
@@ -330,6 +398,62 @@
 String g(num y) => f(y as String);
 {% endprettify %}
 
+### assignment_to_final_no_setter
+
+_There isn’t a setter named '{0}' in class '{1}'._
+
+#### Description
+
+The analyzer produces this diagnostic when a reference to a setter is
+found; there is no setter defined for the type; but there is a getter
+defined with the same name.
+
+#### Example
+
+The following code produces this diagnostic because there is no setter
+named `x` in `C`, but there is a getter named `x`:
+
+{% prettify dart %}
+class C {
+  int get x => 0;
+  set y(int p) {}
+}
+
+void f(C c) {
+  c.[!x!] = 1;
+}
+{% endprettify %}
+
+#### Common fixes
+
+If you want to invoke an existing setter, then correct the name:
+
+{% prettify dart %}
+class C {
+  int get x => 0;
+  set y(int p) {}
+}
+
+void f(C c) {
+  c.y = 1;
+}
+{% endprettify %}
+
+If you want to invoke the setter but it just doesn't exist yet, then
+declare it:
+
+{% prettify dart %}
+class C {
+  int get x => 0;
+  set x(int p) {}
+  set y(int p) {}
+}
+
+void f(C c) {
+  c.x = 1;
+}
+{% endprettify %}
+
 ### built_in_identifier_as_extension_name
 
 _The built-in identifier '{0}' can't be used as an extension name._
@@ -341,7 +465,8 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because `mixin` is a built-in
+identifier:
 
 {% prettify dart %}
 extension [!mixin!] on int {}
@@ -362,7 +487,8 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because `x` is a variable, not
+a type:
 
 {% prettify dart %}
 num x = 0;
@@ -378,6 +504,47 @@
 int y = x as int;
 {% endprettify %}
 
+### concrete_class_with_abstract_member
+
+_'{0}' must have a method body because '{1}' isn't abstract._
+
+#### Description
+
+The analyzer produces this diagnostic when a member of a concrete class is
+found that doesn't have a concrete implementation. Concrete classes aren't
+allowed to contain abstract members.
+
+#### Example
+
+The following code produces this diagnostic because `m` is an abstract
+method but `C` isn't an abstract class:
+
+{% prettify dart %}
+class C {
+  [!void m();!]
+}
+{% endprettify %}
+
+#### Common fixes
+
+If it's valid to create instances of the class, provide an implementation
+for the member:
+
+{% prettify dart %}
+class C {
+  void m() {}
+}
+{% endprettify %}
+
+If it isn't valid to create instances of the class, mark the class as being
+abstract:
+
+{% prettify dart %}
+abstract class C {
+  void m();
+}
+{% endprettify %}
+
 ### const_initialized_with_non_constant_value
 
 _Const variables must be initialized with a constant value._
@@ -416,6 +583,31 @@
 final y = x;
 {% endprettify %}
 
+### const_not_initialized
+
+_The constant '{0}' must be initialized._
+
+#### Description
+
+The analyzer produces this diagnostic when a variable that is declared to
+be a constant doesn't have an initializer.
+
+#### Example
+
+The following code produces this diagnostic because `c` isn't initialized:
+
+{% prettify dart %}
+const [!c!];
+{% endprettify %}
+
+#### Common fixes
+
+Add an initializer:
+
+{% prettify dart %}
+const c = 'c';
+{% endprettify %}
+
 ### const_spread_expected_list_or_set
 
 _A list or a set is expected in this spread._
@@ -428,7 +620,8 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because the value of `list1` is
+`null`, which is neither a list nor a set:
 
 {% prettify dart %}
 const List<int> list1 = null;
@@ -456,7 +649,8 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because the value of `map1` is
+`null`, which isn't a map:
 
 {% prettify dart %}
 const Map<String, int> map1 = null;
@@ -483,7 +677,7 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because `i` isn't a constant:
 
 {% prettify dart %}
 class C {
@@ -506,6 +700,159 @@
 C f(int i) => C(i);
 {% endprettify %}
 
+### dead_code
+
+_Dead code._
+
+#### Description
+
+The analyzer produces this diagnostic when code is found that won't be
+executed because execution will never reach the code.
+
+#### Example
+
+The following code produces this diagnostic because the invocation of
+`print` occurs after the function has returned:
+
+{% prettify dart %}
+void f() {
+  return;
+  [!print('here');!]
+}
+{% endprettify %}
+
+#### Common fixes
+
+If the code isn't needed, then remove it:
+
+{% prettify dart %}
+void f() {
+  return;
+}
+{% endprettify %}
+
+If the code needs to be executed, then either move the code to a place
+where it will be executed:
+
+{% prettify dart %}
+void f() {
+  print('here');
+  return;
+}
+{% endprettify %}
+
+Or, rewrite the code before it, so that it can be reached:
+
+{% prettify dart %}
+void f({bool skipPrinting = true}) {
+  if (skipPrinting) {
+    return;
+  }
+  print('here');
+}
+{% endprettify %}
+
+### dead_code_catch_following_catch
+
+_Dead code: Catch clauses after a 'catch (e)' or an 'on Object catch (e)' are
+never reached._
+
+#### Description
+
+The analyzer produces this diagnostic when a catch clause is found that
+can't be executed because it’s after a catch clause of the form `catch (e)`
+or `on Object catch (e)`. The first catch clause that matches the thrown
+object is selected, and both of those forms will match any object, so no
+catch clauses that follow them will be selected.
+
+#### Example
+
+The following code produces this diagnostic:
+
+{% prettify dart %}
+void f() {
+  try {
+  } catch (e) {
+  } [!on String {
+  }!]
+}
+{% endprettify %}
+
+#### Common fixes
+
+If the clause should be selectable, then move the clause before the general
+clause:
+
+{% prettify dart %}
+void f() {
+  try {
+  } on String {
+  } catch (e) {
+  }
+}
+{% endprettify %}
+
+If the clause doesn't need to be selectable, then remove it:
+
+{% prettify dart %}
+void f() {
+  try {
+  } catch (e) {
+  }
+}
+{% endprettify %}
+
+### dead_code_on_catch_subtype
+
+_Dead code: This on-catch block won’t be executed because '{0}' is a subtype of
+'{1}' and hence will have been caught already._
+
+#### Description
+
+The analyzer produces this diagnostic when a catch clause is found that
+can't be executed because it is after a catch clause that catches either
+the same type or a supertype of the clause's type. The first catch clause
+that matches the thrown object is selected, and the earlier clause l always
+matches anything matchable by the highlighted clause, so the highlighted
+clause will never be selected.
+
+#### Example
+
+The following code produces this diagnostic:
+
+{% prettify dart %}
+void f() {
+  try {
+  } on num {
+  } [!on int {
+  }!]
+}
+{% endprettify %}
+
+#### Common fixes
+
+If the clause should be selectable, then move the clause before the general
+clause:
+
+{% prettify dart %}
+void f() {
+  try {
+  } on int {
+  } on num {
+  }
+}
+{% endprettify %}
+
+If the clause doesn't need to be selectable, then remove it:
+
+{% prettify dart %}
+void f() {
+  try {
+  } on num {
+  }
+}
+{% endprettify %}
+
 ### deprecated_member_use
 
 _'{0}' is deprecated and shouldn't be used._
@@ -546,7 +893,7 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because `x` is deprecated:
 
 {% prettify dart %}
 @deprecated
@@ -571,7 +918,8 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because the name `x` is
+declared twice:
 
 {% prettify dart %}
 int x = 0;
@@ -587,6 +935,37 @@
 int y = 1;
 {% endprettify %}
 
+### duplicate_import
+
+_Duplicate import._
+
+#### Description
+
+The analyzer produces this diagnostic when an import directive is found
+that is the same as an import before it in the file. The second import
+doesn’t add value and should be removed.
+
+#### Example
+
+The following code produces this diagnostic:
+
+{% prettify dart %}
+import 'package:meta/meta.dart';
+import [!'package:meta/meta.dart'!];
+
+@sealed class C {}
+{% endprettify %}
+
+#### Common fixes
+
+Remove the unnecessary import:
+
+{% prettify dart %}
+import 'package:meta/meta.dart';
+
+@sealed class C {}
+{% endprettify %}
+
 ### equal_elements_in_const_set
 
 _Two values in a constant set can't be equal._
@@ -599,7 +978,8 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because the string `'a'` is
+specified twice:
 
 {% prettify dart %}
 const Set<String> set = {'a', [!'a'!]};
@@ -630,7 +1010,8 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because the key `1` is used
+twice:
 
 {% prettify dart %}
 const map = <int, String>{1: 'a', 2: 'b', [!1!]: 'c', 4: 'd'};
@@ -683,6 +1064,47 @@
 var map = <String, int>{'a': 0, 'b': 1, 'c': 2};
 {% endprettify %}
 
+### extends_non_class
+
+_Classes can only extend other classes._
+
+#### Description
+
+The analyzer produces this diagnostic when an extends clause contains a
+name that is declared to be something other than a class.
+
+#### Example
+
+The following code produces this diagnostic because `f` is declared to be a
+function:
+
+{% prettify dart %}
+void f() {}
+
+class C extends [!f!] {}
+{% endprettify %}
+
+#### Common fixes
+
+If you want the class to extend a class other than `Object`, then replace
+the name in the extends clause with the name of that class:
+
+{% prettify dart %}
+void f() {}
+
+class C extends B {}
+
+class B {}
+{% endprettify %}
+
+If you want the class to extend `Object`, then remove the extends clause:
+
+{% prettify dart %}
+void f() {}
+
+class C {}
+{% endprettify %}
+
 ### extension_as_expression
 
 _Extension '{0}' can't be used as an expression._
@@ -691,11 +1113,14 @@
 
 The analyzer produces this diagnostic when the name of an extension is used
 in an expression other than in an extension override or to qualify an
-access to a static member of the extension.
+access to a static member of the extension. Because classes define a type,
+the name of a class can be used to refer to the instance of `Type`
+representing the type of the class. Extensions, on the other hand, don't
+define a type and can't be used as a type literal.
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because `E` is an extension:
 
 {% prettify dart %}
 extension E on int {
@@ -733,7 +1158,8 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because the name `a` is being
+used for two different members:
 
 {% prettify dart %}
 extension E on Object {
@@ -764,7 +1190,8 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because the method `a` doesn't
+have a body:
 
 {% prettify dart %}
 extension E on String {
@@ -789,7 +1216,8 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because there is a constructor
+declaration in `E`:
 
 {% prettify dart %}
 extension E on String {
@@ -813,7 +1241,8 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because `s` is an instance
+field:
 
 {% prettify dart %}
 extension E on String {
@@ -840,7 +1269,8 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because `toString` is defined
+by `Object`:
 
 {% prettify dart %}
 extension E on String {
@@ -873,15 +1303,15 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because `m` is static:
 
 {% prettify dart %}
 extension E on String {
-  static void staticMethod() {}
+  static void m() {}
 }
 
 void f() {
-  E('').[!staticMethod!]();
+  E('').[!m!]();
 }
 {% endprettify %}
 
@@ -891,11 +1321,11 @@
 
 {% prettify dart %}
 extension E on String {
-  static void staticMethod() {}
+  static void m() {}
 }
 
 void f() {
-  E.staticMethod();
+  E.m();
 }
 {% endprettify %}
 
@@ -911,7 +1341,7 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because `3` isn't a `String`:
 
 {% prettify dart %}
 extension E on String {
@@ -955,7 +1385,8 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because `E(i)` isn't an
+expression:
 
 {% prettify dart %}
 extension E on int {
@@ -1002,11 +1433,14 @@
 #### Description
 
 The analyzer produces this diagnostic when an extension override is used as
-the target of a cascade expression.
+the target of a cascade expression. The value of a cascade expression
+`e..m` is the value of the target `e`, but extension overrides are not
+expressions and don't have a value.
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because `E(3)` isn't an
+expression:
 
 {% prettify dart %}
 extension E on int {
@@ -1044,7 +1478,8 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because `f` defines 2
+parameters but is invoked with 3 arguments:
 
 {% prettify dart %}
 void f(int a, int b) {}
@@ -1076,7 +1511,9 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because `f` defines 2
+positional parameters but has a named parameter that could be used for the
+third argument:
 
 {% prettify dart %}
 void f(int a, int b, {int c}) {}
@@ -1118,7 +1555,8 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because `x` doesn't have an
+initializer:
 
 {% prettify dart %}
 final [!x!];
@@ -1153,6 +1591,97 @@
 }
 {% endprettify %}
 
+### final_not_initialized_constructor
+
+_All final variables must be initialized, but '{0}' and '{1}' are not._
+
+_All final variables must be initialized, but '{0}' is not._
+
+_All final variables must be initialized, but '{0}', '{1}', and {2} others are
+not._
+
+#### Description
+
+The analyzer produces this diagnostic when a class defines one or more
+final instance fields without initializers and has at least one constructor
+that doesn't initialize those fields. All final instance fields must be
+initialized when the instance is created, either by the field's initializer
+or by the constructor.
+
+#### Example
+
+The following code produces this diagnostic:
+
+{% prettify dart %}
+class C {
+  final String value;
+
+  [!C!]();
+}
+{% endprettify %}
+
+#### Common fixes
+
+If the value should be passed in to the constructor directly, then use a
+field formal parameter to initialize the field `value`:
+
+{% prettify dart %}
+class C {
+  final String value;
+
+  C(this.value);
+}
+{% endprettify %}
+
+If the value should be computed indirectly from a value provided by the
+caller, then add a parameter and include an initializer:
+
+{% prettify dart %}
+class C {
+  final String value;
+
+  C(Object o) : value = o.toString();
+}
+{% endprettify %}
+
+If the value of the field doesn't depend on values that can be passed to
+the constructor, then add an initializer for the field as part of the field
+declaration:
+
+{% prettify dart %}
+class C {
+  final String value = '';
+
+  C();
+}
+{% endprettify %}
+
+If the value of the field doesn't depend on values that can be passed to
+the constructor but different constructors need to initialize it to
+different values, then add an initializer for the field in the initializer
+list:
+
+{% prettify dart %}
+class C {
+  final String value;
+
+  C() : value = '';
+
+  C.named() : value = 'c';
+}
+{% endprettify %}
+
+However, if the value is the same for all instances, then consider using a
+static field instead of an instance field:
+
+{% prettify dart %}
+class C {
+  static const String value = '';
+
+  C();
+}
+{% endprettify %}
+
 ### implements_non_class
 
 _Classes and mixins can only implement other classes and mixins._
@@ -1165,7 +1694,8 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because `x` is a variable
+rather than a class or mixin:
 
 {% prettify dart %}
 var x;
@@ -1186,6 +1716,126 @@
 of an existing class or mixin, or remove the name from the implements
 clause.
 
+### implicit_this_reference_in_initializer
+
+_Only static members can be accessed in initializers._
+
+#### Description
+
+The analyzer produces this diagnostic when it finds a reference to an
+instance member in a constructor's initializer list.
+
+#### Example
+
+The following code produces this diagnostic because `defaultX` is an
+instance member:
+
+{% prettify dart %}
+class C {
+  int x;
+
+  C() : x = [!defaultX!];
+
+  int get defaultX => 0;
+}
+{% endprettify %}
+
+#### Common fixes
+
+If the member can be made static, then do so:
+
+{% prettify dart %}
+class C {
+  int x;
+
+  C() : x = defaultX;
+
+  static int get defaultX => 0;
+}
+{% endprettify %}
+
+If not, then replace the reference in the initializer with a different
+expression that doesn't use an instance member:
+
+{% prettify dart %}
+class C {
+  int x;
+
+  C() : x = 0;
+
+  int get defaultX => 0;
+}
+{% endprettify %}
+
+### initializing_formal_for_non_existent_field
+
+_'{0}' isn't a field in the enclosing class._
+
+#### Description
+
+The analyzer produces this diagnostic when a field formal parameter is
+found in a constructor in a class that doesn't declare the field being
+initialized.
+
+#### Example
+
+The following code produces this diagnostic because the field `x` isn't
+defined:
+
+{% prettify dart %}
+class C {
+  int y;
+
+  C([!this.x!]);
+}
+{% endprettify %}
+
+#### Common fixes
+
+If the field name was wrong, then change it to the name of an existing
+field:
+
+{% prettify dart %}
+class C {
+  int y;
+
+  C(this.y);
+}
+{% endprettify %}
+
+If the field name is correct but hasn't yet been defined, then declare the
+field:
+
+{% prettify dart %}
+class C {
+  int x;
+  int y;
+
+  C(this.x);
+}
+{% endprettify %}
+
+If the parameter is needed but shouldn't initialize a field, then convert
+it to a normal parameter and use it:
+
+{% prettify dart %}
+class C {
+  int y;
+
+  C(int x) : y = x * 2;
+}
+{% endprettify %}
+
+If the parameter isn't needed, then remove it:
+
+{% prettify dart %}
+class C {
+  int y;
+
+  C();
+}
+{% endprettify %}
+
 ### invalid_assignment
 
 _A value of type '{0}' can't be assigned to a variable of type '{1}'._
@@ -1287,12 +1937,25 @@
 
 #### Description
 
-The meaning of the `@literal` annotation is only defined when it's applied
-to a const constructor.
+The analyzer produces this diagnostic when the `@literal` annotation is
+applied to anything other than a const constructor.
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because the constructor is not
+a `const` constructor:
+
+{% prettify dart %}
+import 'package:meta/meta.dart';
+
+class C {
+  [!@literal!]
+  C();
+}
+{% endprettify %}
+
+The following code produces this diagnostic because `x` isn't a
+constructor:
 
 {% prettify dart %}
 import 'package:meta/meta.dart';
@@ -1303,12 +1966,89 @@
 
 #### Common fixes
 
-Remove the annotation:
+If the annotation is on a constructor and the constructor should always be
+invoked with `const`, when possible, then mark the constructor with the
+`const` keyword:
+
+{% prettify dart %}
+import 'package:meta/meta.dart';
+
+class C {
+  @literal
+  const C();
+}
+{% endprettify %}
+
+If the constructor can't be marked as `const`, then remove the annotation.
+
+If the annotation is on anything other than a constructor, then remove the
+annotation:
 
 {% prettify dart %}
 var x;
 {% endprettify %}
 
+### invalid_override
+
+_'{1}.{0}' ('{2}') isn't a valid override of '{3}.{0}' ('{4}')._
+
+#### Description
+
+The analyzer produces this diagnostic when a member of a class is found
+that overrides a member from a supertype and the override isn't valid. An
+override is valid if all of these are true:
+* It allows all of the arguments allowed by the overridden member.
+* It doesn't require any arguments that aren't required by the overridden
+  member.
+* The type of every parameter of the overridden member is assignable to the
+  corresponding parameter of the override.
+* The return type of the override is assignable to the return type of the
+  overridden member.
+
+#### Example
+
+The following code produces this diagnostic because the type of the
+parameter `s` (`String`) isn't assignable to the type of the parameter `i`
+(`int`):
+
+{% prettify dart %}
+class A {
+  void m(int i) {}
+}
+
+class B extends A {
+  void [!m!](String s) {}
+}
+{% endprettify %}
+
+#### Common fixes
+
+If the invalid method is intended to override the method from the
+superclass, then change it to conform:
+
+{% prettify dart %}
+class A {
+  void m(int i) {}
+}
+
+class B extends A {
+  void m(int i) {}
+}
+{% endprettify %}
+
+If it isn't intended to override the method from the superclass, then
+rename it:
+
+{% prettify dart %}
+class A {
+  void m(int i) {}
+}
+
+class B extends A {
+  void m2(String s) {}
+}
+{% endprettify %}
+
 ### invalid_use_of_covariant_in_extension
 
 _Can't have modifier '#lexeme' in an extension._
@@ -1322,7 +2062,8 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because `i` is marked as being
+covariant:
 
 {% prettify dart %}
 extension E on String {
@@ -1340,6 +2081,94 @@
 }
 {% endprettify %}
 
+### invalid_visibility_annotation
+
+_The member '{0}' is annotated with '{1}', but this annotation is only
+meaningful on declarations of public members._
+
+#### Description
+
+The analyzer produces this diagnostic when either the `@visibleForTemplate`
+or `@visibleForTesting` annotation is applied to a non-public declaration.
+
+#### Example
+
+The following code produces this diagnostic:
+
+{% prettify dart %}
+import 'package:meta/meta.dart';
+
+[!@visibleForTesting!]
+void _someFunction() {}
+
+void f() => _someFunction();
+{% endprettify %}
+
+#### Common fixes
+
+If the declaration doesn't need to be used by test code, then remove the
+annotation:
+
+{% prettify dart %}
+void _someFunction() {}
+
+void f() => _someFunction();
+{% endprettify %}
+
+If it does, then make it public:
+
+{% prettify dart %}
+import 'package:meta/meta.dart';
+
+@visibleForTesting
+void someFunction() {}
+
+void f() => someFunction();
+{% endprettify %}
+
+### invocation_of_extension_without_call
+
+_The extension '{0}' doesn't define a 'call' method so the override can't be
+used in an invocation._
+
+#### Description
+
+The analyzer produces this diagnostic when an extension override is used to
+invoke a function but the extension doesn't declare a `call` method.
+
+#### Example
+
+The following code produces this diagnostic because the extension `E`
+doesn't define a `call` method:
+
+{% prettify dart %}
+extension E on String {}
+
+void f() {
+  [!E('')!]();
+}
+{% endprettify %}
+
+#### Common fixes
+
+If the extension is intended to define a `call` method, then declare it:
+
+{% prettify dart %}
+extension E on String {
+  int call() => 0;
+}
+
+void f() {
+  E('')();
+}
+{% endprettify %}
+
+If the extended type defines a `call` method, then remove the extension
+override.
+
+If the `call` method isn't defined, then rewrite the code so that it
+doesn't invoke the `call` method.
+
 ### invocation_of_non_function
 
 _'{0}' isn't a function._
@@ -1352,7 +2181,8 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because `Binary` is the name of
+a function type, not a function:
 
 {% prettify dart %}
 typedef Binary = int Function(int, int);
@@ -1366,6 +2196,46 @@
 
 Replace the name with the name of a function.
 
+### list_element_type_not_assignable
+
+_The element type '{0}' can't be assigned to the list type '{1}'._
+
+#### Description
+
+The analyzer produces this diagnostic when the type of an element in a list
+literal isn't assignable to the element type of the list.
+
+#### Example
+
+The following code produces this diagnostic because `2.5` is a double, and
+the list can hold only integers:
+
+{% prettify dart %}
+List<int> x = [1, [!2.5!], 3];
+{% endprettify %}
+
+#### Common fixes
+
+If you intended to add a different object to the list, then replace the
+element with an expression that computes the intended object:
+
+{% prettify dart %}
+List<int> x = [1, 2, 3];
+{% endprettify %}
+
+If the object shouldn't be in the list, then remove the element:
+
+{% prettify dart %}
+List<int> x = [1, 3];
+{% endprettify %}
+
+If the object being computed is correct, then widen the element type of the
+list to allow all of the different types of objects it needs to contain:
+
+{% prettify dart %}
+List<num> x = [1, 2.5, 3];
+{% endprettify %}
+
 ### map_entry_not_in_map
 
 _Map entries can only be used in a map literal._
@@ -1377,7 +2247,8 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because the literal has a map
+entry even though it's a set literal:
 
 {% prettify dart %}
 const collection = <String>{[!'a' : 'b'!]};
@@ -1404,6 +2275,47 @@
 const collection = <String>{'a', 'b'};
 {% endprettify %}
 
+### missing_required_param
+
+_The parameter '{0}' is required._
+
+_The parameter '{0}' is required. {1}._
+
+#### Description
+
+The analyzer produces this diagnostic when a method or function with a
+named parameter that is annotated as being required is invoked without
+providing a value for the parameter.
+
+#### Example
+
+The following code produces this diagnostic because the named parameter `x`
+is required:
+
+{% prettify dart %}
+import 'package:meta/meta.dart';
+
+void f({@required int x}) {}
+
+void g() {
+  [!f!]();
+}
+{% endprettify %}
+
+#### Common fixes
+
+Provide the required value:
+
+{% prettify dart %}
+import 'package:meta/meta.dart';
+
+void f({@required int x}) {}
+
+void g() {
+  f(x: 2);
+}
+{% endprettify %}
+
 ### missing_return
 
 _This function has a return type of '{0}', but doesn't end with a return
@@ -1417,7 +2329,8 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because `f` doesn't end with a
+return:
 
 {% prettify dart %}
 int [!f!](int x) {
@@ -1432,6 +2345,177 @@
 Add a return statement that makes the return value explicit, even if `null`
 is the appropriate value.
 
+### mixin_on_sealed_class
+
+_The class '{0}' shouldn't be used as a mixin constraint because it is sealed,
+and any class mixing in this mixin must have '{0}' as a superclass._
+
+#### Description
+
+The analyzer produces this diagnostic when the superclass constraint of a
+mixin is a class from a different package that was marked as `@sealed`.
+Classes that are sealed can't be extended, implemented, mixed in, or used
+as a superclass constraint.
+
+#### Example
+
+If the package 'p' defines a sealed class:
+
+{% prettify dart %}
+import 'package:meta/meta.dart';
+
+@sealed
+class C {}
+{% endprettify %}
+
+Then, the following code, when in a package other than 'p', produces this
+diagnostic:
+
+{% prettify dart %}
+import 'package:p/p.dart';
+
+[!mixin M on C {}!]
+{% endprettify %}
+
+#### Common fixes
+
+If the classes that use the mixin don't need to be subclasses of the sealed
+class, then consider adding a field and delegating to the wrapped instance
+of the sealed class.
+
+### mixin_super_class_constraint_non_interface
+
+_Only classes and mixins can be used as superclass constraints._
+
+#### Description
+
+The analyzer produces this diagnostic when a type following the `on`
+keyword in a mixin declaration is neither a class nor a mixin.
+
+#### Example
+
+The following code produces this diagnostic because `F` is neither a class
+nor a mixin:
+
+{% prettify dart %}
+typedef F = void Function();
+
+mixin M on [!F!] {}
+{% endprettify %}
+
+#### Common fixes
+
+If the type was intended to be a class but was mistyped, then replace the
+name.
+
+Otherwise, remove the type from the on clause.
+
+### non_abstract_class_inherits_abstract_member
+
+_Missing concrete implementation of '{0}'._
+
+_Missing concrete implementations of '{0}' and '{1}'._
+
+_Missing concrete implementations of '{0}', '{1}', '{2}', '{3}', and {4} more._
+
+_Missing concrete implementations of '{0}', '{1}', '{2}', and '{3}'._
+
+_Missing concrete implementations of '{0}', '{1}', and '{2}'._
+
+#### Description
+
+The analyzer produces this diagnostic when a concrete class inherits one or
+more abstract members, and doesn't provide or inherit an implementation for
+at least one of those abstract members.
+
+#### Example
+
+The following code produces this diagnostic because the class `B` doesn't
+have a concrete implementation of `m`:
+
+{% prettify dart %}
+abstract class A {
+  void m();
+}
+
+class [!B!] extends A {}
+{% endprettify %}
+
+#### Common fixes
+
+If the subclass can provide a concrete implementation for some or all of
+the abstract inherited members, then add the concrete implementations:
+
+{% prettify dart %}
+abstract class A {
+  void m();
+}
+
+class B extends A {
+  void m() {}
+}
+{% endprettify %}
+
+If there is a mixin that provides an implementation of the inherited
+methods, then apply the mixin to the subclass:
+
+{% prettify dart %}
+abstract class A {
+  void m();
+}
+
+class B extends A with M {}
+
+mixin M {
+  void m() {}
+}
+{% endprettify %}
+
+If the subclass can't provide a concrete implementation for all of the
+abstract inherited members, then mark the subclass as being abstract:
+
+{% prettify dart %}
+abstract class A {
+  void m();
+}
+
+abstract class B extends A {}
+{% endprettify %}
+
+### non_bool_condition
+
+_Conditions must have a static type of 'bool'._
+
+#### Description
+
+The analyzer produces this diagnostic when a condition, such as an `if` or
+`while` loop, doesn't have the static type `bool`.
+
+#### Example
+
+The following code produces this diagnostic because `x` has the static type
+`int`:
+
+{% prettify dart %}
+void f(int x) {
+  if ([!x!]) {
+    // ...
+  }
+}
+{% endprettify %}
+
+#### Common fixes
+
+Change the condition so that it produces a Boolean value:
+
+{% prettify dart %}
+void f(int x) {
+  if (x == 0) {
+    // ...
+  }
+}
+{% endprettify %}
+
 ### non_constant_case_expression
 
 _Case expressions must be constant._
@@ -1443,7 +2527,7 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because `j` isn't a constant:
 
 {% prettify dart %}
 void f(int i, int j) {
@@ -1468,6 +2552,47 @@
 }
 {% endprettify %}
 
+### non_constant_default_value
+
+_The default value of an optional parameter must be constant._
+
+#### Description
+
+The analyzer produces this diagnostic when an optional parameter, either
+named or positional, has a default value that isn't a compile-time
+constant.
+
+#### Example
+
+The following code produces this diagnostic:
+
+{% prettify dart %}
+var defaultValue = 3;
+
+void f([int value = [!defaultValue!]]) {}
+{% endprettify %}
+
+#### Common fixes
+
+If the default value can be converted to be a constant, then convert it:
+
+{% prettify dart %}
+const defaultValue = 3;
+
+void f([int value = defaultValue]) {}
+{% endprettify %}
+
+If the default value needs to change over time, then apply the default
+value inside the function:
+
+{% prettify dart %}
+var defaultValue = 3;
+
+void f([int value]) {
+  value ??= defaultValue;
+}
+{% endprettify %}
+
 ### non_constant_list_element
 
 _The values in a const list literal must be constants._
@@ -1567,7 +2692,7 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic beause `a` isn't a constant:
 
 {% prettify dart %}
 var a = 'a';
@@ -1602,7 +2727,7 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because `a` isn't a constant:
 
 {% prettify dart %}
 var a = 'a';
@@ -1626,6 +2751,52 @@
 var m = {0: a};
 {% endprettify %}
 
+### non_const_call_to_literal_constructor
+
+_This instance creation must be 'const', because the {0} constructor is marked
+as '@literal'._
+
+_This instance creation must be 'const', because the {0} constructor is marked
+as '@literal'._
+
+#### Description
+
+The analyzer produces this diagnostic when a constructor that has the
+`@literal` annotation is invoked without using the `const` keyword, but all
+of the arguments to the constructor are constants. The annotation indicates
+that the constructor should be used to create a constant value whenever
+possible.
+
+#### Example
+
+The following code produces this diagnostic:
+
+{% prettify dart %}
+import 'package:meta/meta.dart';
+
+class C {
+  @literal
+  const C();
+}
+
+C f() => [!C()!];
+{% endprettify %}
+
+#### Common fixes
+
+Add the keyword `const` before the constructor invocation:
+
+{% prettify dart %}
+import 'package:meta/meta.dart';
+
+class C {
+  @literal
+  const C();
+}
+
+void f() => const C();
+{% endprettify %}
+
 ### non_type_as_type_argument
 
 _The name '{0}' isn't a type so it can't be used as a type argument._
@@ -1688,7 +2859,8 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because `f` declares two
+required parameters, but only one argument is provided:
 
 {% prettify dart %}
 void f(int a, int b) {}
@@ -1749,7 +2921,7 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because `l` isn't a `Map`:
 
 {% prettify dart %}
 var l =  <String>['a', 'b'];
@@ -1766,6 +2938,51 @@
 var m = <int, String>{...l.asMap()};
 {% endprettify %}
 
+### override_on_non_overriding_member
+
+_The field doesn't override an inherited getter or setter._
+
+_The getter doesn't override an inherited getter._
+
+_The method doesn't override an inherited method._
+
+_The setter doesn't override an inherited setter._
+
+#### Description
+
+The analyzer produces this diagnostic when a class member is annotated with
+the `@override` annotation, but the member isn’t declared in any of the
+supertypes of the class.
+
+#### Example
+
+The following code produces this diagnostic because `m` isn't declared in
+any of the supertypes of `C`:
+
+{% prettify dart %}
+class C {
+  @override
+  String [!m!]() => '';
+}
+{% endprettify %}
+
+#### Common fixes
+
+If the member is intended to override a member with a different name, then
+update the member to have the same name:
+
+{% prettify dart %}
+class C {
+  @override
+  String toString() => '';
+}
+{% endprettify %}
+
+If the member is intended to override a member that was removed from the
+superclass, then consider removing the member from the subclass.
+
+If the member can't be removed, then remove the annotation.
+
 ### redirect_to_non_class
 
 _The name '{0}' isn't a type and can't be used in a redirected constructor._
@@ -1824,7 +3041,8 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because `i` is used before it
+is declared:
 
 {% prettify dart %}
 void f() {
@@ -1857,6 +3075,43 @@
 }
 {% endprettify %}
 
+### return_of_invalid_type
+
+_A value of type '{0} can't be returned from function '{2}' because it has a
+return type of '{1}'._
+
+_A value of type '{0} can't be returned from method '{2}' because it has a
+return type of '{1}'._
+
+#### Description
+
+The analyzer produces this diagnostic when a method or function returns a
+value whose type isn't assignable to the declared return type.
+
+#### Example
+
+The following code produces this diagnostic because `f` has a return type
+of `String` but is returning an `int`:
+
+{% prettify dart %}
+String f() => [!3!];
+{% endprettify %}
+
+#### Common fixes
+
+If the return type is correct, then replace the value being returned with a
+value of the correct type, possibly by converting the existing value:
+
+{% prettify dart %}
+String f() => 3.toString();
+{% endprettify %}
+
+If the value is correct, then change the return type to match:
+
+{% prettify dart %}
+int f() => 3;
+{% endprettify %}
+
 ### sdk_version_async_exported_from_core
 
 _The class '{0}' wasn't exported from 'dart:core' until version 2.1, but this
@@ -2344,7 +3599,8 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because `super` can't be used
+in an extension:
 
 {% prettify dart %}
 extension E on Object {
@@ -2373,7 +3629,8 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because `String` isn't a
+subclass of `num`:
 
 {% prettify dart %}
 class A<E extends num> {}
@@ -2402,7 +3659,8 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because the name `Srting` isn't
+defined:
 
 {% prettify dart %}
 void f(Object o) {
@@ -2435,7 +3693,8 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because the name `undefined`
+isn't defined:
 
 {% prettify dart %}
 [!@undefined!]
@@ -2475,7 +3734,7 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because `Piont` isn't defined:
 
 {% prettify dart %}
 class Point {}
@@ -2791,7 +4050,8 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because the name `emty` isn't
+defined:
 
 {% prettify dart %}
 List<int> empty() => [];
@@ -2830,7 +4090,8 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because `String` has no member
+named `len`:
 
 {% prettify dart %}
 int f(String s) => s.[!len!];
@@ -2858,7 +4119,8 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because the name `rihgt` isn't
+defined:
 
 {% prettify dart %}
 int min(int left, int right) => left <= [!rihgt!] ? left : right;
@@ -2889,7 +4151,8 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because the identifier
+`removeMiddle` isn't defined:
 
 {% prettify dart %}
 int f(List<int> l) => l.[!removeMiddle!]();
@@ -2917,7 +4180,8 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because `m` doesn't declare a
+named parameter named `a`:
 
 {% prettify dart %}
 class C {
@@ -2973,6 +4237,38 @@
 }
 {% endprettify %}
 
+### undefined_operator
+
+_The operator '{0}' isn't defined for the class '{1}'._
+
+#### Description
+
+The analyzer produces this diagnostic when a user-definable operator is
+invoked on an object for which the operator isn't defined.
+
+#### Example
+
+The following code produces this diagnostic because the class `C` doesn't
+define the operator `+`:
+
+{% prettify dart %}
+class C {}
+
+C f(C c) => c [!+!] 2;
+{% endprettify %}
+
+#### Common fixes
+
+If the operator should be defined for the class, then define it:
+
+{% prettify dart %}
+class C {
+  C operator +(int i) => this;
+}
+
+C f(C c) => c + 2;
+{% endprettify %}
+
 ### undefined_prefixed_name
 
 _The name '{0}' is being referenced through the prefix '{1}', but it isn't
@@ -2986,7 +4282,8 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because `dart:core` doesn't
+define anything named `a`:
 
 {% prettify dart %}
 import 'dart:core' as p;
@@ -3016,7 +4313,8 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because there isn't a setter
+named `z`:
 
 {% prettify dart %}
 class C {
@@ -3054,7 +4352,8 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because `Object` doesn't define
+a member named `n`:
 
 {% prettify dart %}
 class C {
@@ -3088,7 +4387,8 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because `m` is a static member
+of the extended type `C`:
 
 {% prettify dart %}
 class C {
@@ -3172,7 +4472,8 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because `_x` isn't referenced
+anywhere in the library:
 
 {% prettify dart %}
 class Point {
@@ -3198,7 +4499,8 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because nothing defined in
+`dart:async` is referenced in the library:
 
 {% prettify dart %}
 import [!'dart:async'!];
@@ -3224,7 +4526,8 @@
 
 #### Example
 
-The following code produces this diagnostic:
+The following code produces this diagnostic because the value of `count` is
+never read:
 
 {% prettify dart %}
 void main() {
@@ -3295,3 +4598,66 @@
 
 If the file isn't a generated file, then check the spelling of the URI or
 create the file.
+
+### wrong_number_of_parameters_for_operator
+
+_Operator '{0}' should declare exactly {1} parameters, but {2} found._
+
+#### Description
+
+The analyzer produces this diagnostic when a declaration of an operator has
+the wrong number of parameters.
+
+#### Example
+
+The following code produces this diagnostic because the operator `+` must
+have a single parameter corresponding to the right operand:
+
+{% prettify dart %}
+class C {
+  int operator [!+!](a, b) => 0;
+}
+{% endprettify %}
+
+#### Common fixes
+
+Add or remove parameters to match the required number:
+
+{% prettify dart %}
+class C {
+  int operator +(a) => 0;
+}
+{% endprettify %}
+
+### wrong_number_of_type_arguments
+
+_The type '{0}' is declared with {1} type parameters, but {2} type arguments
+were given._
+
+#### Description
+
+The analyzer produces this diagnostic when a type that has type parameters
+is used and type arguments are provided, but the number of type arguments
+isn't the same as the number of type parameters.
+
+#### Example
+
+The following code produces this diagnostic because `C` has one type
+parameter but two type arguments are provided:
+
+{% prettify dart %}
+class C<E> {}
+
+void f([!C<int, int>!] x) {}
+{% endprettify %}
+
+#### Common fixes
+
+Add or remove type arguments, as necessary, to match the number of type
+parameters defined for the type:
+
+{% prettify dart %}
+class C<E> {}
+
+void f(C<int> x) {}
+{% endprettify %}
diff --git a/pkg/analyzer/tool/diagnostics/generate.dart b/pkg/analyzer/tool/diagnostics/generate.dart
index 580c05d..17ffb98 100644
--- a/pkg/analyzer/tool/diagnostics/generate.dart
+++ b/pkg/analyzer/tool/diagnostics/generate.dart
@@ -163,12 +163,6 @@
     _writeDiagnostics(sink);
   }
 
-  /// Return a version of the [text] in which characters that have special
-  /// meaning in markdown have been escaped.
-  String _escape(String text) {
-    return text.replaceAll('_', '\\_');
-  }
-
   /// Extract documentation from all of the files containing the definitions of
   /// diagnostics.
   void _extractAllDocs() {
diff --git a/pkg/analyzer/tool/messages/generate.dart b/pkg/analyzer/tool/messages/generate.dart
index 176b649..0566bdf 100644
--- a/pkg/analyzer/tool/messages/generate.dart
+++ b/pkg/analyzer/tool/messages/generate.dart
@@ -26,6 +26,8 @@
 main() async {
   String analyzerPkgPath = normalize(join(pkg_root.packageRoot, 'analyzer'));
   String frontEndPkgPath = normalize(join(pkg_root.packageRoot, 'front_end'));
+  String frontEndSharedPkgPath =
+      normalize(join(pkg_root.packageRoot, '_fe_analyzer_shared'));
 
   Map<dynamic, dynamic> messagesYaml = loadYaml(
       new File(join(frontEndPkgPath, 'messages.yaml')).readAsStringSync());
@@ -35,8 +37,8 @@
   String syntacticErrorsSource = new File(join(analyzerPkgPath,
           joinAll(posix.split('lib/src/dart/error/syntactic_errors.dart'))))
       .readAsStringSync();
-  String parserSource = new File(join(frontEndPkgPath,
-          joinAll(posix.split('lib/src/fasta/parser/parser.dart'))))
+  String parserSource = new File(join(frontEndSharedPkgPath,
+          joinAll(posix.split('lib/src/parser/parser.dart'))))
       .readAsStringSync();
 
   final codeGenerator = new _SyntacticErrorGenerator(
diff --git a/pkg/analyzer_cli/lib/src/build_mode.dart b/pkg/analyzer_cli/lib/src/build_mode.dart
index 8c70966..12601f9 100644
--- a/pkg/analyzer_cli/lib/src/build_mode.dart
+++ b/pkg/analyzer_cli/lib/src/build_mode.dart
@@ -11,12 +11,12 @@
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/error/error.dart';
 import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/src/context/context.dart';
 import 'package:analyzer/src/dart/analysis/byte_store.dart';
 import 'package:analyzer/src/dart/analysis/cache.dart';
 import 'package:analyzer/src/dart/analysis/driver.dart';
 import 'package:analyzer/src/dart/analysis/file_state.dart';
 import 'package:analyzer/src/dart/analysis/performance_logger.dart';
-import 'package:analyzer/src/dart/analysis/restricted_analysis_context.dart';
 import 'package:analyzer/src/dart/analysis/session.dart';
 import 'package:analyzer/src/dart/sdk/sdk.dart';
 import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl;
@@ -471,7 +471,7 @@
   }
 
   void _createLinkedElementFactory() {
-    var analysisContext = RestrictedAnalysisContext(
+    var analysisContext = AnalysisContextImpl(
       SynchronousSession(analysisOptions, declaredVariables),
       sourceFactory,
     );
diff --git a/pkg/analyzer_cli/test/options_test.dart b/pkg/analyzer_cli/test/options_test.dart
index 3356456..7ebd969 100644
--- a/pkg/analyzer_cli/test/options_test.dart
+++ b/pkg/analyzer_cli/test/options_test.dart
@@ -15,7 +15,6 @@
 main() {
   group('CommandLineOptions', () {
     group('parse', () {
-      int lastExitHandlerCode;
       StringBuffer outStringBuffer = new StringBuffer();
       StringBuffer errorStringBuffer = new StringBuffer();
 
@@ -28,9 +27,7 @@
         savedErrorSink = errorSink;
         savedExitHandler = exitHandler;
         savedExitCode = exitCode;
-        exitHandler = (int code) {
-          lastExitHandlerCode = code;
-        };
+        exitHandler = (int code) {};
         outSink = outStringBuffer;
         errorSink = errorStringBuffer;
       });
diff --git a/pkg/analyzer_plugin/lib/src/utilities/visitors/local_declaration_visitor.dart b/pkg/analyzer_plugin/lib/src/utilities/visitors/local_declaration_visitor.dart
index d0a3556..2b320e8 100644
--- a/pkg/analyzer_plugin/lib/src/utilities/visitors/local_declaration_visitor.dart
+++ b/pkg/analyzer_plugin/lib/src/utilities/visitors/local_declaration_visitor.dart
@@ -155,20 +155,8 @@
   visitForStatement(ForStatement node) {
     var forLoopParts = node.forLoopParts;
     if (forLoopParts is ForEachPartsWithDeclaration) {
-      DeclaredIdentifier loopVar = forLoopParts.loopVariable;
-      if (loopVar != null) {
-        SimpleIdentifier id = loopVar.identifier;
-        if (id != null) {
-          // If there is no loop variable, don't declare it.
-          declaredLocalVar(id, loopVar.type);
-        }
-      }
-    } else if (forLoopParts is ForEachPartsWithIdentifier) {
-      SimpleIdentifier id = forLoopParts.identifier;
-      if (id != null) {
-        // If there is no loop variable, don't declare it.
-        declaredLocalVar(id, null);
-      }
+      DeclaredIdentifier loopVariable = forLoopParts.loopVariable;
+      declaredLocalVar(loopVariable.identifier, loopVariable.type);
     } else if (forLoopParts is ForPartsWithDeclarations) {
       VariableDeclarationList varList = forLoopParts.variables;
       if (varList != null) {
diff --git a/pkg/analyzer_plugin/lib/utilities/completion/type_member_contributor.dart b/pkg/analyzer_plugin/lib/utilities/completion/type_member_contributor.dart
index cf31db3..1b2a9d3 100644
--- a/pkg/analyzer_plugin/lib/utilities/completion/type_member_contributor.dart
+++ b/pkg/analyzer_plugin/lib/utilities/completion/type_member_contributor.dart
@@ -246,7 +246,7 @@
   @override
   void declaredGenericTypeAlias(GenericTypeAlias declaration) {
     if (declaration.name.name == targetName) {
-      TypeAnnotation typeName = declaration.functionType.returnType;
+      TypeAnnotation typeName = declaration.functionType?.returnType;
       if (typeName != null) {
         typeFound = typeName.type;
       }
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 64cba71..37ce297 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
@@ -10,7 +10,6 @@
 import 'package:analyzer/dart/element/nullability_suffix.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
-import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/test_utilities/find_node.dart';
 import 'package:analyzer_plugin/protocol/protocol_common.dart';
@@ -2831,8 +2830,7 @@
       nullabilitySuffix: NullabilitySuffix.star,
     );
 
-    TypeSystem typeSystem = await session.typeSystem;
-    var inherited = new InheritanceManager3(typeSystem).getInherited(
+    var inherited = new InheritanceManager3().getInherited(
       targetType,
       new Name(null, nameToOverride),
     );
diff --git a/pkg/analyzer_plugin/test/utilities/completion/type_member_contributor_test.dart b/pkg/analyzer_plugin/test/utilities/completion/type_member_contributor_test.dart
index 08ba2a4..194ea25 100644
--- a/pkg/analyzer_plugin/test/utilities/completion/type_member_contributor_test.dart
+++ b/pkg/analyzer_plugin/test/utilities/completion/type_member_contributor_test.dart
@@ -2070,6 +2070,14 @@
     expect(suggestion.element.parameters, '(int value)');
   }
 
+  test_genericTypeAlias_noFunctionType() async {
+    addTestSource('''
+typedef F=;
+g(F.^
+''');
+    await computeSuggestions();
+  }
+
   test_IfStatement() async {
     // SimpleIdentifier  IfStatement
     addTestSource('''
diff --git a/pkg/compiler/lib/src/constants/expressions.dart b/pkg/compiler/lib/src/constants/expressions.dart
index 095bec3..0a6c24b 100644
--- a/pkg/compiler/lib/src/constants/expressions.dart
+++ b/pkg/compiler/lib/src/constants/expressions.dart
@@ -847,7 +847,7 @@
   final String name;
 
   TypeConstantExpression(this.type, this.name) {
-    assert(type.isInterfaceType || type.isTypedef || type.isDynamic,
+    assert(type is InterfaceType || type is TypedefType || type is DynamicType,
         "Unexpected type constant type: $type");
   }
 
diff --git a/pkg/compiler/lib/src/deferred_load.dart b/pkg/compiler/lib/src/deferred_load.dart
index 1c392c8..0276634 100644
--- a/pkg/compiler/lib/src/deferred_load.dart
+++ b/pkg/compiler/lib/src/deferred_load.dart
@@ -317,7 +317,7 @@
           DartType type = typeUse.type;
           switch (typeUse.kind) {
             case TypeUseKind.TYPE_LITERAL:
-              if (type.isInterfaceType) {
+              if (type is InterfaceType) {
                 InterfaceType interface = type;
                 dependencies.addClass(
                     interface.element, typeUse.deferredImport);
@@ -1659,12 +1659,27 @@
   }
 
   @override
+  void visitLegacyType(LegacyType type, Null argument) {
+    visit(type.baseType);
+  }
+
+  @override
+  void visitNullableType(NullableType type, Null argument) {
+    visit(type.baseType);
+  }
+
+  @override
   void visitFutureOrType(FutureOrType type, Null argument) {
     _dependencies.addClass(_commonElements.futureClass);
     visit(type.typeArgument);
   }
 
   @override
+  void visitNeverType(NeverType type, Null argument) {
+    // Nothing to add.
+  }
+
+  @override
   void visitDynamicType(DynamicType type, Null argument) {
     // Nothing to add.
   }
diff --git a/pkg/compiler/lib/src/elements/types.dart b/pkg/compiler/lib/src/elements/types.dart
index ee278b1..a5cee44 100644
--- a/pkg/compiler/lib/src/elements/types.dart
+++ b/pkg/compiler/lib/src/elements/types.dart
@@ -36,6 +36,7 @@
   DartType get unaliased => this;
 
   /// Is `true` if this type is a top type.
+  // TODO(fishythefish): Update this for normalization.
   bool get isTop => false;
 
   /// Is `true` if this type has no non-dynamic type arguments.
@@ -44,39 +45,6 @@
   /// Is `true` if this type should be treated as the dynamic type.
   bool get treatAsDynamic => false;
 
-  /// Is `true` if this type is the dynamic type.
-  bool get isDynamic => false;
-
-  /// Is `true` if this type is an erased type.
-  bool get isErased => false;
-
-  /// Is `true` if this type is the any type.
-  bool get isAny => false;
-
-  /// Is `true` if this type is the void type.
-  bool get isVoid => false;
-
-  /// Is `true` if this type is an interface type.
-  bool get isInterfaceType => false;
-
-  /// Is `true` if this type is a typedef.
-  bool get isTypedef => false;
-
-  /// Is `true` if this type is a function type.
-  bool get isFunctionType => false;
-
-  /// Is `true` if this type is a type variable.
-  bool get isTypeVariable => false;
-
-  /// Is `true` if this type is a type variable declared on a function type
-  ///
-  /// For instance `T` in
-  ///     void Function<T>(T t)
-  bool get isFunctionTypeVariable => false;
-
-  /// Is `true` if this type is a `FutureOr` type.
-  bool get isFutureOr => false;
-
   /// Whether this type contains a type variable.
   bool get containsTypeVariables => false;
 
@@ -176,6 +144,82 @@
   }
 }
 
+class LegacyType extends DartType {
+  final DartType baseType;
+
+  LegacyType(this.baseType);
+
+  @override
+  bool get containsTypeVariables => baseType.containsTypeVariables;
+
+  @override
+  void forEachTypeVariable(f(TypeVariableType variable)) {
+    baseType.forEachTypeVariable(f);
+  }
+
+  @override
+  R accept<R, A>(DartTypeVisitor<R, A> visitor, A argument) =>
+      visitor.visitLegacyType(this, argument);
+
+  @override
+  int get hashCode => baseType.hashCode * 31;
+
+  @override
+  bool operator ==(other) {
+    if (identical(this, other)) return true;
+    if (other is! LegacyType) return false;
+    return _equalsInternal(other, null);
+  }
+
+  @override
+  bool _equals(DartType other, _Assumptions assumptions) {
+    if (identical(this, other)) return true;
+    if (other is! LegacyType) return false;
+    return _equalsInternal(other, assumptions);
+  }
+
+  bool _equalsInternal(LegacyType other, _Assumptions assumptions) =>
+      baseType._equals(other.baseType, assumptions);
+}
+
+class NullableType extends DartType {
+  final DartType baseType;
+
+  NullableType(this.baseType);
+
+  @override
+  bool get containsTypeVariables => baseType.containsTypeVariables;
+
+  @override
+  void forEachTypeVariable(f(TypeVariableType variable)) {
+    baseType.forEachTypeVariable(f);
+  }
+
+  @override
+  R accept<R, A>(DartTypeVisitor<R, A> visitor, A argument) =>
+      visitor.visitNullableType(this, argument);
+
+  @override
+  int get hashCode => baseType.hashCode * 37;
+
+  @override
+  bool operator ==(other) {
+    if (identical(this, other)) return true;
+    if (other is! NullableType) return false;
+    return _equalsInternal(other, null);
+  }
+
+  @override
+  bool _equals(DartType other, _Assumptions assumptions) {
+    if (identical(this, other)) return true;
+    if (other is! NullableType) return false;
+    return _equalsInternal(other, assumptions);
+  }
+
+  bool _equalsInternal(NullableType other, _Assumptions assumptions) =>
+      baseType._equals(other.baseType, assumptions);
+}
+
 class InterfaceType extends DartType {
   final ClassEntity element;
   final List<DartType> typeArguments;
@@ -187,9 +231,6 @@
   bool get isTop => isObject;
 
   @override
-  bool get isInterfaceType => true;
-
-  @override
   bool get isObject {
     return element.name == 'Object' &&
         element.library.canonicalUri == Uris.dart_core;
@@ -258,9 +299,6 @@
   bool get isTop => unaliased.isTop;
 
   @override
-  bool get isTypedef => true;
-
-  @override
   bool get containsTypeVariables =>
       typeArguments.any((type) => type.containsTypeVariables);
 
@@ -317,9 +355,6 @@
   TypeVariableType(this.element);
 
   @override
-  bool get isTypeVariable => true;
-
-  @override
   bool get containsTypeVariables => true;
 
   @override
@@ -379,9 +414,6 @@
   }
 
   @override
-  bool get isFunctionTypeVariable => true;
-
-  @override
   int get hashCode => index.hashCode * 19;
 
   @override
@@ -404,6 +436,23 @@
       visitor.visitFunctionTypeVariable(this, argument);
 }
 
+class NeverType extends DartType {
+  const NeverType._();
+
+  factory NeverType() => const NeverType._();
+
+  @override
+  R accept<R, A>(DartTypeVisitor<R, A> visitor, A argument) =>
+      visitor.visitNeverType(this, argument);
+
+  @override
+  int get hashCode => 41;
+
+  @override
+  bool _equals(DartType other, _Assumptions assumptions) =>
+      identical(this, other);
+}
+
 class VoidType extends DartType {
   const VoidType._();
 
@@ -413,9 +462,6 @@
   bool get isTop => true;
 
   @override
-  bool get isVoid => true;
-
-  @override
   R accept<R, A>(DartTypeVisitor<R, A> visitor, A argument) =>
       visitor.visitVoidType(this, argument);
 
@@ -437,9 +483,6 @@
   bool get isTop => true;
 
   @override
-  bool get isDynamic => true;
-
-  @override
   bool get treatAsDynamic => true;
 
   @override
@@ -467,9 +510,6 @@
   bool get treatAsDynamic => true;
 
   @override
-  bool get isErased => true;
-
-  @override
   R accept<R, A>(DartTypeVisitor<R, A> visitor, A argument) =>
       visitor.visitErasedType(this, argument);
 
@@ -501,9 +541,6 @@
   bool get isTop => true;
 
   @override
-  bool get isAny => true;
-
-  @override
   R accept<R, A>(DartTypeVisitor<R, A> visitor, A argument) =>
       visitor.visitAnyType(this, argument);
 
@@ -565,9 +602,6 @@
     namedParameterTypes.forEach((type) => type.forEachTypeVariable(f));
   }
 
-  @override
-  bool get isFunctionType => true;
-
   FunctionType instantiate(List<DartType> arguments) {
     return subst(arguments, typeVariables);
   }
@@ -648,9 +682,6 @@
   bool get isTop => typeArgument.isTop;
 
   @override
-  bool get isFutureOr => true;
-
-  @override
   bool get containsTypeVariables => typeArgument.containsTypeVariables;
 
   @override
@@ -699,6 +730,12 @@
 
   R visit(covariant DartType type, A argument) => type.accept(this, argument);
 
+  R visitLegacyType(covariant LegacyType type, A argument) => null;
+
+  R visitNullableType(covariant NullableType type, A argument) => null;
+
+  R visitNeverType(covariant NeverType type, A argument) => null;
+
   R visitVoidType(covariant VoidType type, A argument) => null;
 
   R visitTypeVariableType(covariant TypeVariableType type, A argument) => null;
@@ -728,6 +765,18 @@
   R visitType(covariant DartType type, A argument);
 
   @override
+  R visitLegacyType(covariant LegacyType type, A argument) =>
+      visitType(type, argument);
+
+  @override
+  R visitNullableType(covariant NullableType type, A argument) =>
+      visitType(type, argument);
+
+  @override
+  R visitNeverType(covariant NeverType type, A argument) =>
+      visitType(type, argument);
+
+  @override
   R visitVoidType(covariant VoidType type, A argument) =>
       visitType(type, argument);
 
@@ -794,6 +843,35 @@
       type;
 
   @override
+  DartType visitLegacyType(covariant LegacyType type, A argument) {
+    DartType probe = _map[type];
+    if (probe != null) return probe;
+
+    DartType newBaseType = visit(type.baseType, argument);
+    // Create a new type only if necessary.
+    if (identical(type.baseType, newBaseType)) {
+      return _mapped(type, type);
+    }
+    return _mapped(type, LegacyType(newBaseType));
+  }
+
+  @override
+  DartType visitNullableType(covariant NullableType type, A argument) {
+    DartType probe = _map[type];
+    if (probe != null) return probe;
+
+    DartType newBaseType = visit(type.baseType, argument);
+    // Create a new type only if necessary.
+    if (identical(type.baseType, newBaseType)) {
+      return _mapped(type, type);
+    }
+    return _mapped(type, NullableType(newBaseType));
+  }
+
+  @override
+  DartType visitNeverType(covariant NeverType type, A argument) => type;
+
+  @override
   DartType visitTypeVariableType(covariant TypeVariableType type, A argument) {
     return substituteTypeVariableType(type, argument, true);
   }
@@ -803,8 +881,8 @@
       covariant FunctionTypeVariable type, A argument) {
     // Function type variables are added to the map only for type variables that
     // need to be replaced with updated bounds.
-    DartType seen = _map[type];
-    if (seen != null) return seen;
+    DartType probe = _map[type];
+    if (probe != null) return probe;
     return substituteFunctionTypeVariable(type, argument, true);
   }
 
@@ -813,8 +891,8 @@
 
   @override
   DartType visitFunctionType(covariant FunctionType type, A argument) {
-    DartType seen = _map[type];
-    if (seen != null) return seen;
+    DartType probe = _map[type];
+    if (probe != null) return probe;
 
     List<FunctionTypeVariable> newTypeVariables =
         _handleFunctionTypeVariables(type.typeVariables, argument);
@@ -919,8 +997,8 @@
       return type;
     }
 
-    DartType seen = _map[type];
-    if (seen != null) return seen;
+    DartType probe = _map[type];
+    if (probe != null) return probe;
 
     List<DartType> newTypeArguments = _substTypes(typeArguments, argument);
     // Create a new type only if necessary.
@@ -932,8 +1010,8 @@
 
   @override
   DartType visitTypedefType(covariant TypedefType type, A argument) {
-    DartType seen = _map[type];
-    if (seen != null) return seen;
+    DartType probe = _map[type];
+    if (probe != null) return probe;
 
     List<DartType> newTypeArguments = _substTypes(type.typeArguments, argument);
     FunctionType newUnaliased = visit(type.unaliased, argument);
@@ -957,8 +1035,8 @@
 
   @override
   DartType visitFutureOrType(covariant FutureOrType type, A argument) {
-    DartType seen = _map[type];
-    if (seen != null) return seen;
+    DartType probe = _map[type];
+    if (probe != null) return probe;
 
     DartType newTypeArgument = visit(type.typeArgument, argument);
     // Create a new type only if necessary.
@@ -998,8 +1076,8 @@
   bool handleFreeFunctionTypeVariable(FunctionTypeVariable type) {
     // Function type variables are added to the map for type variables that need
     // to be replaced with updated bounds.
-    DartType seen = _substitutionVisitor._map[type];
-    if (seen != null) return seen != type;
+    DartType probe = _substitutionVisitor._map[type];
+    if (probe != null) return probe != type;
     return !identical(
         type,
         _substitutionVisitor.substituteFunctionTypeVariable(
@@ -1008,7 +1086,7 @@
 }
 
 /// A visitor that by default visits the substructure of the type until some
-/// visit returns `true`.  The default handers return `false` which will search
+/// visit returns `true`.  The default handlers return `false` which will search
 /// the whole structure unless overridden.
 abstract class DartTypeStructuralPredicateVisitor
     extends DartTypeVisitor<bool, List<FunctionTypeVariable>> {
@@ -1016,6 +1094,9 @@
 
   bool run(DartType type) => visit(type, null);
 
+  bool handleLegacyType(LegacyType type) => false;
+  bool handleNullableType(NullableType type) => false;
+  bool handleNeverType(NeverType type) => false;
   bool handleVoidType(VoidType type) => false;
   bool handleTypeVariableType(TypeVariableType type) => false;
   bool handleBoundFunctionTypeVariable(FunctionTypeVariable type) => false;
@@ -1029,6 +1110,19 @@
   bool handleFutureOrType(FutureOrType type) => false;
 
   @override
+  bool visitLegacyType(LegacyType type, List<FunctionTypeVariable> bindings) =>
+      handleLegacyType(type) || visit(type.baseType, bindings);
+
+  @override
+  bool visitNullableType(
+          NullableType type, List<FunctionTypeVariable> bindings) =>
+      handleNullableType(type) || visit(type.baseType, bindings);
+
+  @override
+  bool visitNeverType(NeverType type, List<FunctionTypeVariable> bindings) =>
+      false;
+
+  @override
   bool visitVoidType(VoidType type, List<FunctionTypeVariable> bindings) =>
       handleVoidType(type);
 
@@ -1219,6 +1313,23 @@
   }
 
   @override
+  void visitLegacyType(covariant LegacyType type, _) {
+    _visit(type.baseType);
+    _token('*');
+  }
+
+  @override
+  void visitNullableType(covariant NullableType type, _) {
+    _visit(type.baseType);
+    _token('?');
+  }
+
+  @override
+  void visitNeverType(covariant NeverType type, _) {
+    _identifier('Never');
+  }
+
+  @override
   void visitVoidType(covariant VoidType type, _) {
     _identifier('void');
   }
@@ -1365,6 +1476,8 @@
 }
 
 /// Abstract visitor for determining relations between types.
+// TODO(fishythefish): Rewrite type relations to support NNBD types and new
+// subtyping algorithm structure.
 abstract class AbstractTypeRelation<T extends DartType>
     extends BaseDartTypeVisitor<bool, T> {
   CommonElements get commonElements;
@@ -1573,11 +1686,11 @@
   bool visitTypeVariableType(TypeVariableType t, T s) {
     // Identity check is handled in [isSubtype].
     DartType bound = getTypeVariableBound(t.element);
-    if (bound.isTypeVariable) {
+    if (bound is TypeVariableType) {
       // The bound is potentially cyclic so we need to be extra careful.
       Set<TypeVariableEntity> seenTypeVariables = new Set<TypeVariableEntity>();
       seenTypeVariables.add(t.element);
-      while (bound.isTypeVariable) {
+      while (bound is TypeVariableType) {
         TypeVariableType typeVariable = bound;
         if (bound == s) {
           // [t] extends [s].
@@ -1599,7 +1712,7 @@
 
   @override
   bool visitFunctionTypeVariable(FunctionTypeVariable t, DartType s) {
-    if (!s.isFunctionTypeVariable) return false;
+    if (s is! FunctionTypeVariable) return false;
     return assumptions.isAssumed(t, s);
   }
 }
@@ -1608,10 +1721,10 @@
     extends AbstractTypeRelation<T> {
   bool isMoreSpecific(T t, T s) {
     if (identical(t, s) ||
-        t.isAny ||
-        s.isAny ||
+        t is AnyType ||
+        s is AnyType ||
         s.treatAsDynamic ||
-        s.isVoid ||
+        s is VoidType ||
         s == commonElements.objectType ||
         t == commonElements.nullType) {
       return true;
@@ -1633,8 +1746,8 @@
 
   @override
   bool invalidFunctionReturnTypes(T t, T s) {
-    if (s.treatAsDynamic && t.isVoid) return true;
-    return !s.isVoid && !isMoreSpecific(t, s);
+    if (s.treatAsDynamic && t is VoidType) return true;
+    return s is! VoidType && !isMoreSpecific(t, s);
   }
 
   @override
@@ -1662,12 +1775,12 @@
 abstract class SubtypeVisitor<T extends DartType>
     extends MoreSpecificVisitor<T> {
   bool isSubtype(DartType t, DartType s) {
-    if (t.isAny || s.isAny) return true;
-    if (s.isFutureOr) {
+    if (t is AnyType || s is AnyType) return true;
+    if (s is FutureOrType) {
       FutureOrType sFutureOr = s;
       if (isSubtype(t, sFutureOr.typeArgument)) {
         return true;
-      } else if (t.isInterfaceType) {
+      } else if (t is InterfaceType) {
         InterfaceType tInterface = t;
         if (tInterface.element == commonElements.futureClass &&
             isSubtype(
@@ -1710,7 +1823,7 @@
 
   @override
   bool visitFutureOrType(FutureOrType t, covariant DartType s) {
-    if (s.isFutureOr) {
+    if (s is FutureOrType) {
       FutureOrType sFutureOr = s;
       return isSubtype(t.typeArgument, sFutureOr.typeArgument);
     }
@@ -1727,7 +1840,7 @@
 
   @override
   bool isSubtype(DartType t, DartType s) {
-    if (t.isAny || s.isAny) return true;
+    if (t is AnyType || s is AnyType) return true;
     if (t is TypeVariableType || s is TypeVariableType) {
       return true;
     }
diff --git a/pkg/compiler/lib/src/inferrer/builder_kernel.dart b/pkg/compiler/lib/src/inferrer/builder_kernel.dart
index 4c49acb..48e3b92 100644
--- a/pkg/compiler/lib/src/inferrer/builder_kernel.dart
+++ b/pkg/compiler/lib/src/inferrer/builder_kernel.dart
@@ -1692,7 +1692,7 @@
       DartType type = node.guard != null
           ? _elementMap.getDartType(node.guard)
           : DynamicType();
-      if (type.isInterfaceType) {
+      if (type is InterfaceType) {
         InterfaceType interfaceType = type;
         mask = _types.nonNullSubtype(interfaceType.element);
       } else {
diff --git a/pkg/compiler/lib/src/inferrer/inferrer_engine.dart b/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
index a4accab..98c43b2 100644
--- a/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
+++ b/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
@@ -387,11 +387,11 @@
         mappedType = types.boolType;
       } else if (type == commonElements.nullType) {
         mappedType = types.nullType;
-      } else if (type.isVoid) {
+      } else if (type is VoidType) {
         mappedType = types.nullType;
-      } else if (type.isDynamic) {
+      } else if (type is DynamicType) {
         return types.dynamicType;
-      } else if (type.isInterfaceType) {
+      } else if (type is InterfaceType) {
         mappedType = types.nonNullSubtype(type.element);
       } else {
         mappedType = types.dynamicType;
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
index f674734..af0410d 100644
--- a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
+++ b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
@@ -2275,21 +2275,21 @@
   AbstractValue otherType;
   if (annotation.treatAsDynamic) {
     return type;
-  } else if (annotation.isInterfaceType) {
-    InterfaceType interfaceType = annotation;
-    if (interfaceType.element == closedWorld.commonElements.objectClass) {
+  } else if (annotation is InterfaceType) {
+    if (annotation.element == closedWorld.commonElements.objectClass) {
       return type;
     }
-    otherType = abstractValueDomain.createNonNullSubtype(interfaceType.element);
-  } else if (annotation.isVoid) {
+    otherType = abstractValueDomain.createNonNullSubtype(annotation.element);
+  } else if (annotation is VoidType) {
     return type;
-  } else if (annotation.isTypedef || annotation.isFunctionType) {
+  } else if (annotation is TypedefType || annotation is FunctionType) {
     otherType = closedWorld.abstractValueDomain.functionType;
-  } else if (annotation.isFutureOr) {
+  } else if (annotation is FutureOrType) {
     // TODO(johnniwinther): Narrow FutureOr types.
     return type;
   } else {
-    assert(annotation.isTypeVariable || annotation.isFunctionTypeVariable);
+    assert(
+        annotation is TypeVariableType || annotation is FunctionTypeVariable);
     // TODO(ngeoffray): Narrow to bound.
     return type;
   }
diff --git a/pkg/compiler/lib/src/inferrer/type_system.dart b/pkg/compiler/lib/src/inferrer/type_system.dart
index c5c32cf..2e05bac 100644
--- a/pkg/compiler/lib/src/inferrer/type_system.dart
+++ b/pkg/compiler/lib/src/inferrer/type_system.dart
@@ -318,14 +318,14 @@
   TypeInformation narrowType(TypeInformation type, DartType annotation,
       {bool isNullable: true}) {
     AbstractValue otherType;
-    if (annotation.isVoid) return type;
+    if (annotation is VoidType) return type;
     if (annotation.treatAsDynamic) {
       if (isNullable) return type;
       // If the input is already narrowed to be not-null, there is no value
       // in adding another narrowing node.
       if (_isNonNullNarrow(type)) return type;
       otherType = _abstractValueDomain.excludeNull(dynamicType.type);
-    } else if (annotation.isInterfaceType) {
+    } else if (annotation is InterfaceType) {
       InterfaceType interface = annotation;
       if (interface.element == _closedWorld.commonElements.objectClass) {
         if (isNullable) return type;
@@ -335,13 +335,13 @@
         otherType =
             _abstractValueDomain.createNonNullSubtype(interface.element);
       }
-    } else if (annotation.isTypedef || annotation.isFunctionType) {
+    } else if (annotation is TypedefType || annotation is FunctionType) {
       otherType = functionType.type;
-    } else if (annotation.isFutureOr) {
+    } else if (annotation is FutureOrType) {
       // TODO(johnniwinther): Support narrowing of FutureOr.
       return type;
     } else {
-      assert(annotation.isTypeVariable);
+      assert(annotation is TypeVariableType);
       // TODO(ngeoffray): Narrow to bound.
       return type;
     }
diff --git a/pkg/compiler/lib/src/ir/annotations.dart b/pkg/compiler/lib/src/ir/annotations.dart
index 4e10bf8..899b8d0 100644
--- a/pkg/compiler/lib/src/ir/annotations.dart
+++ b/pkg/compiler/lib/src/ir/annotations.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:kernel/ast.dart' as ir;
+import 'package:kernel/type_environment.dart' as ir;
 import '../common/names.dart';
 import 'modular.dart';
 
@@ -125,13 +126,15 @@
   IrAnnotationData data = new IrAnnotationData();
 
   void processMember(ir.Member member) {
+    ir.StaticTypeContext staticTypeContext = new ir.StaticTypeContext(
+        member, modularCore.constantEvaluator.typeEnvironment);
     List<PragmaAnnotationData> pragmaAnnotations;
     List<String> createsAnnotations;
     List<String> returnsAnnotations;
     for (ir.Expression annotation in member.annotations) {
       if (annotation is ir.ConstantExpression) {
-        ir.Constant constant =
-            modularCore.constantEvaluator.evaluate(annotation);
+        ir.Constant constant = modularCore.constantEvaluator
+            .evaluate(staticTypeContext, annotation);
 
         String jsName = _getJsInteropName(constant);
         if (jsName != null) {
@@ -176,10 +179,13 @@
   }
 
   for (ir.Library library in component.libraries) {
+    ir.StaticTypeContext staticTypeContext =
+        new ir.StaticTypeContext.forAnnotations(
+            library, modularCore.constantEvaluator.typeEnvironment);
     for (ir.Expression annotation in library.annotations) {
       if (annotation is ir.ConstantExpression) {
-        ir.Constant constant =
-            modularCore.constantEvaluator.evaluate(annotation);
+        ir.Constant constant = modularCore.constantEvaluator
+            .evaluate(staticTypeContext, annotation);
 
         String jsName = _getJsInteropName(constant);
         if (jsName != null) {
@@ -190,8 +196,8 @@
     for (ir.Class cls in library.classes) {
       for (ir.Expression annotation in cls.annotations) {
         if (annotation is ir.ConstantExpression) {
-          ir.Constant constant =
-              modularCore.constantEvaluator.evaluate(annotation);
+          ir.Constant constant = modularCore.constantEvaluator
+              .evaluate(staticTypeContext, annotation);
 
           String nativeClassName = _getNativeClassName(constant);
           if (nativeClassName != null) {
diff --git a/pkg/compiler/lib/src/ir/cached_static_type.dart b/pkg/compiler/lib/src/ir/cached_static_type.dart
index ea00634..efda170 100644
--- a/pkg/compiler/lib/src/ir/cached_static_type.dart
+++ b/pkg/compiler/lib/src/ir/cached_static_type.dart
@@ -17,11 +17,13 @@
   final StaticTypeCache _cache;
 
   @override
+  final ir.StaticTypeContext staticTypeContext;
+
+  @override
   final ThisInterfaceType thisType;
 
-  CachedStaticType(
-      ir.TypeEnvironment typeEnvironment, this._cache, this.thisType)
-      : super(typeEnvironment);
+  CachedStaticType(this.staticTypeContext, this._cache, this.thisType)
+      : super(staticTypeContext.typeEnvironment);
 
   @override
   ir.DartType getStaticType(ir.Expression node) {
diff --git a/pkg/compiler/lib/src/ir/constants.dart b/pkg/compiler/lib/src/ir/constants.dart
index 5235031..fd7b002 100644
--- a/pkg/compiler/lib/src/ir/constants.dart
+++ b/pkg/compiler/lib/src/ir/constants.dart
@@ -34,12 +34,15 @@
   ErrorReporter get errorReporter => super.errorReporter;
 
   @override
-  ir.Constant evaluate(ir.Expression node, {bool requireConstant: true}) {
+  ir.Constant evaluate(
+      ir.StaticTypeContext staticTypeContext, ir.Expression node,
+      {bool requireConstant: true}) {
     errorReporter.requiresConstant = requireConstant;
     if (node is ir.ConstantExpression) {
       ir.Constant constant = node.constant;
       if (constant is ir.UnevaluatedConstant) {
-        ir.Constant result = super.evaluate(constant.expression);
+        ir.Constant result =
+            super.evaluate(staticTypeContext, constant.expression);
         assert(
             result is ir.UnevaluatedConstant ||
                 !result.accept(const UnevaluatedConstantFinder()),
@@ -54,10 +57,10 @@
     if (requireConstant) {
       // TODO(johnniwinther): Handle reporting of compile-time constant
       // evaluation errors.
-      return super.evaluate(node);
+      return super.evaluate(staticTypeContext, node);
     } else {
       try {
-        return super.evaluate(node);
+        return super.evaluate(staticTypeContext, node);
       } catch (e) {
         return null;
       }
diff --git a/pkg/compiler/lib/src/ir/element_map.dart b/pkg/compiler/lib/src/ir/element_map.dart
index 250c391..09aecbe 100644
--- a/pkg/compiler/lib/src/ir/element_map.dart
+++ b/pkg/compiler/lib/src/ir/element_map.dart
@@ -59,6 +59,7 @@
 
   CommonElements get commonElements;
   DiagnosticReporter get reporter;
+  ir.CoreTypes get coreTypes;
   InterfaceType getThisType(IndexedClass cls);
   InterfaceType getSuperType(IndexedClass cls);
   OrderedTypeSet getOrderedTypeSet(IndexedClass cls);
diff --git a/pkg/compiler/lib/src/ir/impact.dart b/pkg/compiler/lib/src/ir/impact.dart
index 0954db8..8deb4c3 100644
--- a/pkg/compiler/lib/src/ir/impact.dart
+++ b/pkg/compiler/lib/src/ir/impact.dart
@@ -198,9 +198,12 @@
   @override
   final VariableScopeModel variableScopeModel;
 
-  ImpactBuilderBase(ir.TypeEnvironment typeEnvironment,
-      ir.ClassHierarchy classHierarchy, this.variableScopeModel)
-      : super(typeEnvironment, classHierarchy);
+  @override
+  final ir.StaticTypeContext staticTypeContext;
+
+  ImpactBuilderBase(this.staticTypeContext, ir.ClassHierarchy classHierarchy,
+      this.variableScopeModel)
+      : super(staticTypeContext.typeEnvironment, classHierarchy);
 
   @override
   void handleIntLiteral(ir.IntLiteral node) {
@@ -668,10 +671,10 @@
   @override
   final inferEffectivelyFinalVariableTypes;
 
-  ImpactBuilder(ir.TypeEnvironment typeEnvironment,
+  ImpactBuilder(ir.StaticTypeContext staticTypeContext,
       ir.ClassHierarchy classHierarchy, VariableScopeModel variableScopeModel,
       {this.useAsserts: false, this.inferEffectivelyFinalVariableTypes: true})
-      : super(typeEnvironment, classHierarchy, variableScopeModel);
+      : super(staticTypeContext, classHierarchy, variableScopeModel);
 
   ImpactBuilderData computeImpact(ir.Member node) {
     if (retainDataForTesting) {
diff --git a/pkg/compiler/lib/src/ir/scope_visitor.dart b/pkg/compiler/lib/src/ir/scope_visitor.dart
index 82402b7..21db425 100644
--- a/pkg/compiler/lib/src/ir/scope_visitor.dart
+++ b/pkg/compiler/lib/src/ir/scope_visitor.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:kernel/ast.dart' as ir;
+import 'package:kernel/type_environment.dart' as ir;
 import 'package:front_end/src/api_prototype/constant_evaluator.dart' as ir;
 
 import 'closure.dart';
@@ -15,6 +16,7 @@
 class ScopeModelBuilder extends ir.Visitor<InitializerComplexity>
     with VariableCollectorMixin {
   final ir.ConstantEvaluator _constantEvaluator;
+  ir.StaticTypeContext _staticTypeContext;
 
   final ClosureScopeModel _model = new ClosureScopeModel();
 
@@ -85,6 +87,8 @@
           initializerComplexity: const InitializerComplexity.lazy());
     }
 
+    _staticTypeContext =
+        new ir.StaticTypeContext(node, _constantEvaluator.typeEnvironment);
     if (node is ir.Constructor) {
       _hasThisLocal = true;
     } else if (node is ir.Procedure && node.kind == ir.ProcedureKind.Factory) {
@@ -1074,7 +1078,7 @@
   @override
   InitializerComplexity visitConstantExpression(ir.ConstantExpression node) {
     if (node.constant is ir.UnevaluatedConstant) {
-      node.constant = _constantEvaluator.evaluate(node);
+      node.constant = _constantEvaluator.evaluate(_staticTypeContext, node);
     }
     return const InitializerComplexity.constant();
   }
diff --git a/pkg/compiler/lib/src/ir/static_type.dart b/pkg/compiler/lib/src/ir/static_type.dart
index b54d98c..716567a 100644
--- a/pkg/compiler/lib/src/ir/static_type.dart
+++ b/pkg/compiler/lib/src/ir/static_type.dart
@@ -392,7 +392,9 @@
   ir.DartType _narrowInstanceReceiver(
       ir.Member interfaceTarget, ir.DartType receiverType) {
     if (interfaceTarget != null && receiverType == const ir.DynamicType()) {
-      receiverType = interfaceTarget.enclosingClass.thisType;
+      receiverType = interfaceTarget.enclosingClass.getThisType(
+          typeEnvironment.coreTypes,
+          interfaceTarget.enclosingLibrary.nonNullable);
     }
     return receiverType;
   }
@@ -1377,7 +1379,8 @@
 
   @override
   Null visitProcedure(ir.Procedure node) {
-    thisType = new ThisInterfaceType.from(node.enclosingClass?.thisType);
+    thisType = new ThisInterfaceType.from(node.enclosingClass?.getThisType(
+        typeEnvironment.coreTypes, node.enclosingLibrary.nonNullable));
     _currentVariables = {};
     visitSignature(node.function);
     visitNode(node.function.body);
@@ -1391,7 +1394,8 @@
 
   @override
   Null visitConstructor(ir.Constructor node) {
-    thisType = new ThisInterfaceType.from(node.enclosingClass.thisType);
+    thisType = new ThisInterfaceType.from(node.enclosingClass.getThisType(
+        typeEnvironment.coreTypes, node.enclosingLibrary.nonNullable));
     _currentVariables = {};
     visitSignature(node.function);
     visitNodes(node.initializers);
@@ -1406,7 +1410,8 @@
 
   @override
   Null visitField(ir.Field node) {
-    thisType = new ThisInterfaceType.from(node.enclosingClass?.thisType);
+    thisType = new ThisInterfaceType.from(node.enclosingClass?.getThisType(
+        typeEnvironment.coreTypes, node.enclosingLibrary.nonNullable));
     _currentVariables = {};
     visitNode(node.initializer);
     handleField(node);
diff --git a/pkg/compiler/lib/src/ir/static_type_base.dart b/pkg/compiler/lib/src/ir/static_type_base.dart
index f8f4999..7ad2078 100644
--- a/pkg/compiler/lib/src/ir/static_type_base.dart
+++ b/pkg/compiler/lib/src/ir/static_type_base.dart
@@ -65,6 +65,8 @@
 
   ir.TypeEnvironment get typeEnvironment => _typeEnvironment;
 
+  ir.StaticTypeContext get staticTypeContext;
+
   ThisInterfaceType get thisType;
 
   @override
@@ -131,17 +133,20 @@
 
   @override
   ir.DartType visitListLiteral(ir.ListLiteral node) {
-    return typeEnvironment.literalListType(node.typeArgument);
+    return typeEnvironment.literalListType(
+        node.typeArgument, ir.Nullability.legacy);
   }
 
   @override
   ir.DartType visitSetLiteral(ir.SetLiteral node) {
-    return typeEnvironment.literalSetType(node.typeArgument);
+    return typeEnvironment.literalSetType(
+        node.typeArgument, ir.Nullability.legacy);
   }
 
   @override
   ir.DartType visitMapLiteral(ir.MapLiteral node) {
-    return typeEnvironment.literalMapType(node.keyType, node.valueType);
+    return typeEnvironment.literalMapType(
+        node.keyType, node.valueType, ir.Nullability.legacy);
   }
 
   @override
@@ -225,12 +230,13 @@
 
   @override
   ir.DartType visitLoadLibrary(ir.LoadLibrary node) {
-    return typeEnvironment.futureType(const ir.DynamicType());
+    return typeEnvironment.futureType(
+        const ir.DynamicType(), ir.Nullability.legacy);
   }
 
   @override
   ir.DartType visitConstantExpression(ir.ConstantExpression node) {
     // TODO(johnniwinther): Include interface exactness where applicable.
-    return node.getStaticType(typeEnvironment);
+    return node.getStaticType(staticTypeContext);
   }
 }
diff --git a/pkg/compiler/lib/src/ir/visitors.dart b/pkg/compiler/lib/src/ir/visitors.dart
index ffd71e5..22374f1 100644
--- a/pkg/compiler/lib/src/ir/visitors.dart
+++ b/pkg/compiler/lib/src/ir/visitors.dart
@@ -258,11 +258,11 @@
   ConstantExpression visitTypeLiteral(ir.TypeLiteral node) {
     String name;
     DartType type = elementMap.getDartType(node.type);
-    if (type.isDynamic) {
+    if (type is DynamicType) {
       name = 'dynamic';
     } else if (type is InterfaceType) {
       name = type.element.name;
-    } else if (type.isTypedef) {
+    } else if (type is TypedefType) {
       // TODO(johnniwinther): Compute a name for the type literal? It is only
       // used in error messages in the old SSA builder.
       name = '?';
@@ -499,6 +499,8 @@
 
     ConstructedConstantExpression superConstructorInvocation;
     List<AssertConstantExpression> assertions = <AssertConstantExpression>[];
+    List<ir.DartType> parametersAsArguments = ir.getAsTypeArguments(
+        node.enclosingClass.typeParameters, node.enclosingLibrary);
     for (ir.Initializer initializer in node.initializers) {
       if (initializer is ir.FieldInitializer) {
         registerField(initializer.field, visit(initializer.value));
@@ -509,9 +511,7 @@
             initializer.arguments.types);
       } else if (initializer is ir.RedirectingInitializer) {
         superConstructorInvocation = _computeConstructorInvocation(
-            initializer.target,
-            initializer.arguments,
-            node.enclosingClass.thisType.typeArguments);
+            initializer.target, initializer.arguments, parametersAsArguments);
       } else if (initializer is ir.AssertInitializer) {
         ConstantExpression condition = visit(initializer.statement.condition);
         ConstantExpression message = initializer.statement.message != null
@@ -664,6 +664,7 @@
 
   @override
   DartType visitBottomType(ir.BottomType node) {
+    // TODO(fishythefish): Change `Null` to `Never` for NNBD.
     return elementMap.commonElements.nullType;
   }
 }
diff --git a/pkg/compiler/lib/src/js_backend/checked_mode_helpers.dart b/pkg/compiler/lib/src/js_backend/checked_mode_helpers.dart
index c577600..46b78b2 100644
--- a/pkg/compiler/lib/src/js_backend/checked_mode_helpers.dart
+++ b/pkg/compiler/lib/src/js_backend/checked_mode_helpers.dart
@@ -58,7 +58,7 @@
   @override
   void generateAdditionalArguments(SsaCodeGenerator codegen, ModularNamer namer,
       HTypeConversion node, List<jsAst.Expression> arguments) {
-    assert(node.typeExpression.isTypeVariable);
+    assert(node.typeExpression is TypeVariableType);
     codegen.use(node.typeRepresentation);
     arguments.add(codegen.pop());
   }
@@ -73,7 +73,7 @@
   @override
   void generateAdditionalArguments(SsaCodeGenerator codegen, ModularNamer namer,
       HTypeConversion node, List<jsAst.Expression> arguments) {
-    assert(node.typeExpression.isFunctionType);
+    assert(node.typeExpression is FunctionType);
     codegen.use(node.typeRepresentation);
     arguments.add(codegen.pop());
   }
@@ -88,7 +88,7 @@
   @override
   void generateAdditionalArguments(SsaCodeGenerator codegen, ModularNamer namer,
       HTypeConversion node, List<jsAst.Expression> arguments) {
-    assert(node.typeExpression.isFutureOr);
+    assert(node.typeExpression is FutureOrType);
     codegen.use(node.typeRepresentation);
     arguments.add(codegen.pop());
   }
@@ -203,23 +203,23 @@
   String getCheckedModeHelperNameInternal(
       DartType type, CommonElements commonElements,
       {bool typeCast, bool nativeCheckOnly}) {
-    assert(!type.isTypedef);
+    assert(type is! TypedefType);
 
-    if (type.isTypeVariable) {
+    if (type is TypeVariableType) {
       return typeCast
           ? 'subtypeOfRuntimeTypeCast'
           : 'assertSubtypeOfRuntimeType';
     }
 
-    if (type.isFunctionType) {
+    if (type is FunctionType) {
       return typeCast ? 'functionTypeCast' : 'functionTypeCheck';
     }
 
-    if (type.isFutureOr) {
+    if (type is FutureOrType) {
       return typeCast ? 'futureOrCast' : 'futureOrCheck';
     }
 
-    assert(type.isInterfaceType,
+    assert(type is InterfaceType,
         failedAt(NO_LOCATION_SPANNABLE, "Unexpected type: $type"));
     InterfaceType interfaceType = type;
     ClassEntity element = interfaceType.element;
@@ -284,7 +284,7 @@
       return nativeCheck ? 'listSuperNative$suffix' : 'listSuper$suffix';
     }
 
-    if (type.isInterfaceType && !type.treatAsRaw) {
+    if (type is InterfaceType && !type.treatAsRaw) {
       return typeCast ? 'subtypeCast' : 'assertSubtype';
     }
 
diff --git a/pkg/compiler/lib/src/js_backend/codegen_listener.dart b/pkg/compiler/lib/src/js_backend/codegen_listener.dart
index f7d02de..f4ae36c 100644
--- a/pkg/compiler/lib/src/js_backend/codegen_listener.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen_listener.dart
@@ -174,7 +174,7 @@
       // If the type is a web component, we need to ensure the constructors are
       // available to 'upgrade' the native object.
       TypeConstantValue type = constant;
-      if (type.representedType.isInterfaceType) {
+      if (type.representedType is InterfaceType) {
         InterfaceType representedType = type.representedType;
         _customElementsAnalysis.registerTypeConstant(representedType.element);
       }
diff --git a/pkg/compiler/lib/src/js_backend/custom_elements_analysis.dart b/pkg/compiler/lib/src/js_backend/custom_elements_analysis.dart
index 16be5f2..2a547ec 100644
--- a/pkg/compiler/lib/src/js_backend/custom_elements_analysis.dart
+++ b/pkg/compiler/lib/src/js_backend/custom_elements_analysis.dart
@@ -102,13 +102,13 @@
   }
 
   void registerTypeLiteral(DartType type) {
-    if (type.isInterfaceType) {
+    if (type is InterfaceType) {
       // TODO(sra): If we had a flow query from the type literal expression to
       // the Type argument of the metadata lookup, we could tell if this type
       // literal is really a demand for the metadata.
       InterfaceType interfaceType = type;
       join.selectedClasses.add(interfaceType.element);
-    } else if (type.isTypeVariable) {
+    } else if (type is TypeVariableType) {
       // This is a type parameter of a parameterized class.
       // TODO(sra): Is there a way to determine which types are bound to the
       // parameter?
diff --git a/pkg/compiler/lib/src/js_backend/field_analysis.dart b/pkg/compiler/lib/src/js_backend/field_analysis.dart
index aa2c328..766013e 100644
--- a/pkg/compiler/lib/src/js_backend/field_analysis.dart
+++ b/pkg/compiler/lib/src/js_backend/field_analysis.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:kernel/ast.dart' as ir;
+import 'package:kernel/type_environment.dart' as ir;
 
 import '../common.dart';
 import '../constants/values.dart';
@@ -56,7 +57,8 @@
 
       FieldEntity fieldElement = _elementMap.getField(field);
       ir.Expression expression = field.initializer;
-      ConstantValue value = _elementMap.getConstantValue(expression,
+      ConstantValue value = _elementMap.getConstantValue(
+          _elementMap.getStaticTypeContext(fieldElement), expression,
           requireConstant: false, implicitNull: true);
       if (value != null && value.isConstant) {
         fieldData[fieldElement] = new AllocatorData(value);
@@ -65,6 +67,8 @@
 
     for (ir.Constructor constructor in classNode.constructors) {
       KConstructor constructorElement = _elementMap.getConstructor(constructor);
+      ir.StaticTypeContext staticTypeContext =
+          _elementMap.getStaticTypeContext(constructorElement);
       constructors.add(constructorElement);
       for (ir.Initializer initializer in constructor.initializers) {
         if (initializer is ir.FieldInitializer) {
@@ -79,7 +83,8 @@
 
           Initializer initializerValue = const Initializer.complex();
           ir.Expression value = initializer.value;
-          ConstantValue constantValue = _elementMap.getConstantValue(value,
+          ConstantValue constantValue = _elementMap.getConstantValue(
+              staticTypeContext, value,
               requireConstant: false, implicitNull: true);
           if (constantValue != null && constantValue.isConstant) {
             initializerValue = new Initializer.direct(constantValue);
@@ -90,9 +95,8 @@
             if (position != -1) {
               if (position >= constructor.function.requiredParameterCount) {
                 constantValue = _elementMap.getConstantValue(
-                    parameter.initializer,
-                    requireConstant: false,
-                    implicitNull: true);
+                    staticTypeContext, parameter.initializer,
+                    requireConstant: false, implicitNull: true);
                 if (constantValue != null && constantValue.isConstant) {
                   initializerValue =
                       new Initializer.positional(position, constantValue);
@@ -103,9 +107,8 @@
                   constructor.function.namedParameters.indexOf(parameter);
               if (position != -1) {
                 constantValue = _elementMap.getConstantValue(
-                    parameter.initializer,
-                    requireConstant: false,
-                    implicitNull: true);
+                    staticTypeContext, parameter.initializer,
+                    requireConstant: false, implicitNull: true);
                 if (constantValue != null && constantValue.isConstant) {
                   initializerValue =
                       new Initializer.named(parameter.name, constantValue);
@@ -123,7 +126,8 @@
   void registerStaticField(KField field, InitializerComplexity complexity) {
     ir.Field node = _elementMap.getMemberNode(field);
     ir.Expression expression = node.initializer;
-    ConstantValue value = _elementMap.getConstantValue(expression,
+    ConstantValue value = _elementMap.getConstantValue(
+        _elementMap.getStaticTypeContext(field), expression,
         requireConstant: node.isConst, implicitNull: true);
     if (value != null && !value.isConstant) {
       value = null;
diff --git a/pkg/compiler/lib/src/js_backend/frequency_assignment.dart b/pkg/compiler/lib/src/js_backend/frequency_assignment.dart
new file mode 100644
index 0000000..b19015e
--- /dev/null
+++ b/pkg/compiler/lib/src/js_backend/frequency_assignment.dart
@@ -0,0 +1,216 @@
+// Copyright (c) 2019, 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:collection' show SplayTreeMap;
+
+/// Assigns names from [nameSequence] to items using a naive algorithm.
+///
+/// Items are assigned the next available name in decreasing frequency
+/// order. This allocation order is unstable in that small changes in the input
+/// cause large changes in the output. To see this, consider a typical
+/// distribution that has a 'tail' where large numbers of items occur two or
+/// three times. If the small change causes one of the items that occurs twice
+/// to occur four times, of then all the items that occur three times will be
+/// assigned names that are 'shifted down' in the allocation order, as will many
+/// of the items that occur twice.
+///
+/// See [semistableFrequencyAssignment] for meaning of parameters.
+void naiveFrequencyAssignment(
+    int items,
+    Iterable<String> nameSequence,
+    int Function(int) hashOf,
+    int Function(int) countOf,
+    void Function(int, String) assign) {
+  Iterator<String> nameIterator = nameSequence.iterator..moveNext();
+
+  for (int item = 0; item < items; item++) {
+    assign(item, nameIterator.current);
+    nameIterator.moveNext();
+  }
+}
+
+/// Assigns names from [nameSequence] to items, trying to avoid the unstable
+/// allocation of [naiveFrequencyAssignment] by assigning items to their
+/// hashing-based 'preferred' slots if possible.
+///
+/// - [items]: number of items to be assigned names. Items are numbered from
+///   zero. Items must be sorted in order of decreasing [countOf].
+///
+/// - [nameSequence]: Potentially unbounded sequence of valid names in
+///   increasing size.
+///
+/// - [hashOf]: Function returning a stable hash code for item `i`.
+///
+/// - [countOf]: Function returning the frequency or number of occurences of
+///   item `i`.
+///
+/// - [assign]: Function to register the assignment of a name to item `i`.
+void semistableFrequencyAssignment(
+    int items,
+    Iterable<String> nameSequence,
+    int Function(int) hashOf,
+    int Function(int) countOf,
+    void Function(int, String) assign) {
+  // Overallocate 3x the number of names so that the last pool is large enough
+  // to substantially reduce collisions. Round up to the next power of two so
+  // that slightly changing the number of items does not usually change the size
+  // of the largest pool.
+  int maxIndex = 1 << (items * 3).bitLength;
+  List<String> names = nameSequence.take(maxIndex).toList(growable: false);
+  List<_Pool> pools = _Pool.makePools(names);
+
+  // First cohort with unassigned items.
+  _Cohort firstCohort = _Cohort.makeCohorts(items, countOf);
+
+  for (var pool in pools) {
+    // Completely allocate smaller pools before allocating larger
+    // pools. Completely allocate each cohort in turn.
+
+    // TODO(sra): If the next several cohorts all fit in the current pool, the
+    // allocation will not change the bytes saved by minification.  Consider
+    // allocating the preferred slot from several cohorts before allocating a
+    // non-preferred slot. This should increase the number of items allocated to
+    // their preferred slot.
+    firstCohort = firstCohort?.skipEmpty();
+    for (var startCohort = firstCohort;
+        startCohort != null;
+        startCohort = startCohort.next) {
+      if (pool.remaining == 0) break;
+
+      // Pass 1: assign members of cohort their preferred slot if available.
+      List<int> assigned = [];
+      for (var item in startCohort.unassigned) {
+        if (pool.remaining == 0) break;
+        int hash = hashOf(item);
+        int slot = hash % pool.size;
+        if (pool.slotIsAvailable(slot)) {
+          assign(item, pool.allocate(slot));
+          assigned.add(item);
+        }
+      }
+      startCohort.unassigned.removeAll(assigned);
+      // Pass 2: assign members of cohort their second 'rehash' slot if
+      // available, or the next available slot.
+      assigned.clear();
+      for (var item in startCohort.unassigned) {
+        if (pool.remaining == 0) break;
+        int hash = hashOf(item);
+        int rehashSlot = (5 * hash + 7) % pool.size;
+        int slot = pool.firstAvailableSlotFrom(rehashSlot);
+        assign(item, pool.allocate(slot));
+        assigned.add(item);
+      }
+      startCohort.unassigned.removeAll(assigned);
+    }
+  }
+
+  // Perform naive assignment of any items left unassigned above (should be
+  // none).
+  for (var pool in pools) {
+    while (pool.remaining > 0) {
+      firstCohort = firstCohort?.skipEmpty();
+      if (firstCohort == null) break;
+
+      var item = firstCohort.unassigned.first;
+      String name = pool.allocate(pool.firstAvailableSlot());
+      assign(item, name);
+      firstCohort.unassigned.remove(item);
+    }
+  }
+}
+
+/// A [_Pool] is a set of identifiers of the same length from which names are
+/// allocated.
+class _Pool {
+  final List<String /*?*/ > _names = [];
+
+  // Keep the unused (available) slots in an ordered set for efficiently finding
+  // the next available slot (i.e. linear rehash).  We are concerned about
+  // efficiency because the smaller pools are completely allocated, making
+  // worst-case linear rehashing quadratic. Using an ordered map brings this
+  // down to O(N log N).
+  //
+  // We would prefer an ordered Set, but SplayTreeSet does not have methods to
+  // find keys adjacent to a query key.
+  final SplayTreeMap<int, bool> _availableSlots = SplayTreeMap();
+
+  static List<_Pool> makePools(Iterable<String> names) {
+    List<_Pool> pools = [];
+    for (var name in names) {
+      int length = name.length;
+      while (pools.length < length) pools.add(_Pool());
+      _Pool pool = pools[length - 1];
+      pool._availableSlots[pool._names.length] = true;
+      pool._names.add(name);
+    }
+    return pools;
+  }
+
+  int get size => _names.length;
+  int get remaining => _availableSlots.length;
+
+  bool slotIsAvailable(int slot) => _names[slot] != null;
+
+  int firstAvailableSlot() => _availableSlots.keys.first;
+
+  /// Returns [start] if slot [start] is free, otherwise returns the next
+  /// available slot.
+  int firstAvailableSlotFrom(int start) =>
+      _availableSlots.firstKeyAfter(start - 1) ??
+      _availableSlots.firstKeyAfter(-1) ??
+      (throw StateError('No entries left in pool'));
+
+  String allocate(int slot) {
+    String name = _names[slot];
+    assert(name != null);
+    _names[slot] = null;
+    _availableSlots.remove(slot);
+    return name;
+  }
+
+  @override
+  String toString() => '_Pool(${_names.length}, ${_availableSlots.length})';
+}
+
+/// A [_Cohort] is a set of entities which occur with the same frequency. The
+/// entities are identified by integers.
+class _Cohort {
+  _Cohort next; // Next cohort in decreasing frequency.
+  final int count; // This is the cohort of items occuring [count] times.
+  Set<int> unassigned = Set();
+
+  _Cohort(this.count);
+
+  _Cohort skipEmpty() {
+    _Cohort cohort = this;
+    while (cohort != null && cohort.remaining == 0) cohort = cohort.next;
+    return cohort;
+  }
+
+  int get remaining => unassigned.length;
+
+  static _Cohort makeCohorts(int items, int Function(int) countOf) {
+    // Build _Cohorts.
+    _Cohort first, current;
+    int lastCount = -1;
+    for (int item = 0; item < items; item++) {
+      int count = countOf(item);
+      if (count != lastCount) {
+        lastCount = count;
+        _Cohort next = _Cohort(count);
+        if (current == null) {
+          first = next;
+        } else {
+          current.next = next;
+        }
+        current = next;
+      }
+      current.unassigned.add(item);
+    }
+    return first;
+  }
+
+  @override
+  String toString() => '_Cohort($count, $remaining)';
+}
diff --git a/pkg/compiler/lib/src/js_backend/impact_transformer.dart b/pkg/compiler/lib/src/js_backend/impact_transformer.dart
index 7c2177a..3e0b432 100644
--- a/pkg/compiler/lib/src/js_backend/impact_transformer.dart
+++ b/pkg/compiler/lib/src/js_backend/impact_transformer.dart
@@ -185,7 +185,7 @@
           break;
         case TypeUseKind.TYPE_LITERAL:
           _customElementsResolutionAnalysis.registerTypeLiteral(type);
-          if (type.isTypeVariable) {
+          if (type is TypeVariableType) {
             TypeVariableType typeVariable = type;
             Entity typeDeclaration = typeVariable.element.typeDeclaration;
             if (typeDeclaration is ClassEntity) {
@@ -332,9 +332,11 @@
     type = _elementEnvironment.getUnaliasedType(type);
     registerImpact(_impacts.typeCheck);
 
-    if (!type.treatAsRaw || type.containsTypeVariables || type.isFunctionType) {
+    if (!type.treatAsRaw ||
+        type.containsTypeVariables ||
+        type is FunctionType) {
       registerImpact(_impacts.genericTypeCheck);
-      if (type.isTypeVariable) {
+      if (type is TypeVariableType) {
         registerImpact(_impacts.typeVariableTypeCheck);
       }
     }
@@ -353,7 +355,6 @@
 class CodegenImpactTransformer {
   final JClosedWorld _closedWorld;
   final ElementEnvironment _elementEnvironment;
-  final CommonElements _commonElements;
   final BackendImpacts _impacts;
   final NativeData _nativeData;
   final BackendUsage _backendUsage;
@@ -367,7 +368,6 @@
   CodegenImpactTransformer(
       this._closedWorld,
       this._elementEnvironment,
-      this._commonElements,
       this._impacts,
       this._nativeData,
       this._backendUsage,
@@ -379,8 +379,8 @@
       this._nativeEmitter);
 
   void onIsCheckForCodegen(DartType type, TransformedWorldImpact transformed) {
-    if (type.isDynamic) return;
-    if (type.isVoid) return;
+    if (type is DynamicType) return;
+    if (type is VoidType) return;
     type = type.unaliased;
     _impacts.typeCheck.registerImpact(transformed, _elementEnvironment);
 
diff --git a/pkg/compiler/lib/src/js_backend/interceptor_data.dart b/pkg/compiler/lib/src/js_backend/interceptor_data.dart
index db85765..867c379 100644
--- a/pkg/compiler/lib/src/js_backend/interceptor_data.dart
+++ b/pkg/compiler/lib/src/js_backend/interceptor_data.dart
@@ -278,7 +278,7 @@
     // is mixed-in or in an implements clause.
 
     if (!type.treatAsRaw) return false;
-    if (type.isFutureOr) return false;
+    if (type is FutureOrType) return false;
     InterfaceType interfaceType = type;
     ClassEntity classElement = interfaceType.element;
     if (isInterceptedClass(classElement)) return false;
diff --git a/pkg/compiler/lib/src/js_backend/namer.dart b/pkg/compiler/lib/src/js_backend/namer.dart
index fd7df4d..aaabd51 100644
--- a/pkg/compiler/lib/src/js_backend/namer.dart
+++ b/pkg/compiler/lib/src/js_backend/namer.dart
@@ -1513,7 +1513,7 @@
 
   @override
   jsAst.Name operatorIsType(DartType type) {
-    if (type.isFunctionType) {
+    if (type is FunctionType) {
       // TODO(erikcorry): Reduce from $isx to ix when we are minifying.
       return new CompoundName([
         new StringBackedName(fixedNames.operatorIsPrefix),
@@ -1617,7 +1617,7 @@
   }
 
   String getTypeRepresentationForTypeConstant(DartType type) {
-    if (type.isDynamic) return "dynamic";
+    if (type is DynamicType) return "dynamic";
     if (type is TypedefType) {
       return uniqueNameForTypeConstantElement(
           type.element.library, type.element);
@@ -2178,11 +2178,11 @@
   }
 
   bool _isSimpleFunctionType(FunctionType type) {
-    if (!type.returnType.isDynamic) return false;
+    if (type.returnType is! DynamicType) return false;
     if (!type.optionalParameterTypes.isEmpty) return false;
     if (!type.namedParameterTypes.isEmpty) return false;
     for (DartType parameter in type.parameterTypes) {
-      if (!parameter.isDynamic) return false;
+      if (parameter is! DynamicType) return false;
     }
     return true;
   }
diff --git a/pkg/compiler/lib/src/js_backend/resolution_listener.dart b/pkg/compiler/lib/src/js_backend/resolution_listener.dart
index c781753..9d16126 100644
--- a/pkg/compiler/lib/src/js_backend/resolution_listener.dart
+++ b/pkg/compiler/lib/src/js_backend/resolution_listener.dart
@@ -270,7 +270,7 @@
           ..addAll(functionType.optionalParameterTypes)
           ..addAll(functionType.namedParameterTypes);
         for (var type in allParameterTypes) {
-          if (type.isFunctionType || type.isTypedef) {
+          if (type is FunctionType || type is TypedefType) {
             var closureConverter = _commonElements.closureConverter;
             worldImpact.registerStaticUse(
                 new StaticUse.implicitInvoke(closureConverter));
diff --git a/pkg/compiler/lib/src/js_backend/runtime_types.dart b/pkg/compiler/lib/src/js_backend/runtime_types.dart
index b486e74..319ab0c 100644
--- a/pkg/compiler/lib/src/js_backend/runtime_types.dart
+++ b/pkg/compiler/lib/src/js_backend/runtime_types.dart
@@ -1023,6 +1023,22 @@
   }
 
   @override
+  jsAst.Expression visitLegacyType(LegacyType type, ModularEmitter emitter) {
+    throw UnsupportedError('Legacy RTI does not support legacy types');
+  }
+
+  @override
+  jsAst.Expression visitNullableType(
+      NullableType type, ModularEmitter emitter) {
+    throw UnsupportedError('Legacy RTI does not support nullable types');
+  }
+
+  @override
+  jsAst.Expression visitNeverType(NeverType type, ModularEmitter emitter) {
+    throw UnsupportedError('Legacy RTI does not support the Never type');
+  }
+
+  @override
   jsAst.Expression visitFunctionTypeVariable(
       FunctionTypeVariable type, ModularEmitter emitter) {
     int position = functionTypeVariables.indexOf(type);
@@ -1290,81 +1306,53 @@
   }
 }
 
-class ArgumentCollector extends DartTypeVisitor<dynamic, bool> {
+class ArgumentCollector extends DartTypeVisitor<void, void> {
   final Set<ClassEntity> classes = new Set<ClassEntity>();
 
   void addClass(ClassEntity cls) {
     classes.add(cls);
   }
 
-  collect(DartType type, {bool isTypeArgument: false}) {
-    visit(type, isTypeArgument);
+  void collect(DartType type) {
+    visit(type, null);
   }
 
   /// Collect all types in the list as if they were arguments of an
   /// InterfaceType.
-  collectAll(List<DartType> types, {bool isTypeArgument: false}) {
-    for (DartType type in types) {
-      visit(type, true);
-    }
+  void collectAll(List<DartType> types) => types.forEach(collect);
+
+  @override
+  void visitLegacyType(LegacyType type, _) {
+    collect(type.baseType);
   }
 
   @override
-  visitTypedefType(TypedefType type, bool isTypeArgument) {
-    collect(type.unaliased, isTypeArgument: isTypeArgument);
+  void visitNullableType(NullableType type, _) {
+    collect(type.baseType);
   }
 
   @override
-  visitInterfaceType(InterfaceType type, bool isTypeArgument) {
-    if (isTypeArgument) addClass(type.element);
-    collectAll(type.typeArguments, isTypeArgument: true);
+  void visitFutureOrType(FutureOrType type, _) {
+    collect(type.typeArgument);
   }
 
   @override
-  visitFunctionType(FunctionType type, _) {
-    collect(type.returnType, isTypeArgument: true);
-    collectAll(type.parameterTypes, isTypeArgument: true);
-    collectAll(type.optionalParameterTypes, isTypeArgument: true);
-    collectAll(type.namedParameterTypes, isTypeArgument: true);
-  }
-}
-
-class FunctionArgumentCollector extends DartTypeVisitor<dynamic, bool> {
-  final Set<ClassEntity> classes = new Set<ClassEntity>();
-
-  FunctionArgumentCollector();
-
-  collect(DartType type, {bool inFunctionType: false}) {
-    visit(type, inFunctionType);
-  }
-
-  collectAll(Iterable<DartType> types, {bool inFunctionType: false}) {
-    for (DartType type in types) {
-      visit(type, inFunctionType);
-    }
+  void visitTypedefType(TypedefType type, _) {
+    collect(type.unaliased);
   }
 
   @override
-  visitTypedefType(TypedefType type, bool inFunctionType) {
-    collect(type.unaliased, inFunctionType: inFunctionType);
+  void visitInterfaceType(InterfaceType type, _) {
+    addClass(type.element);
+    collectAll(type.typeArguments);
   }
 
   @override
-  visitInterfaceType(InterfaceType type, bool inFunctionType) {
-    if (inFunctionType) {
-      classes.add(type.element);
-    }
-    collectAll(type.typeArguments, inFunctionType: inFunctionType);
-  }
-
-  @override
-  visitFunctionType(FunctionType type, _) {
-    collect(type.returnType, inFunctionType: true);
-    collectAll(type.parameterTypes, inFunctionType: true);
-    collectAll(type.optionalParameterTypes, inFunctionType: true);
-    collectAll(type.namedParameterTypes, inFunctionType: true);
-    collectAll(type.typeVariables.map((type) => type.bound),
-        inFunctionType: true);
+  void visitFunctionType(FunctionType type, _) {
+    collect(type.returnType);
+    collectAll(type.parameterTypes);
+    collectAll(type.optionalParameterTypes);
+    collectAll(type.namedParameterTypes);
   }
 }
 
@@ -1387,7 +1375,8 @@
 
   TypeVisitor({this.onClass, this.onTypeVariable, this.onFunctionType});
 
-  visitType(DartType type, TypeVisitorState state) => type.accept(this, state);
+  void visitType(DartType type, TypeVisitorState state) =>
+      type.accept(this, state);
 
   TypeVisitorState covariantArgument(TypeVisitorState state) {
     switch (state) {
@@ -1417,13 +1406,25 @@
     throw new UnsupportedError("Unexpected TypeVisitorState $state");
   }
 
-  visitTypes(List<DartType> types, TypeVisitorState state) {
+  void visitTypes(List<DartType> types, TypeVisitorState state) {
     for (DartType type in types) {
       visitType(type, state);
     }
   }
 
   @override
+  void visitLegacyType(LegacyType type, TypeVisitorState state) =>
+      visitType(type.baseType, state);
+
+  @override
+  void visitNullableType(NullableType type, TypeVisitorState state) =>
+      visitType(type.baseType, state);
+
+  @override
+  void visitFutureOrType(FutureOrType type, TypeVisitorState state) =>
+      visitType(type.typeArgument, state);
+
+  @override
   void visitTypeVariableType(TypeVariableType type, TypeVisitorState state) {
     if (onTypeVariable != null) {
       onTypeVariable(type.element, state: state);
diff --git a/pkg/compiler/lib/src/js_backend/runtime_types_new.dart b/pkg/compiler/lib/src/js_backend/runtime_types_new.dart
index 92a3b0a..53f2004 100644
--- a/pkg/compiler/lib/src/js_backend/runtime_types_new.dart
+++ b/pkg/compiler/lib/src/js_backend/runtime_types_new.dart
@@ -226,6 +226,23 @@
   void visit(DartType type, _) => type.accept(this, _);
 
   @override
+  void visitLegacyType(LegacyType type, _) {
+    visit(type.baseType, _);
+    _emitCode(Recipe.wrapStar);
+  }
+
+  @override
+  void visitNullableType(NullableType type, _) {
+    visit(type.baseType, _);
+    _emitCode(Recipe.wrapQuestion);
+  }
+
+  @override
+  void visitNeverType(NeverType type, _) {
+    _emitExtensionOp(Recipe.pushNeverExtension);
+  }
+
+  @override
   void visitTypeVariableType(TypeVariableType type, _) {
     TypeEnvironmentStructure environment = _environment;
     if (environment is SingletonTypeEnvironmentStructure) {
diff --git a/pkg/compiler/lib/src/js_backend/runtime_types_resolution.dart b/pkg/compiler/lib/src/js_backend/runtime_types_resolution.dart
index 9c9fd78..a303026 100644
--- a/pkg/compiler/lib/src/js_backend/runtime_types_resolution.dart
+++ b/pkg/compiler/lib/src/js_backend/runtime_types_resolution.dart
@@ -1055,7 +1055,7 @@
 
     void processChecks(Set<DartType> checks) {
       checks.forEach((DartType type) {
-        if (type.isInterfaceType) {
+        if (type is InterfaceType) {
           InterfaceType itf = type;
           if (!itf.treatAsRaw) {
             potentiallyNeedTypeArguments(itf.element);
@@ -1067,7 +1067,7 @@
             Entity typeDeclaration = typeVariable.element.typeDeclaration;
             potentiallyNeedTypeArguments(typeDeclaration);
           });
-          if (type.isFunctionType) {
+          if (type is FunctionType) {
             checkClosures(potentialSubtypeOf: type);
           }
           if (type is FutureOrType) {
@@ -1100,8 +1100,8 @@
     void checkFunction(Entity function, FunctionType type) {
       for (FunctionTypeVariable typeVariable in type.typeVariables) {
         DartType bound = typeVariable.bound;
-        if (!bound.isDynamic &&
-            !bound.isVoid &&
+        if (bound is! DynamicType &&
+            bound is! VoidType &&
             bound != closedWorld.commonElements.objectType) {
           potentiallyNeedTypeArguments(function);
           break;
diff --git a/pkg/compiler/lib/src/js_backend/type_reference.dart b/pkg/compiler/lib/src/js_backend/type_reference.dart
index 068fe60..e6be8f9 100644
--- a/pkg/compiler/lib/src/js_backend/type_reference.dart
+++ b/pkg/compiler/lib/src/js_backend/type_reference.dart
@@ -76,8 +76,16 @@
         FullTypeEnvironmentRecipe;
 import '../serialization/serialization.dart';
 import '../util/util.dart' show Hashing;
+import 'frequency_assignment.dart';
 import 'runtime_types_new.dart' show RecipeEncoder;
 
+/// Run the minifier for 'type$' property names even in non-minified mode,
+/// making a name from minified name and the readable name. Usage:
+///
+///     DART_VM_OPTIONS='-DDebugMinifyTypesHolder=true' dart2js ...
+///
+const _debugMinify = bool.fromEnvironment('DebugMinifyTypesHolder');
+
 /// A [TypeReference] is a deferred JavaScript expression that refers to the
 /// runtime representation of a ground type or ground type environment.  The
 /// deferred expression is filled in by the TypeReferenceFinalizer which is
@@ -386,7 +394,7 @@
       referencesInTable.add(referenceSet);
     }
 
-    if (!_minify) {
+    if (!_minify && !_debugMinify) {
       // For unminified code, use the characteristic names as property names.
       // TODO(sra): Some of these names are long. We could truncate the names
       // after the unique prefix.
@@ -410,15 +418,20 @@
       referenceSet.hash = _hashCharacteristicString(referenceSet.name);
     }
 
-    Iterator<String> names = minifiedNameSequence().iterator..moveNext();
-
-    // TODO(sra): It is highly unstable to allocate names in frequency
-    // order. Use a more stable frequency based allocation by assigning
-    // 'preferred' names.
-    for (_ReferenceSet referenceSet in referencesByFrequency) {
-      referenceSet.propertyName = names.current;
-      names.moveNext();
+    int hashOf(int index) => referencesByFrequency[index].hash;
+    int countOf(int index) => referencesByFrequency[index].count;
+    void assign(int index, String name) {
+      if (_minify) {
+        referencesByFrequency[index].propertyName = name;
+      } else {
+        var refSet = referencesByFrequency[index];
+        refSet.propertyName = name + '_' + refSet.name;
+      }
     }
+
+    //naiveFrequencyAssignment(
+    semistableFrequencyAssignment(referencesByFrequency.length,
+        minifiedNameSequence(), hashOf, countOf, assign);
   }
 
   static int _hashCharacteristicString(String s) {
@@ -607,6 +620,23 @@
   }
 
   @override
+  void visitLegacyType(covariant LegacyType type, _) {
+    _add('legacy');
+    _visit(type.baseType, type);
+  }
+
+  @override
+  void visitNullableType(covariant NullableType type, _) {
+    _add('nullable');
+    _visit(type.baseType, type);
+  }
+
+  @override
+  void visitNeverType(covariant NeverType type, _) {
+    _add('Never');
+  }
+
+  @override
   void visitVoidType(covariant VoidType type, _) {
     _add('void');
   }
diff --git a/pkg/compiler/lib/src/js_emitter/constant_ordering.dart b/pkg/compiler/lib/src/js_emitter/constant_ordering.dart
index f1200d2..7648503 100644
--- a/pkg/compiler/lib/src/js_emitter/constant_ordering.dart
+++ b/pkg/compiler/lib/src/js_emitter/constant_ordering.dart
@@ -212,21 +212,29 @@
   }
 
   @override
-  int visitVoidType(covariant VoidType type, _) => 6;
-  @override
-  int visitTypeVariableType(covariant TypeVariableType type, _) => 3;
-  @override
   int visitFunctionType(covariant FunctionType type, _) => 0;
   @override
   int visitInterfaceType(covariant InterfaceType type, _) => 1;
   @override
   int visitTypedefType(covariant TypedefType type, _) => 2;
   @override
+  int visitTypeVariableType(covariant TypeVariableType type, _) => 3;
+  @override
+  int visitNeverType(covariant NeverType type, _) => 4;
+  @override
   int visitDynamicType(covariant DynamicType type, _) => 5;
   @override
+  int visitVoidType(covariant VoidType type, _) => 6;
+  @override
   int visitAnyType(covariant AnyType type, _) => 7;
   @override
   int visitErasedType(covariant ErasedType type, _) => 8;
+  @override
+  int visitLegacyType(covariant LegacyType type, _) => 9;
+  @override
+  int visitNullableType(covariant NullableType type, _) => 10;
+  @override
+  int visitFutureOrType(covariant FutureOrType type, _) => 11;
 }
 
 class _DartTypeOrdering extends DartTypeVisitor<int, DartType> {
@@ -246,6 +254,25 @@
   }
 
   @override
+  int visitLegacyType(covariant LegacyType type, covariant LegacyType other) =>
+      compare(type.baseType, other.baseType);
+
+  @override
+  int visitNullableType(
+          covariant NullableType type, covariant NullableType other) =>
+      visit(type.baseType, other.baseType);
+
+  @override
+  int visitFutureOrType(
+          covariant FutureOrType type, covariant FutureOrType other) =>
+      visit(type.typeArgument, other.typeArgument);
+
+  @override
+  int visitNeverType(covariant NeverType type, covariant NeverType other) {
+    throw UnsupportedError('Unreachable');
+  }
+
+  @override
   int visitVoidType(covariant VoidType type, covariant VoidType other) {
     throw new UnsupportedError('Unreachable');
   }
diff --git a/pkg/compiler/lib/src/js_emitter/native_emitter.dart b/pkg/compiler/lib/src/js_emitter/native_emitter.dart
index 7be3f0d..c520f5c 100644
--- a/pkg/compiler/lib/src/js_emitter/native_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/native_emitter.dart
@@ -268,7 +268,7 @@
       for (jsAst.Parameter stubParameter in stubParameters) {
         if (stubParameter.name == name) {
           type = type.unaliased;
-          if (type.isFunctionType) {
+          if (type is FunctionType) {
             closureConverter ??= _emitterTask.emitter
                 .staticFunctionAccess(_commonElements.closureConverter);
 
diff --git a/pkg/compiler/lib/src/js_emitter/program_builder/collector.dart b/pkg/compiler/lib/src/js_emitter/program_builder/collector.dart
index 7b49849f..3105010 100644
--- a/pkg/compiler/lib/src/js_emitter/program_builder/collector.dart
+++ b/pkg/compiler/lib/src/js_emitter/program_builder/collector.dart
@@ -9,13 +9,10 @@
 ///
 /// The code for the containing (used) methods must exist in the `universe`.
 class Collector {
-  final CompilerOptions _options;
   final JCommonElements _commonElements;
   final JElementEnvironment _elementEnvironment;
   final OutputUnitData _outputUnitData;
   final CodegenWorld _codegenWorld;
-  // TODO(floitsch): the code-emitter task should not need a namer.
-  final Namer _namer;
   final Emitter _emitter;
   final NativeData _nativeData;
   final InterceptorData _interceptorData;
@@ -47,12 +44,10 @@
   final List<ClassEntity> nativeClassesAndSubclasses = <ClassEntity>[];
 
   Collector(
-      this._options,
       this._commonElements,
       this._elementEnvironment,
       this._outputUnitData,
       this._codegenWorld,
-      this._namer,
       this._emitter,
       this._nativeData,
       this._interceptorData,
diff --git a/pkg/compiler/lib/src/js_emitter/program_builder/field_visitor.dart b/pkg/compiler/lib/src/js_emitter/program_builder/field_visitor.dart
index 83a7d37..f753208 100644
--- a/pkg/compiler/lib/src/js_emitter/program_builder/field_visitor.dart
+++ b/pkg/compiler/lib/src/js_emitter/program_builder/field_visitor.dart
@@ -24,7 +24,6 @@
     bool needsGetter, bool needsSetter, bool needsCheckedSetter);
 
 class FieldVisitor {
-  final CompilerOptions _options;
   final JElementEnvironment _elementEnvironment;
   final JCommonElements _commonElements;
   final CodegenWorld _codegenWorld;
@@ -32,7 +31,7 @@
   final Namer _namer;
   final JClosedWorld _closedWorld;
 
-  FieldVisitor(this._options, this._elementEnvironment, this._commonElements,
+  FieldVisitor(this._elementEnvironment, this._commonElements,
       this._codegenWorld, this._nativeData, this._namer, this._closedWorld);
 
   /// Invokes [f] for each of the fields of [element].
diff --git a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
index cfd16dc..ebb4796 100644
--- a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
+++ b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
@@ -137,12 +137,10 @@
       this._rtiNeededClasses,
       this._mainFunction)
       : this.collector = new Collector(
-            _options,
             _commonElements,
             _elementEnvironment,
             _outputUnitData,
             _codegenWorld,
-            _namer,
             _task.emitter,
             _nativeData,
             _interceptorData,
@@ -1173,7 +1171,7 @@
           fieldData.isElided));
     }
 
-    FieldVisitor visitor = new FieldVisitor(_options, _elementEnvironment,
+    FieldVisitor visitor = new FieldVisitor(_elementEnvironment,
         _commonElements, _codegenWorld, _nativeData, _namer, _closedWorld);
     visitor.visitFields(visitField,
         visitStatics: visitStatics, library: library, cls: cls);
diff --git a/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart b/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
index fcc0a7e..7365429 100644
--- a/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
@@ -240,7 +240,7 @@
       return new jsAst.VariableUse(_getVariableName(variable.element.name));
     }
 
-    if (substitution.arguments.every((DartType type) => type.isDynamic)) {
+    if (substitution.arguments.every((DartType type) => type is DynamicType)) {
       return emitter.generateFunctionThatReturnsNull();
     } else {
       jsAst.Expression value =
@@ -323,6 +323,17 @@
   }
 
   @override
+  bool visitLegacyType(LegacyType type, OutputUnit argument) =>
+      visit(type.baseType, argument);
+
+  @override
+  bool visitNullableType(NullableType type, OutputUnit argument) =>
+      visit(type.baseType, argument);
+
+  @override
+  bool visitNeverType(NeverType type, OutputUnit argument) => true;
+
+  @override
   bool visitFutureOrType(FutureOrType type, OutputUnit argument) {
     if (_outputUnitData.outputUnitForClass(_commonElements.functionClass) !=
         argument) {
diff --git a/pkg/compiler/lib/src/js_model/closure.dart b/pkg/compiler/lib/src/js_model/closure.dart
index 61bb3c7..df0534f 100644
--- a/pkg/compiler/lib/src/js_model/closure.dart
+++ b/pkg/compiler/lib/src/js_model/closure.dart
@@ -1160,7 +1160,8 @@
     ir.TreeNode sourceNode = definition.node;
     ir.DartType type;
     if (sourceNode is ir.Class) {
-      type = sourceNode.thisType;
+      type = sourceNode.getThisType(
+          elementMap.coreTypes, sourceNode.enclosingLibrary.nonNullable);
     } else if (sourceNode is ir.VariableDeclaration) {
       type = sourceNode.type;
     } else if (sourceNode is ir.Field) {
diff --git a/pkg/compiler/lib/src/js_model/element_map_impl.dart b/pkg/compiler/lib/src/js_model/element_map_impl.dart
index 333b359..dad0b52 100644
--- a/pkg/compiler/lib/src/js_model/element_map_impl.dart
+++ b/pkg/compiler/lib/src/js_model/element_map_impl.dart
@@ -1202,6 +1202,7 @@
     return data.imports[node];
   }
 
+  @override
   ir.CoreTypes get coreTypes =>
       _coreTypes ??= ir.CoreTypes(programEnv.mainComponent);
 
@@ -1211,17 +1212,22 @@
   ir.ClassHierarchy get classHierarchy =>
       _classHierarchy ??= ir.ClassHierarchy(programEnv.mainComponent);
 
+  ir.StaticTypeContext getStaticTypeContext(ir.Member node) {
+    // TODO(johnniwinther): Cache the static type context.
+    return new ir.StaticTypeContext(node, typeEnvironment);
+  }
+
   @override
   StaticTypeProvider getStaticTypeProvider(MemberEntity member) {
     MemberDefinition memberDefinition = members.getData(member).definition;
     StaticTypeCache cachedStaticTypes;
-    ir.InterfaceType thisType;
+    ir.StaticTypeContext staticTypeContext;
     switch (memberDefinition.kind) {
       case MemberKind.regular:
       case MemberKind.constructor:
       case MemberKind.constructorBody:
         ir.Member node = memberDefinition.node;
-        thisType = node.enclosingClass?.thisType;
+        staticTypeContext = getStaticTypeContext(node);
         cachedStaticTypes = members.getData(member).staticTypes;
         break;
       case MemberKind.closureCall:
@@ -1229,7 +1235,7 @@
         while (node != null) {
           if (node is ir.Member) {
             ir.Member member = node;
-            thisType = member.enclosingClass?.thisType;
+            staticTypeContext = getStaticTypeContext(member);
             cachedStaticTypes = members.getData(getMember(member)).staticTypes;
             break;
           }
@@ -1240,12 +1246,26 @@
       case MemberKind.signature:
       case MemberKind.generatorBody:
         cachedStaticTypes = const StaticTypeCache();
+        ir.TreeNode node = memberDefinition.node;
+        while (node != null) {
+          if (node is ir.Member) {
+            ir.Member member = node;
+            staticTypeContext = getStaticTypeContext(member);
+            break;
+          } else if (node is ir.Library) {
+            // Closure field may use class nodes or type parameter nodes as
+            // the definition node.
+            staticTypeContext =
+                new ir.StaticTypeContext.forAnnotations(node, typeEnvironment);
+          }
+          node = node.parent;
+        }
         break;
     }
-
     assert(cachedStaticTypes != null, "No static types cached for $member.");
-    return new CachedStaticType(typeEnvironment, cachedStaticTypes,
-        new ThisInterfaceType.from(thisType));
+    assert(staticTypeContext != null, "No static types context for $member.");
+    return new CachedStaticType(staticTypeContext, cachedStaticTypes,
+        new ThisInterfaceType.from(staticTypeContext.thisType));
   }
 
   @override
@@ -2784,9 +2804,7 @@
 class ClosedEntityWriter extends EntityWriter {
   final int _earlyMemberIndexLimit;
 
-  final JsKernelToElementMap _elementMap;
-
-  ClosedEntityWriter(this._elementMap, this._earlyMemberIndexLimit);
+  ClosedEntityWriter(this._earlyMemberIndexLimit);
 
   @override
   void writeMemberToDataSink(DataSink sink, IndexedMember value) {
diff --git a/pkg/compiler/lib/src/js_model/js_strategy.dart b/pkg/compiler/lib/src/js_model/js_strategy.dart
index 339c61f..822be8c 100644
--- a/pkg/compiler/lib/src/js_model/js_strategy.dart
+++ b/pkg/compiler/lib/src/js_model/js_strategy.dart
@@ -312,7 +312,6 @@
     _codegenImpactTransformer = new CodegenImpactTransformer(
         closedWorld,
         closedWorld.elementEnvironment,
-        closedWorld.commonElements,
         impacts,
         closedWorld.nativeData,
         closedWorld.backendUsage,
@@ -413,7 +412,7 @@
   EntityWriter forEachCodegenMember(void Function(MemberEntity member) f) {
     int earlyMemberIndexLimit = _elementMap.prepareForCodegenSerialization();
     ClosedEntityWriter entityWriter =
-        new ClosedEntityWriter(_elementMap, earlyMemberIndexLimit);
+        new ClosedEntityWriter(earlyMemberIndexLimit);
     for (int memberIndex = 0;
         memberIndex < _elementMap.members.length;
         memberIndex++) {
diff --git a/pkg/compiler/lib/src/js_model/js_world_builder.dart b/pkg/compiler/lib/src/js_model/js_world_builder.dart
index fd739cc..6308055 100644
--- a/pkg/compiler/lib/src/js_model/js_world_builder.dart
+++ b/pkg/compiler/lib/src/js_model/js_world_builder.dart
@@ -760,6 +760,18 @@
   }
 
   @override
+  DartType visitLegacyType(LegacyType type, _EntityConverter converter) =>
+      LegacyType(visit(type.baseType, converter));
+
+  @override
+  DartType visitNullableType(NullableType type, _EntityConverter converter) =>
+      NullableType(visit(type.baseType, converter));
+
+  @override
+  DartType visitNeverType(NeverType type, _EntityConverter converter) =>
+      NeverType();
+
+  @override
   DartType visitDynamicType(DynamicType type, _EntityConverter converter) {
     return DynamicType();
   }
diff --git a/pkg/compiler/lib/src/kernel/dart2js_target.dart b/pkg/compiler/lib/src/kernel/dart2js_target.dart
index 48f1dcb..02c3047 100644
--- a/pkg/compiler/lib/src/kernel/dart2js_target.dart
+++ b/pkg/compiler/lib/src/kernel/dart2js_target.dart
@@ -53,6 +53,11 @@
   @override
   bool get enableNoSuchMethodForwarders => true;
 
+  // TODO(johnniwinther): Change this to `false` when late field lowering is
+  // ready.
+  @override
+  bool get supportsLateFields => true;
+
   @override
   List<String> get extraRequiredLibraries => _requiredLibraries[name];
 
diff --git a/pkg/compiler/lib/src/kernel/deferred_load.dart b/pkg/compiler/lib/src/kernel/deferred_load.dart
index 87a90be..09c383c 100644
--- a/pkg/compiler/lib/src/kernel/deferred_load.dart
+++ b/pkg/compiler/lib/src/kernel/deferred_load.dart
@@ -5,6 +5,7 @@
 library kernel.deferred_load_data;
 
 import 'package:kernel/ast.dart' as ir;
+import 'package:kernel/type_environment.dart' as ir;
 
 import '../common_elements.dart';
 import '../compiler.dart' show Compiler;
@@ -83,7 +84,8 @@
     // Fetch the internal node in order to skip annotations on the member.
     // TODO(sigmund): replace this pattern when the kernel-ast provides a better
     // way to skip annotations (issue 31565).
-    var visitor = new ConstantCollector(_elementMap, dependencies);
+    var visitor = new ConstantCollector(
+        _elementMap, _elementMap.getStaticTypeContext(element), dependencies);
     if (node is ir.Field) {
       node.initializer?.accept(visitor);
       return;
@@ -119,14 +121,15 @@
 class ConstantCollector extends ir.RecursiveVisitor {
   final KernelToElementMap elementMap;
   final Dependencies dependencies;
+  final ir.StaticTypeContext staticTypeContext;
 
-  ConstantCollector(this.elementMap, this.dependencies);
+  ConstantCollector(this.elementMap, this.staticTypeContext, this.dependencies);
 
   CommonElements get commonElements => elementMap.commonElements;
 
   void add(ir.Expression node, {bool required: true}) {
-    ConstantValue constant =
-        elementMap.getConstantValue(node, requireConstant: required);
+    ConstantValue constant = elementMap
+        .getConstantValue(staticTypeContext, node, requireConstant: required);
     if (constant != null) {
       dependencies.addConstant(
           constant, elementMap.getImport(getDeferredImport(node)));
diff --git a/pkg/compiler/lib/src/kernel/element_map.dart b/pkg/compiler/lib/src/kernel/element_map.dart
index f0a3770..a9ef438 100644
--- a/pkg/compiler/lib/src/kernel/element_map.dart
+++ b/pkg/compiler/lib/src/kernel/element_map.dart
@@ -112,7 +112,8 @@
   js.Name getNameForJsGetName(ConstantValue constant, Namer namer);
 
   /// Computes the [ConstantValue] for the constant [expression].
-  ConstantValue getConstantValue(ir.Expression expression,
+  ConstantValue getConstantValue(
+      ir.StaticTypeContext staticTypeContext, ir.Expression expression,
       {bool requireConstant: true, bool implicitNull: false});
 
   /// Return the [ImportEntity] corresponding to [node].
@@ -178,6 +179,8 @@
 
   /// Returns the defining node for [member].
   ir.Member getMemberNode(covariant MemberEntity member);
+
+  ir.StaticTypeContext getStaticTypeContext(MemberEntity member);
 }
 
 /// Kinds of foreign functions.
diff --git a/pkg/compiler/lib/src/kernel/element_map_impl.dart b/pkg/compiler/lib/src/kernel/element_map_impl.dart
index cb01960..c8e869a 100644
--- a/pkg/compiler/lib/src/kernel/element_map_impl.dart
+++ b/pkg/compiler/lib/src/kernel/element_map_impl.dart
@@ -800,6 +800,12 @@
   ir.ClassHierarchy get classHierarchy =>
       _classHierarchy ??= ir.ClassHierarchy(env.mainComponent);
 
+  @override
+  ir.StaticTypeContext getStaticTypeContext(MemberEntity member) {
+    // TODO(johnniwinther): Cache the static type context.
+    return new ir.StaticTypeContext(getMemberNode(member), typeEnvironment);
+  }
+
   Dart2jsConstantEvaluator get constantEvaluator {
     return _constantEvaluator ??= new Dart2jsConstantEvaluator(typeEnvironment,
         (ir.LocatedMessage message, List<ir.LocatedMessage> context) {
@@ -1065,13 +1071,14 @@
   }
 
   @override
-  ConstantValue getConstantValue(ir.Expression node,
+  ConstantValue getConstantValue(
+      ir.StaticTypeContext staticTypeContext, ir.Expression node,
       {bool requireConstant: true,
       bool implicitNull: false,
       bool checkCasts: true}) {
     if (node is ir.ConstantExpression) {
-      ir.Constant constant =
-          constantEvaluator.evaluate(node, requireConstant: requireConstant);
+      ir.Constant constant = constantEvaluator.evaluate(staticTypeContext, node,
+          requireConstant: requireConstant);
       if (constant == null) {
         if (requireConstant) {
           throw new UnsupportedError(
@@ -1111,13 +1118,15 @@
   }
 
   /// Converts [annotations] into a list of [ConstantValue]s.
-  List<ConstantValue> getMetadata(List<ir.Expression> annotations) {
+  List<ConstantValue> getMetadata(
+      ir.StaticTypeContext staticTypeContext, List<ir.Expression> annotations) {
     if (annotations.isEmpty) return const <ConstantValue>[];
     List<ConstantValue> metadata = <ConstantValue>[];
     annotations.forEach((ir.Expression node) {
       // We skip the implicit cast checks for metadata to avoid circular
       // dependencies in the js-interop class registration.
-      metadata.add(getConstantValue(node, checkCasts: false));
+      metadata
+          .add(getConstantValue(staticTypeContext, node, checkCasts: false));
     });
     return metadata;
   }
@@ -1417,7 +1426,14 @@
       ImpactData impactData = impactBuilderData.impactData;
       memberData.staticTypes = impactBuilderData.cachedStaticTypes;
       KernelImpactConverter converter = new KernelImpactConverter(
-          this, member, reporter, options, _constantValuefier);
+          this,
+          member,
+          reporter,
+          options,
+          _constantValuefier,
+          // TODO(johnniwinther): Pull the static type context from the cached
+          // static types.
+          new ir.StaticTypeContext(node, typeEnvironment));
       return converter.convert(impactData);
     } else {
       KernelImpactBuilder builder = new KernelImpactBuilder(
@@ -1425,6 +1441,7 @@
           member,
           reporter,
           options,
+          new ir.StaticTypeContext(node, typeEnvironment),
           variableScopeModel,
           annotations,
           _constantValuefier);
diff --git a/pkg/compiler/lib/src/kernel/env.dart b/pkg/compiler/lib/src/kernel/env.dart
index 077aa0a..6496281 100644
--- a/pkg/compiler/lib/src/kernel/env.dart
+++ b/pkg/compiler/lib/src/kernel/env.dart
@@ -10,6 +10,7 @@
 import 'package:kernel/ast.dart' as ir;
 import 'package:kernel/clone.dart';
 import 'package:kernel/type_algebra.dart';
+import 'package:kernel/type_environment.dart' as ir;
 import 'package:collection/collection.dart' show mergeSort; // a stable sort.
 
 import '../common.dart';
@@ -203,7 +204,10 @@
   KLibraryData(this.library);
 
   Iterable<ConstantValue> getMetadata(KernelToElementMapImpl elementMap) {
-    return _metadata ??= elementMap.getMetadata(library.annotations);
+    return _metadata ??= elementMap.getMetadata(
+        new ir.StaticTypeContext.forAnnotations(
+            library, elementMap.typeEnvironment),
+        library.annotations);
   }
 
   Iterable<ImportEntity> getImports(KernelToElementMapImpl elementMap) {
@@ -667,7 +671,10 @@
   @override
   Iterable<ConstantValue> getMetadata(
       covariant KernelToElementMapImpl elementMap) {
-    return _metadata ??= elementMap.getMetadata(node.annotations);
+    return _metadata ??= elementMap.getMetadata(
+        new ir.StaticTypeContext.forAnnotations(
+            node.enclosingLibrary, elementMap.typeEnvironment),
+        node.annotations);
   }
 
   @override
@@ -705,7 +712,9 @@
   @override
   Iterable<ConstantValue> getMetadata(
       covariant KernelToElementMapImpl elementMap) {
-    return _metadata ??= elementMap.getMetadata(node.annotations);
+    return _metadata ??= elementMap.getMetadata(
+        new ir.StaticTypeContext(node, elementMap.typeEnvironment),
+        node.annotations);
   }
 
   @override
diff --git a/pkg/compiler/lib/src/kernel/kernel_impact.dart b/pkg/compiler/lib/src/kernel/kernel_impact.dart
index 4e4571e..ac71d58 100644
--- a/pkg/compiler/lib/src/kernel/kernel_impact.dart
+++ b/pkg/compiler/lib/src/kernel/kernel_impact.dart
@@ -55,12 +55,12 @@
       this.currentMember,
       this.reporter,
       this._options,
+      ir.StaticTypeContext staticTypeContext,
       VariableScopeModel variableScopeModel,
       this._annotations,
       this._constantValuefier)
       : this.impactBuilder = new ResolutionWorldImpactBuilder(currentMember),
-        super(elementMap.typeEnvironment, elementMap.classHierarchy,
-            variableScopeModel);
+        super(staticTypeContext, elementMap.classHierarchy, variableScopeModel);
 
   @override
   CommonElements get commonElements => elementMap.commonElements;
@@ -91,9 +91,11 @@
   final MemberEntity currentMember;
   @override
   final ConstantValuefier _constantValuefier;
+  @override
+  final ir.StaticTypeContext staticTypeContext;
 
   KernelImpactConverter(this.elementMap, this.currentMember, this.reporter,
-      this._options, this._constantValuefier)
+      this._options, this._constantValuefier, this.staticTypeContext)
       : this.impactBuilder = new ResolutionWorldImpactBuilder(currentMember);
 
   @override
@@ -125,6 +127,7 @@
   CommonElements get commonElements;
   NativeBasicData get _nativeBasicData;
   ConstantValuefier get _constantValuefier;
+  ir.StaticTypeContext get staticTypeContext;
 
   Object _computeReceiverConstraint(
       ir.DartType receiverType, ClassRelation relation) {
@@ -142,7 +145,7 @@
   @override
   void registerParameterCheck(ir.DartType irType) {
     DartType type = elementMap.getDartType(irType);
-    if (!type.isDynamic) {
+    if (type is! DynamicType) {
       impactBuilder.registerTypeUse(new TypeUse.parameterCheck(type));
     }
   }
@@ -355,8 +358,8 @@
     assert(node.isConst);
     ConstructorEntity constructor = elementMap.getConstructor(node.target);
     if (commonElements.isSymbolConstructor(constructor)) {
-      ConstantValue value =
-          elementMap.getConstantValue(node.arguments.positional.first);
+      ConstantValue value = elementMap.getConstantValue(
+          staticTypeContext, node.arguments.positional.first);
       if (!value.isString) {
         // TODO(het): Get the actual span for the Symbol constructor argument
         reporter.reportErrorMessage(
@@ -856,7 +859,8 @@
 
     for (ir.SwitchCase switchCase in node.cases) {
       for (ir.Expression expression in switchCase.expressions) {
-        ConstantValue value = elementMap.getConstantValue(expression);
+        ConstantValue value =
+            elementMap.getConstantValue(staticTypeContext, expression);
         DartType type = value.getType(elementMap.commonElements);
         if (firstCaseType == null) {
           firstCase = expression;
diff --git a/pkg/compiler/lib/src/kernel/kernel_strategy.dart b/pkg/compiler/lib/src/kernel/kernel_strategy.dart
index 80ea69f..642120d 100644
--- a/pkg/compiler/lib/src/kernel/kernel_strategy.dart
+++ b/pkg/compiler/lib/src/kernel/kernel_strategy.dart
@@ -5,6 +5,7 @@
 library dart2js.kernel.frontend_strategy;
 
 import 'package:kernel/ast.dart' as ir;
+import 'package:kernel/type_environment.dart' as ir;
 
 import '../common.dart';
 import '../common/backend_api.dart';
@@ -457,8 +458,10 @@
       // depend on metadata, so these parts of the impact data need to be
       // computed during conversion to [ResolutionImpact].
       impactBuilderData = _compilerTask.measureSubtask('worldImpact', () {
-        ImpactBuilder builder = new ImpactBuilder(_elementMap.typeEnvironment,
-            _elementMap.classHierarchy, scopeModel.variableScopeModel,
+        ImpactBuilder builder = new ImpactBuilder(
+            new ir.StaticTypeContext(node, _elementMap.typeEnvironment),
+            _elementMap.classHierarchy,
+            scopeModel.variableScopeModel,
             useAsserts: _elementMap.options.enableUserAssertions,
             inferEffectivelyFinalVariableTypes:
                 !annotations.contains(PragmaAnnotation.disableFinal));
diff --git a/pkg/compiler/lib/src/kernel/no_such_method_resolver.dart b/pkg/compiler/lib/src/kernel/no_such_method_resolver.dart
index c57d9e1..32f6721 100644
--- a/pkg/compiler/lib/src/kernel/no_such_method_resolver.dart
+++ b/pkg/compiler/lib/src/kernel/no_such_method_resolver.dart
@@ -9,8 +9,6 @@
 
   KernelNoSuchMethodResolver(this.elementMap);
 
-  ElementEnvironment get _elementEnvironment => elementMap.elementEnvironment;
-
   CommonElements get _commonElements => elementMap.commonElements;
 
   @override
diff --git a/pkg/compiler/lib/src/native/behavior.dart b/pkg/compiler/lib/src/native/behavior.dart
index b97e294..0e2aa4b 100644
--- a/pkg/compiler/lib/src/native/behavior.dart
+++ b/pkg/compiler/lib/src/native/behavior.dart
@@ -815,7 +815,7 @@
         }
 
         if (!trustJSInteropTypeAnnotations ||
-            type.isDynamic ||
+            type is DynamicType ||
             type == commonElements.objectType) {
           // By saying that only JS-interop types can be created, we prevent
           // pulling in every other native type (e.g. all of dart:html) when a
@@ -882,7 +882,7 @@
     _behavior.typesReturned.add(!isJsInterop || trustJSInteropTypeAnnotations
         ? returnType
         : commonElements.dynamicType);
-    if (!type.returnType.isVoid) {
+    if (type.returnType is! VoidType) {
       // Declared types are nullable.
       _behavior.typesReturned.add(commonElements.nullType);
     }
diff --git a/pkg/compiler/lib/src/native/enqueue.dart b/pkg/compiler/lib/src/native/enqueue.dart
index 766bfa0..e08baad 100644
--- a/pkg/compiler/lib/src/native/enqueue.dart
+++ b/pkg/compiler/lib/src/native/enqueue.dart
@@ -132,7 +132,7 @@
           InterfaceType specType = _elementEnvironment.getRawType(type.element);
           return _dartTypes.isSubtype(nativeType, specType);
         }));
-      } else if (type.isDynamic) {
+      } else if (type is DynamicType) {
         matchingClasses.addAll(_unusedClasses);
       } else {
         assert(type is VoidType, '$type was ${type.runtimeType}');
diff --git a/pkg/compiler/lib/src/serialization/abstract_source.dart b/pkg/compiler/lib/src/serialization/abstract_source.dart
index c98787d..51cd928 100644
--- a/pkg/compiler/lib/src/serialization/abstract_source.dart
+++ b/pkg/compiler/lib/src/serialization/abstract_source.dart
@@ -187,6 +187,12 @@
     switch (kind) {
       case DartTypeKind.none:
         return null;
+      case DartTypeKind.legacyType:
+        return LegacyType(_readDartType(functionTypeVariables));
+      case DartTypeKind.nullableType:
+        return NullableType(_readDartType(functionTypeVariables));
+      case DartTypeKind.neverType:
+        return NeverType();
       case DartTypeKind.voidType:
         return VoidType();
       case DartTypeKind.typeVariable:
diff --git a/pkg/compiler/lib/src/serialization/helpers.dart b/pkg/compiler/lib/src/serialization/helpers.dart
index 13b0a7f..8d73694 100644
--- a/pkg/compiler/lib/src/serialization/helpers.dart
+++ b/pkg/compiler/lib/src/serialization/helpers.dart
@@ -89,6 +89,9 @@
 /// Enum used for identifying [DartType] subclasses in serialization.
 enum DartTypeKind {
   none,
+  legacyType,
+  nullableType,
+  neverType,
   voidType,
   typeVariable,
   functionTypeVariable,
@@ -122,6 +125,26 @@
   }
 
   @override
+  void visitLegacyType(covariant LegacyType type,
+      List<FunctionTypeVariable> functionTypeVariables) {
+    _sink.writeEnum(DartTypeKind.legacyType);
+    _sink._writeDartType(type.baseType, functionTypeVariables);
+  }
+
+  @override
+  void visitNullableType(covariant NullableType type,
+      List<FunctionTypeVariable> functionTypeVariables) {
+    _sink.writeEnum(DartTypeKind.nullableType);
+    _sink._writeDartType(type.baseType, functionTypeVariables);
+  }
+
+  @override
+  void visitNeverType(covariant NeverType type,
+      List<FunctionTypeVariable> functionTypeVariables) {
+    _sink.writeEnum(DartTypeKind.neverType);
+  }
+
+  @override
   void visitVoidType(covariant VoidType type,
       List<FunctionTypeVariable> functionTypeVariables) {
     _sink.writeEnum(DartTypeKind.voidType);
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index 0688ba9..b696a67 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -1488,8 +1488,8 @@
             _elementMap);
         HInstruction newParameter = localsHandler.directLocals[local];
         DartType bound = _getDartTypeIfValid(typeParameter.bound);
-        if (!bound.isDynamic &&
-            !bound.isVoid &&
+        if (bound is! DynamicType &&
+            bound is! VoidType &&
             bound != _commonElements.objectType) {
           if (options.experimentNewRti) {
             _checkTypeBound(newParameter, bound, local.name);
@@ -5525,7 +5525,7 @@
   /// Returns `true` if the checking of [type] is performed directly on the
   /// object and not on an interceptor.
   bool _hasDirectCheckFor(DartType type) {
-    if (!type.isInterfaceType) return false;
+    if (type is! InterfaceType) return false;
     InterfaceType interfaceType = type;
     ClassEntity element = interfaceType.element;
     return element == _commonElements.stringClass ||
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index ee72ee8..856e4fc 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -390,10 +390,10 @@
         new SsaInstructionSelection(_options, _closedWorld, _interceptorData));
     runPhase(new SsaTypeKnownRemover());
     runPhase(new SsaTrustedCheckRemover(_options));
-    runPhase(new SsaAssignmentChaining(_options, _closedWorld));
+    runPhase(new SsaAssignmentChaining(_closedWorld));
     runPhase(new SsaInstructionMerger(_abstractValueDomain, generateAtUseSite));
     runPhase(new SsaConditionMerger(generateAtUseSite, controlFlowOperators));
-    runPhase(new SsaShareRegionConstants(_options));
+    runPhase(new SsaShareRegionConstants());
 
     SsaLiveIntervalBuilder intervalBuilder =
         new SsaLiveIntervalBuilder(generateAtUseSite, controlFlowOperators);
@@ -2891,7 +2891,7 @@
   void checkType(HInstruction input, HInstruction interceptor, DartType type,
       SourceInformation sourceInformation,
       {bool negative: false}) {
-    if (type.isInterfaceType) {
+    if (type is InterfaceType) {
       InterfaceType interfaceType = type;
       ClassEntity element = interfaceType.element;
       if (element == _commonElements.jsArrayClass) {
@@ -3102,7 +3102,7 @@
           _commonElements.isListSupertype(element)) {
         handleListOrSupertypeCheck(input, interceptor, type, sourceInformation,
             negative: negative);
-      } else if (type.isFunctionType) {
+      } else if (type is FunctionType) {
         checkType(input, interceptor, type, sourceInformation,
             negative: negative);
       } else if ((input.isPrimitive(_abstractValueDomain).isPotentiallyTrue &&
@@ -3133,10 +3133,10 @@
   void visitTypeConversion(HTypeConversion node) {
     assert(node.isTypeCheck || node.isCastCheck);
     DartType type = node.typeExpression;
-    assert(!type.isTypedef);
-    assert(!type.isDynamic);
-    assert(!type.isVoid);
-    if (type.isFunctionType) {
+    assert(type is! TypedefType);
+    assert(type is! DynamicType);
+    assert(type is! VoidType);
+    if (type is FunctionType) {
       // TODO(5022): We currently generate $isFunction checks for
       // function types.
       _registry
@@ -3546,7 +3546,7 @@
     TypeRecipe typeExpression = node.typeExpression;
     if (envStructure is FullTypeEnvironmentStructure &&
         typeExpression is TypeExpressionRecipe) {
-      if (typeExpression.type.isTypeVariable) {
+      if (typeExpression.type is TypeVariableType) {
         TypeVariableType type = typeExpression.type;
         int index = indexTypeVariable(
             _closedWorld, _rtiSubstitutions, envStructure, type);
diff --git a/pkg/compiler/lib/src/ssa/codegen_helpers.dart b/pkg/compiler/lib/src/ssa/codegen_helpers.dart
index a3c4af4..b984e4b 100644
--- a/pkg/compiler/lib/src/ssa/codegen_helpers.dart
+++ b/pkg/compiler/lib/src/ssa/codegen_helpers.dart
@@ -443,10 +443,8 @@
 ///     b.y = a.x = v;
 class SsaAssignmentChaining extends HBaseVisitor with CodegenPhase {
   final JClosedWorld _closedWorld;
-  final CompilerOptions _options;
-  //HGraph graph;
 
-  SsaAssignmentChaining(this._options, this._closedWorld);
+  SsaAssignmentChaining(this._closedWorld);
 
   AbstractValueDomain get _abstractValueDomain =>
       _closedWorld.abstractValueDomain;
@@ -1114,9 +1112,7 @@
 /// name would be shorter than repeated references.  These are caches for 'this'
 /// and constant values.
 class SsaShareRegionConstants extends HBaseVisitor with CodegenPhase {
-  final CompilerOptions _options;
-
-  SsaShareRegionConstants(this._options);
+  SsaShareRegionConstants();
 
   @override
   visitGraph(HGraph graph) {
diff --git a/pkg/compiler/lib/src/ssa/nodes.dart b/pkg/compiler/lib/src/ssa/nodes.dart
index 90297a2..edbcb67 100644
--- a/pkg/compiler/lib/src/ssa/nodes.dart
+++ b/pkg/compiler/lib/src/ssa/nodes.dart
@@ -1404,16 +1404,16 @@
     // Only the builder knows how to create [HTypeConversion]
     // instructions with generics. It has the generic type context
     // available.
-    assert(!type.isTypeVariable);
-    assert(type.treatAsRaw || type.isFunctionType);
-    if (type.isDynamic) return this;
-    if (type.isVoid) return this;
+    assert(type is! TypeVariableType);
+    assert(type.treatAsRaw || type is FunctionType);
+    if (type is DynamicType) return this;
+    if (type is VoidType) return this;
     if (type == closedWorld.commonElements.objectType) return this;
-    if (type.isFunctionType || type.isFutureOr) {
+    if (type is FunctionType || type is FutureOrType) {
       return new HTypeConversion(type, kind,
           closedWorld.abstractValueDomain.dynamicType, this, sourceInformation);
     }
-    assert(type.isInterfaceType);
+    assert(type is InterfaceType);
     if (kind == HTypeConversion.TYPE_CHECK && !type.treatAsRaw) {
       throw 'creating compound check to $type (this = ${this})';
     } else {
@@ -3427,7 +3427,7 @@
     // TODO(sigmund): re-add `&& typeExpression.treatAsRaw` or something
     // equivalent (which started failing once we allowed typeExpressions that
     // contain type parameters matching the original bounds of the type).
-    assert((typeExpression.isFunctionType || typeExpression.isInterfaceType),
+    assert((typeExpression is FunctionType || typeExpression is InterfaceType),
         "Unexpected raw is-test type: $typeExpression");
     return new HIs.internal(typeExpression, [expression, interceptor],
         RAW_CHECK, type, sourceInformation);
@@ -3554,7 +3554,7 @@
       HInstruction input, SourceInformation sourceInformation)
       : checkedType = type,
         super(<HInstruction>[input], type) {
-    assert(typeExpression == null || !typeExpression.isTypedef);
+    assert(typeExpression == null || typeExpression is! TypedefType);
     this.sourceElement = input.sourceElement;
     this.sourceInformation = sourceInformation;
   }
@@ -3563,13 +3563,13 @@
       AbstractValue type, HInstruction input, HInstruction typeRepresentation)
       : checkedType = type,
         super(<HInstruction>[input, typeRepresentation], type) {
-    assert(!typeExpression.isTypedef);
+    assert(typeExpression is! TypedefType);
     sourceElement = input.sourceElement;
   }
 
   bool get hasTypeRepresentation {
     return typeExpression != null &&
-        typeExpression.isInterfaceType &&
+        typeExpression is InterfaceType &&
         inputs.length > 1;
   }
 
@@ -3615,10 +3615,10 @@
     AbstractValueDomain abstractValueDomain = closedWorld.abstractValueDomain;
     DartType type = typeExpression;
     if (type != null) {
-      if (type.isTypeVariable) {
+      if (type is TypeVariableType) {
         return false;
       }
-      if (type.isFutureOr) {
+      if (type is FutureOrType) {
         // `null` always passes type conversion.
         if (checkedInput.isNull(abstractValueDomain).isDefinitelyTrue) {
           return true;
@@ -3633,7 +3633,7 @@
         }
         return false;
       }
-      if (type.isFunctionType) {
+      if (type is FunctionType) {
         // `null` always passes type conversion.
         if (checkedInput.isNull(abstractValueDomain).isDefinitelyTrue) {
           return true;
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
index 2f69165..8c27840 100644
--- a/pkg/compiler/lib/src/ssa/optimize.dart
+++ b/pkg/compiler/lib/src/ssa/optimize.dart
@@ -852,7 +852,7 @@
       if (!canInline) return;
       if (inputPosition >= inputs.length) return;
       HInstruction input = inputs[inputPosition++];
-      if (parameterType.unaliased.isFunctionType) {
+      if (parameterType.unaliased is FunctionType) {
         // Must call the target since it contains a function conversion.
         canInline = false;
         return;
@@ -1093,11 +1093,11 @@
 
     if (!node.isRawCheck) {
       return node;
-    } else if (type.isTypedef) {
+    } else if (type is TypedefType) {
       return node;
-    } else if (type.isFunctionType) {
+    } else if (type is FunctionType) {
       return node;
-    } else if (type.isFutureOr) {
+    } else if (type is FutureOrType) {
       return node;
     }
 
@@ -1174,7 +1174,7 @@
           rep.kind == TypeInfoExpressionKind.COMPLETE &&
           rep.inputs.isEmpty) {
         DartType type = rep.dartType;
-        if (type.isInterfaceType && type.treatAsRaw) {
+        if (type is InterfaceType && type.treatAsRaw) {
           return node.checkedInput.convertType(_closedWorld, type, node.kind)
             ..sourceInformation = node.sourceInformation;
         }
@@ -1427,9 +1427,9 @@
     }
 
     if (!fieldType.treatAsRaw ||
-        fieldType.isTypeVariable ||
-        fieldType.unaliased.isFunctionType ||
-        fieldType.unaliased.isFutureOr) {
+        fieldType is TypeVariableType ||
+        fieldType.unaliased is FunctionType ||
+        fieldType.unaliased is FutureOrType) {
       // We cannot generate the correct type representation here, so don't
       // inline this access.
       // TODO(sra): If the input is such that we don't need a type check, we
@@ -3155,9 +3155,9 @@
     DartType type = instruction.typeExpression;
     if (!instruction.isRawCheck) {
       return;
-    } else if (type.isTypedef) {
+    } else if (type is TypedefType) {
       return;
-    } else if (type.isFutureOr) {
+    } else if (type is FutureOrType) {
       return;
     }
     InterfaceType interfaceType = type;
diff --git a/pkg/compiler/lib/src/ssa/type_builder.dart b/pkg/compiler/lib/src/ssa/type_builder.dart
index 0b77dbd..06429cf 100644
--- a/pkg/compiler/lib/src/ssa/type_builder.dart
+++ b/pkg/compiler/lib/src/ssa/type_builder.dart
@@ -53,8 +53,8 @@
     if (type == null) return null;
     type = builder.localsHandler.substInContext(type);
     type = type.unaliased;
-    if (type.isDynamic) return null;
-    if (!type.isInterfaceType) return null;
+    if (type is DynamicType) return null;
+    if (type is! InterfaceType) return null;
     if (type == _closedWorld.commonElements.objectType) return null;
     // The type element is either a class or the void element.
     ClassEntity element = (type as InterfaceType).element;
@@ -229,10 +229,10 @@
   HInstruction buildTypeArgumentRepresentations(
       DartType type, MemberEntity sourceElement,
       [SourceInformation sourceInformation]) {
-    assert(!type.isTypeVariable);
+    assert(type is! TypeVariableType);
     // Compute the representation of the type arguments, including access
     // to the runtime type information for type variables as instructions.
-    assert(type.isInterfaceType);
+    assert(type is InterfaceType);
     InterfaceType interface = type;
     List<HInstruction> inputs = <HInstruction>[];
     for (DartType argument in interface.typeArguments) {
@@ -261,7 +261,7 @@
       return builder.graph.addConstantNull(_closedWorld);
     }
 
-    if (argument.isTypeVariable) {
+    if (argument is TypeVariableType) {
       return addTypeVariableReference(argument, sourceElement,
           sourceInformation: sourceInformation);
     }
@@ -433,7 +433,7 @@
 
     if (type == null) return original;
     type = type.unaliased;
-    if (type.isInterfaceType && !type.treatAsRaw) {
+    if (type is InterfaceType && !type.treatAsRaw) {
       InterfaceType interfaceType = type;
       AbstractValue subtype =
           _abstractValueDomain.createNullableSubtype(interfaceType.element);
@@ -443,14 +443,14 @@
       return new HTypeConversion.withTypeRepresentation(
           type, kind, subtype, original, representations)
         ..sourceInformation = sourceInformation;
-    } else if (type.isTypeVariable) {
+    } else if (type is TypeVariableType) {
       AbstractValue subtype = original.instructionType;
       HInstruction typeVariable =
           addTypeVariableReference(type, builder.sourceElement);
       return new HTypeConversion.withTypeRepresentation(
           type, kind, subtype, original, typeVariable)
         ..sourceInformation = sourceInformation;
-    } else if (type.isFunctionType || type.isFutureOr) {
+    } else if (type is FunctionType || type is FutureOrType) {
       HInstruction reifiedType =
           analyzeTypeArgument(type, builder.sourceElement);
       // TypeMasks don't encode function types or FutureOr types.
@@ -473,8 +473,8 @@
     if (type == null) return original;
     type = type.unaliased;
 
-    if (type.isDynamic) return original;
-    if (type.isVoid) return original;
+    if (type is DynamicType) return original;
+    if (type is VoidType) return original;
     if (type == _closedWorld.commonElements.objectType) return original;
 
     HInstruction reifiedType = analyzeTypeArgumentNewRti(
diff --git a/pkg/compiler/lib/src/ssa/types.dart b/pkg/compiler/lib/src/ssa/types.dart
index 1795329..201fca6 100644
--- a/pkg/compiler/lib/src/ssa/types.dart
+++ b/pkg/compiler/lib/src/ssa/types.dart
@@ -4,6 +4,7 @@
 
 import '../common_elements.dart' show CommonElements;
 import '../elements/entities.dart';
+import '../elements/types.dart';
 import '../inferrer/abstract_value_domain.dart';
 import '../inferrer/types.dart';
 import '../native/behavior.dart';
@@ -49,9 +50,9 @@
       if (type == SpecialType.JsObject) {
         return abstractValueDomain
             .createNonNullExact(commonElements.objectClass);
-      } else if (type.isVoid) {
+      } else if (type is VoidType) {
         return abstractValueDomain.nullType;
-      } else if (type.isDynamic) {
+      } else if (type is DynamicType) {
         return abstractValueDomain.dynamicType;
       } else if (type == commonElements.nullType) {
         return abstractValueDomain.nullType;
diff --git a/pkg/compiler/lib/src/universe/codegen_world_builder.dart b/pkg/compiler/lib/src/universe/codegen_world_builder.dart
index 64e22df..59b416e 100644
--- a/pkg/compiler/lib/src/universe/codegen_world_builder.dart
+++ b/pkg/compiler/lib/src/universe/codegen_world_builder.dart
@@ -808,20 +808,6 @@
     _invokedSetters.forEach(f);
   }
 
-  bool _hasMatchingSelector(Map<Selector, SelectorConstraints> selectors,
-      MemberEntity member, JClosedWorld world) {
-    if (selectors == null) return false;
-    for (Selector selector in selectors.keys) {
-      if (selector.appliesUnnamed(member)) {
-        SelectorConstraints masks = selectors[selector];
-        if (masks.canHit(member, selector.memberName, world)) {
-          return true;
-        }
-      }
-    }
-    return false;
-  }
-
   @override
   bool hasInvokedGetter(MemberEntity member) {
     MemberUsage memberUsage = _liveMemberUsage[member];
diff --git a/pkg/dart2native/bin/dart2native.dart b/pkg/dart2native/bin/dart2native.dart
index 121aad1..826290e1 100644
--- a/pkg/dart2native/bin/dart2native.dart
+++ b/pkg/dart2native/bin/dart2native.dart
@@ -21,6 +21,8 @@
     path.join(binDir, 'utils', 'gen_snapshot${executableSuffix}');
 final String platformDill =
     path.join(sdkDir, 'lib', '_internal', 'vm_platform_strong.dill');
+final String productPlatformDill =
+    path.join(sdkDir, 'lib', '_internal', 'vm_platform_strong_product.dill');
 
 Future<void> generateNative(
     Kind kind,
@@ -40,8 +42,21 @@
     if (verbose) {
       print('Generating AOT kernel dill.');
     }
-    final kernelResult = await generateAotKernel(dart, genKernel, platformDill,
-        sourceFile, kernelFile, packages, defines);
+
+    // Prefer to use the product platform file, if available. Fall back to the
+    // normal one (this happens if `out/<build-dir>/dart-sdk` is used).
+    //
+    // Background information: For the `dart-sdk` we distribute we build release
+    // and product mode configurations. Then we have an extra bundling step
+    // which will add product-mode
+    // gen_snapshot/dartaotruntime/vm_platform_strong_product.dill to the
+    // release SDK (see tools/bots/dart_sdk.py:CopyAotBinaries)
+    final String platformFileToUse = File(productPlatformDill).existsSync()
+        ? productPlatformDill
+        : platformDill;
+
+    final kernelResult = await generateAotKernel(dart, genKernel,
+        platformFileToUse, sourceFile, kernelFile, packages, defines);
     if (kernelResult.exitCode != 0) {
       stderr.writeln(kernelResult.stdout);
       stderr.writeln(kernelResult.stderr);
diff --git a/pkg/dartfix/CHANGELOG.md b/pkg/dartfix/CHANGELOG.md
index 3a8048b..de84535 100644
--- a/pkg/dartfix/CHANGELOG.md
+++ b/pkg/dartfix/CHANGELOG.md
@@ -1,3 +1,6 @@
+# 0.1.6
+* Improve experimental non-nullable migration support.
+
 # 0.1.5
 * Add command line options for selecting/excluding fixes to apply (`--fix`,
   `--excludeFix`, and `--required`). Call with `--help` for more details.
diff --git a/pkg/dartfix/README.md b/pkg/dartfix/README.md
index 43ed757..245ac92 100644
--- a/pkg/dartfix/README.md
+++ b/pkg/dartfix/README.md
@@ -72,7 +72,7 @@
 and star the fixes you want.
 If no issue exists for the fix, [create a GitHub issue.][new issue]
 
-[dartfix]: https://pub.dartlang.org/packages/dartfix
+[dartfix]: https://pub.dev/packages/dartfix
 [dartfmt]: https://www.dartlang.org/tools/dartfmt
 [added in Dart in 2.1]: https://github.com/dart-lang/sdk/blob/master/CHANGELOG.md#210---2018-11-15
 [features added to Dart in 2.1]: https://github.com/dart-lang/sdk/blob/master/CHANGELOG.md#210---2018-11-15
diff --git a/pkg/dartfix/pubspec.yaml b/pkg/dartfix/pubspec.yaml
index b895769..1ad071e 100644
--- a/pkg/dartfix/pubspec.yaml
+++ b/pkg/dartfix/pubspec.yaml
@@ -1,5 +1,5 @@
 name: dartfix
-version: 0.1.5
+version: 0.1.6
 author: Dart Team <misc@dartlang.org>
 description:
   A tool for migrating Dart source to newer versions of the Dart SDK
diff --git a/pkg/dev_compiler/lib/src/analyzer/code_generator.dart b/pkg/dev_compiler/lib/src/analyzer/code_generator.dart
index 75ce561..d698b73 100644
--- a/pkg/dev_compiler/lib/src/analyzer/code_generator.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/code_generator.dart
@@ -21,7 +21,7 @@
     show DartObject, DartObjectImpl;
 import 'package:analyzer/src/generated/resolver.dart'
     show TypeProvider, NamespaceBuilder;
-import 'package:analyzer/src/generated/type_system.dart' show Dart2TypeSystem;
+import 'package:analyzer/src/generated/type_system.dart' show TypeSystemImpl;
 import 'package:analyzer/src/summary/package_bundle_reader.dart';
 import 'package:analyzer/src/task/strong/ast_properties.dart';
 import 'package:path/path.dart' as p;
@@ -74,7 +74,7 @@
   final SummaryDataStore summaryData;
 
   final CompilerOptions options;
-  final Dart2TypeSystem rules;
+  final TypeSystemImpl rules;
 
   /// Errors that were produced during compilation, if any.
   final ErrorCollector errors;
@@ -196,7 +196,12 @@
 
   CodeGenerator(LinkedAnalysisDriver driver, this.types, this.summaryData,
       this.options, this._extensionTypes, this.errors)
-      : rules = Dart2TypeSystem(types),
+      : rules = TypeSystemImpl(
+          implicitCasts: true,
+          isNonNullableByDefault: false,
+          strictInference: false,
+          typeProvider: types,
+        ),
         declaredVariables = driver.declaredVariables,
         _asyncStreamIterator = getLegacyRawClassType(
             driver.getClass('dart:async', 'StreamIterator')),
@@ -4879,7 +4884,7 @@
     variable ??= js_ast.TemporaryId(name);
 
     var idElement =
-        TemporaryVariableElement.forNode(id, variable, _currentElement);
+        TemporaryVariableElement(name, -1, variable, _currentElement);
     id.staticElement = idElement;
     id.staticType = type;
     setIsDynamicInvoke(id, dynamicInvoke ?? type.isDynamic);
@@ -6687,9 +6692,9 @@
 class TemporaryVariableElement extends LocalVariableElementImpl {
   final js_ast.Expression jsVariable;
 
-  TemporaryVariableElement.forNode(
-      Identifier name, this.jsVariable, Element enclosingElement)
-      : super.forNode(name) {
+  TemporaryVariableElement(
+      String name, int offset, this.jsVariable, Element enclosingElement)
+      : super(name, offset) {
     this.enclosingElement = enclosingElement;
   }
 
diff --git a/pkg/dev_compiler/lib/src/analyzer/element_helpers.dart b/pkg/dev_compiler/lib/src/analyzer/element_helpers.dart
index ee256ec..c1f9a92 100644
--- a/pkg/dev_compiler/lib/src/analyzer/element_helpers.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/element_helpers.dart
@@ -14,7 +14,7 @@
 import 'package:analyzer/src/generated/constant.dart'
     show DartObject, DartObjectImpl;
 import 'package:analyzer/src/generated/constant.dart';
-import 'package:analyzer/src/generated/type_system.dart' show Dart2TypeSystem;
+import 'package:analyzer/src/generated/type_system.dart' show TypeSystemImpl;
 
 import 'type_utilities.dart';
 
@@ -48,7 +48,7 @@
 /// `element.type`, but unfortunately typedef elements do not return a
 /// meaningful type, so we need to work around that.
 DartType instantiateElementTypeToBounds(
-    Dart2TypeSystem rules, TypeDefiningElement element) {
+    TypeSystemImpl rules, TypeDefiningElement element) {
   if (element is TypeParameterizedElement) {
     if (element is ClassElement) {
       var typeArguments = rules.instantiateTypeFormalsToBounds2(element);
diff --git a/pkg/dev_compiler/lib/src/analyzer/js_typerep.dart b/pkg/dev_compiler/lib/src/analyzer/js_typerep.dart
index c24e5f5..aa62632 100644
--- a/pkg/dev_compiler/lib/src/analyzer/js_typerep.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/js_typerep.dart
@@ -5,14 +5,14 @@
 import 'package:analyzer/dart/element/element.dart' show ClassElement;
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
-import 'package:analyzer/src/generated/type_system.dart' show Dart2TypeSystem;
+import 'package:analyzer/src/generated/type_system.dart' show TypeSystemImpl;
 
 import '../compiler/js_typerep.dart';
 import 'driver.dart';
 import 'type_utilities.dart';
 
 class JSTypeRep extends SharedJSTypeRep<DartType> {
-  final Dart2TypeSystem rules;
+  final TypeSystemImpl rules;
   final TypeProvider types;
 
   final ClassElement _jsBool;
diff --git a/pkg/dev_compiler/lib/src/analyzer/module_compiler.dart b/pkg/dev_compiler/lib/src/analyzer/module_compiler.dart
index 3f4cd73..d639be6 100644
--- a/pkg/dev_compiler/lib/src/analyzer/module_compiler.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/module_compiler.dart
@@ -314,23 +314,9 @@
     String mapPath = jsPath + '.map';
     var code = getCode(
         format, p.toUri(jsPath).toString(), p.toUri(mapPath).toString());
-    var c = code.code;
-    if (format == ModuleFormat.amdConcat ||
-        format == ModuleFormat.legacyConcat) {
-      // In single-out-file mode we wrap each module in an eval statement to
-      // leverage sourceURL to improve the debugging experience when source maps
-      // are not enabled.
-      //
-      // Note: We replace all `/` with `.` so that we don't break relative urls
-      // to sources in the original sourcemap. The name of this file is bogus
-      // anyways, so it has very little effect on things.
-      c += '\n//# sourceURL=${name.replaceAll("/", ".")}.js\n';
-      c = 'eval(${json.encode(c)});\n';
-    }
-
     var file = File(jsPath);
     if (!file.parent.existsSync()) file.parent.createSync(recursive: true);
-    file.writeAsStringSync(c);
+    file.writeAsStringSync(code.code);
 
     // TODO(jacobr): it is a bit strange we are writing the source map to a file
     // even when options.inlineSourceMap is true. To be consistent perhaps we
diff --git a/pkg/dev_compiler/lib/src/compiler/module_builder.dart b/pkg/dev_compiler/lib/src/compiler/module_builder.dart
index ec1ea4a..8ac6e20 100644
--- a/pkg/dev_compiler/lib/src/compiler/module_builder.dart
+++ b/pkg/dev_compiler/lib/src/compiler/module_builder.dart
@@ -3,7 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:args/args.dart' show ArgParser, ArgResults;
-import 'package:args/command_runner.dart' show UsageException;
 import 'package:path/path.dart' as p;
 
 import '../js_ast/js_ast.dart';
@@ -20,14 +19,8 @@
   /// Asynchronous Module Definition (AMD, used in browsers).
   amd,
 
-  /// Dart Dev Compiler's legacy format (deprecated).
-  legacy,
-
-  /// Like [amd] but can be concatenated into a single file.
-  amdConcat,
-
-  /// Like [legacy] but can be concatenated into a single file.
-  legacyConcat
+  /// Dart Dev Compiler's own format.
+  ddc,
 }
 
 /// Parses a string into a [ModuleFormat].
@@ -35,35 +28,15 @@
       'es6': ModuleFormat.es6,
       'common': ModuleFormat.common,
       'amd': ModuleFormat.amd,
+      'ddc': ModuleFormat.ddc,
       // Deprecated:
       'node': ModuleFormat.common,
-      'legacy': ModuleFormat.legacy
+      'legacy': ModuleFormat.ddc
     }[s];
 
 /// Parse the module format option added by [addModuleFormatOptions].
 List<ModuleFormat> parseModuleFormatOption(ArgResults args) {
-  var formats =
-      (args['modules'] as List<String>).map(parseModuleFormat).toList();
-
-  if (args['single-out-file'] as bool) {
-    for (int i = 0; i < formats.length; i++) {
-      var format = formats[i];
-      switch (formats[i]) {
-        case ModuleFormat.amd:
-          formats[i] = ModuleFormat.amdConcat;
-          break;
-        case ModuleFormat.legacy:
-          formats[i] = ModuleFormat.legacyConcat;
-          break;
-        default:
-          throw UsageException(
-              'Format $format cannot be combined with '
-                  'single-out-file. Only amd and legacy modes are supported.',
-              '');
-      }
-    }
-  }
-  return formats;
+  return (args['modules'] as List<String>).map(parseModuleFormat).toList();
 }
 
 /// Adds an option to the [argParser] for choosing the module format, optionally
@@ -74,7 +47,8 @@
     'es6',
     'common',
     'amd',
-    'legacy', // deprecated
+    'ddc',
+    'legacy', // renamed to ddc
     'node', // renamed to commonjs
     'all' // to emit all flavors for the SDK
   ], allowedHelp: {
@@ -84,12 +58,6 @@
   }, defaultsTo: [
     'amd'
   ]);
-
-  argParser.addFlag('single-out-file',
-      help: 'emit modules that can be concatenated into one file.\n'
-          'Only compatible with legacy and amd module formats.',
-      defaultsTo: false,
-      hide: hide);
 }
 
 /// Transforms an ES6 [module] into a given module [format].
@@ -102,16 +70,12 @@
 /// [ExportDeclaration]s.
 Program transformModuleFormat(ModuleFormat format, Program module) {
   switch (format) {
-    case ModuleFormat.legacy:
-    case ModuleFormat.legacyConcat:
-      // Legacy format always generates output compatible with single file mode.
-      return LegacyModuleBuilder().build(module);
+    case ModuleFormat.ddc:
+      return DdcModuleBuilder().build(module);
     case ModuleFormat.common:
       return CommonJSModuleBuilder().build(module);
     case ModuleFormat.amd:
       return AmdModuleBuilder().build(module);
-    case ModuleFormat.amdConcat:
-      return AmdModuleBuilder(singleOutFile: true).build(module);
     case ModuleFormat.es6:
     default:
       return module;
@@ -161,9 +125,9 @@
   }
 }
 
-/// Generates modules for with our legacy `dart_library.js` loading mechanism.
+/// Generates modules for with our DDC `dart_library.js` loading mechanism.
 // TODO(jmesserly): remove this and replace with something that interoperates.
-class LegacyModuleBuilder extends _ModuleBuilder {
+class DdcModuleBuilder extends _ModuleBuilder {
   Program build(Program module) {
     // Collect imports/exports/statements.
     visitProgram(module);
@@ -180,7 +144,8 @@
           TemporaryId(pathToJSIdentifier(import.from.valueWithoutQuotes));
       parameters.add(moduleVar);
       for (var importName in import.namedImports) {
-        assert(!importName.isStar); // import * not supported in legacy modules.
+        assert(!importName
+            .isStar); // import * not supported in ddc format modules.
         var asName = importName.asName ?? importName.name;
         var fromName = importName.name.name;
         // Load non-SDK modules on demand (i.e., deferred).
@@ -204,7 +169,7 @@
       // TODO(jmesserly): make these immutable in JS?
       for (var export in exports) {
         var names = export.exportedNames;
-        assert(names != null); // export * not supported in legacy modules.
+        assert(names != null); // export * not supported in ddc modules.
         for (var name in names) {
           var alias = name.asName ?? name.name;
           statements.add(
@@ -280,9 +245,7 @@
 
 /// Generates AMD modules (used in browsers with RequireJS).
 class AmdModuleBuilder extends _ModuleBuilder {
-  final bool singleOutFile;
-
-  AmdModuleBuilder({this.singleOutFile = false});
+  AmdModuleBuilder();
 
   Program build(Program module) {
     var importStatements = <Statement>[];
@@ -326,16 +289,9 @@
     }
 
     // TODO(vsm): Consider using an immediately invoked named function pattern
-    // (see legacy code above).
-    var block = singleOutFile
-        ? js.statement("define(#, #, function(#) { 'use strict'; #; });", [
-            js.string(module.name, "'"),
-            ArrayInitializer(dependencies),
-            fnParams,
-            statements
-          ])
-        : js.statement("define(#, function(#) { 'use strict'; #; });",
-            [ArrayInitializer(dependencies), fnParams, statements]);
+    // (see ddc module code above).
+    var block = js.statement("define(#, function(#) { 'use strict'; #; });",
+        [ArrayInitializer(dependencies), fnParams, statements]);
 
     return Program([block]);
   }
diff --git a/pkg/dev_compiler/lib/src/compiler/shared_command.dart b/pkg/dev_compiler/lib/src/compiler/shared_command.dart
index 09374d2..3d4f240 100644
--- a/pkg/dev_compiler/lib/src/compiler/shared_command.dart
+++ b/pkg/dev_compiler/lib/src/compiler/shared_command.dart
@@ -349,7 +349,14 @@
     var scheme = uri.scheme;
     if (scheme == 'dart' || scheme == 'package' || scheme == multiRootScheme) {
       if (scheme == multiRootScheme) {
-        var multiRootPath = "${multiRootOutputPath ?? ''}${uri.path}";
+        // TODO(sigmund): extract all source-map normalization outside ddc. This
+        // custom logic is BUILD specific and could be shared with other tools
+        // like dart2js.
+        var shortPath = uri.path
+            .replaceAll("/sdk/", "/dart-sdk/")
+            .replaceAll("/sdk_nnbd/", "/dart-sdk/");
+        var multiRootPath = "${multiRootOutputPath ?? ''}$shortPath";
+        multiRootPath = multiRootPath;
         multiRootPath = p.url.relative(multiRootPath, from: sourceMapDir);
         return multiRootPath;
       }
diff --git a/pkg/dev_compiler/lib/src/kernel/command.dart b/pkg/dev_compiler/lib/src/kernel/command.dart
index 4fa082c..478f3b3 100644
--- a/pkg/dev_compiler/lib/src/kernel/command.dart
+++ b/pkg/dev_compiler/lib/src/kernel/command.dart
@@ -10,6 +10,7 @@
 import 'package:build_integration/file_system/multi_root.dart';
 import 'package:cli_util/cli_util.dart' show getSdkPath;
 import 'package:front_end/src/api_unstable/ddc.dart' as fe;
+import 'package:kernel/class_hierarchy.dart';
 import 'package:kernel/kernel.dart' hide MapEntry;
 import 'package:kernel/target/targets.dart';
 import 'package:kernel/text/ast_to_text.dart' as kernel show Printer;
@@ -430,6 +431,77 @@
   return CompilerResult(0, kernelState: compilerState);
 }
 
+// A simplified entrypoint similar to `_compile` that only supports building the
+// sdk. Note that some changes in `_compile_` might need to be copied here as
+// well.
+// TODO(sigmund): refactor the underlying pieces to reduce the code duplication.
+Future<CompilerResult> compileSdkFromDill(List<String> args) async {
+  var argParser = ArgParser(allowTrailingOptions: true)
+    ..addMultiOption('out', abbr: 'o', help: 'Output file (required).')
+    ..addOption('multi-root-scheme', defaultsTo: 'org-dartlang-sdk')
+    ..addOption('multi-root-output-path',
+        help: 'Path to set multi-root files relative to when generating'
+            ' source-maps.',
+        hide: true);
+  SharedCompilerOptions.addArguments(argParser);
+
+  ArgResults argResults;
+  try {
+    argResults = argParser.parse(filterUnknownArguments(args, argParser));
+  } on FormatException catch (error) {
+    print(error);
+    print(_usageMessage(argParser));
+    return CompilerResult(64);
+  }
+
+  var outPaths = argResults['out'] as List<String>;
+  var moduleFormats = parseModuleFormatOption(argResults);
+  if (outPaths.isEmpty) {
+    print('Please specify the output file location. For example:\n'
+        '    -o PATH/TO/OUTPUT_FILE.js');
+    return CompilerResult(64);
+  } else if (outPaths.length != moduleFormats.length) {
+    print('Number of output files (${outPaths.length}) must match '
+        'number of module formats (${moduleFormats.length}).');
+    return CompilerResult(64);
+  }
+
+  var component = loadComponentFromBinary(argResults.rest[0]);
+  var hierarchy = ClassHierarchy(component);
+  var multiRootScheme = argResults['multi-root-scheme'] as String;
+  var multiRootOutputPath = argResults['multi-root-output-path'] as String;
+  var options = SharedCompilerOptions.fromArguments(argResults);
+
+  var compiler = ProgramCompiler(component, hierarchy, options);
+  var jsModule = compiler.emitModule(component, const [], const [], const {});
+  var outFiles = <Future>[];
+
+  // Also the old Analyzer backend had some code to make debugging better when
+  // --single-out-file is used, but that option does not appear to be used by
+  // any of our build systems.
+  for (var i = 0; i < outPaths.length; ++i) {
+    var output = outPaths[i];
+    var moduleFormat = moduleFormats[i];
+    var file = File(output);
+    await file.parent.create(recursive: true);
+    var jsCode = jsProgramToCode(jsModule, moduleFormat,
+        buildSourceMap: options.sourceMap,
+        inlineSourceMap: options.inlineSourceMap,
+        jsUrl: p.toUri(output).toString(),
+        mapUrl: p.toUri(output + '.map').toString(),
+        bazelMapping: options.bazelMapping,
+        customScheme: multiRootScheme,
+        multiRootOutputPath: multiRootOutputPath);
+
+    outFiles.add(file.writeAsString(jsCode.code));
+    if (jsCode.sourceMap != null) {
+      outFiles.add(
+          File(output + '.map').writeAsString(json.encode(jsCode.sourceMap)));
+    }
+  }
+  return CompilerResult(0);
+}
+
 /// The output of compiling a JavaScript module in a particular format.
 /// This was copied from module_compiler.dart class "JSModuleCode".
 class JSCode {
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index 939ee1b..369ec38 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -6,7 +6,6 @@
 import 'dart:convert';
 import 'dart:math' show max, min;
 
-import 'package:front_end/src/api_unstable/ddc.dart' show TypeSchemaEnvironment;
 import 'package:kernel/class_hierarchy.dart';
 import 'package:kernel/core_types.dart';
 import 'package:kernel/kernel.dart' hide MapEntry;
@@ -112,6 +111,8 @@
 
   final TypeEnvironment _types;
 
+  final StatefulStaticTypeContext _staticTypeContext;
+
   final ClassHierarchy _hierarchy;
 
   /// Information about virtual and overridden fields/getters/setters in the
@@ -219,12 +220,22 @@
       SharedCompilerOptions options,
       {CoreTypes coreTypes}) {
     coreTypes ??= CoreTypes(component);
-    var types = TypeSchemaEnvironment(coreTypes, hierarchy);
+    var types = TypeEnvironment(coreTypes, hierarchy);
     var constants = DevCompilerConstants();
     var nativeTypes = NativeTypeSet(coreTypes, constants);
     var jsTypeRep = JSTypeRep(types, hierarchy);
-    return ProgramCompiler._(coreTypes, coreTypes.index, nativeTypes, constants,
-        types, hierarchy, jsTypeRep, NullableInference(jsTypeRep), options);
+    var staticTypeContext = StatefulStaticTypeContext.stacked(types);
+    return ProgramCompiler._(
+        coreTypes,
+        coreTypes.index,
+        nativeTypes,
+        constants,
+        types,
+        hierarchy,
+        jsTypeRep,
+        NullableInference(jsTypeRep, staticTypeContext),
+        staticTypeContext,
+        options);
   }
 
   ProgramCompiler._(
@@ -236,6 +247,7 @@
       this._hierarchy,
       this._typeRep,
       this._nullableInference,
+      this._staticTypeContext,
       this._options)
       : _jsArrayClass = sdk.getClass('dart:_interceptors', 'JSArray'),
         _asyncStreamIteratorClass =
@@ -405,6 +417,7 @@
     // See _emitClass.
     assert(_currentLibrary == null);
     _currentLibrary = library;
+    _staticTypeContext.enterLibrary(_currentLibrary);
 
     if (isSdkInternalRuntime(library)) {
       // `dart:_runtime` uses a different order for bootstrapping.
@@ -427,6 +440,7 @@
       _emitTopLevelFields(library.fields);
     }
 
+    _staticTypeContext.leaveLibrary(_currentLibrary);
     _currentLibrary = null;
   }
 
@@ -472,7 +486,6 @@
     var savedLibrary = _currentLibrary;
     var savedUri = _currentUri;
     _currentClass = c;
-    _types.thisType = c.thisType;
     _currentLibrary = c.enclosingLibrary;
     _currentUri = c.fileUri;
 
@@ -484,7 +497,6 @@
     }
 
     _currentClass = savedClass;
-    _types.thisType = savedClass?.thisType;
     _currentLibrary = savedLibrary;
     _currentUri = savedUri;
   }
@@ -763,7 +775,8 @@
     }
 
     getBaseClass(int count) {
-      var base = emitDeferredType(c.thisType);
+      var base = emitDeferredType(
+          c.getThisType(_coreTypes, c.enclosingLibrary.nonNullable));
       while (--count >= 0) {
         base = js.call('#.__proto__', [base]);
       }
@@ -1345,8 +1358,10 @@
         !f.namedParameters.any(isCovariantParameter)) {
       result = f.thisFunctionType;
     } else {
-      reifyParameter(VariableDeclaration p) =>
-          isCovariantParameter(p) ? _coreTypes.objectClass.thisType : p.type;
+      reifyParameter(VariableDeclaration p) => isCovariantParameter(p)
+          ? _coreTypes.objectClass.getThisType(
+              _coreTypes, _coreTypes.objectClass.enclosingLibrary.nonNullable)
+          : p.type;
       reifyNamedParameter(VariableDeclaration p) =>
           NamedType(p.name, reifyParameter(p));
 
@@ -1374,6 +1389,7 @@
       Constructor node, List<Field> fields, js_ast.Expression className) {
     var savedUri = _currentUri;
     _currentUri = node.fileUri ?? savedUri;
+    _staticTypeContext.enterMember(node);
     var params = _emitParameters(node.function);
     var body = _withCurrentFunction(
         node.function,
@@ -1382,6 +1398,7 @@
 
     var end = _nodeEnd(node.fileEndOffset);
     _currentUri = savedUri;
+    _staticTypeContext.leaveMember(node);
     end ??= _nodeEnd(node.enclosingClass.fileEndOffset);
 
     return js_ast.Fun(params, js_ast.Block(body))..sourceInformation = end;
@@ -1530,7 +1547,9 @@
           (init == null || _constants.isConstant(init))) {
         continue;
       }
+      _staticTypeContext.enterMember(f);
       emitFieldInit(f, init, f);
+      _staticTypeContext.leaveMember(f);
     }
 
     // Run constructor field initializers such as `: foo = bar.baz`
@@ -1650,6 +1669,7 @@
 
     var savedUri = _currentUri;
     for (var m in c.procedures) {
+      _staticTypeContext.enterMember(m);
       // For the Dart SDK, we use the member URI because it may be different
       // from the class (because of patch files). User code does not need this.
       //
@@ -1662,9 +1682,11 @@
         // TODO(jmesserly): is there any other kind of forwarding stub?
         jsMethods.addAll(_emitCovarianceCheckStub(m));
       } else if (m.isFactory) {
-        // Skip redirecting factories (they've already been resolved).
-        if (redirectingFactories?.contains(m) ?? false) continue;
-        jsMethods.add(_emitFactoryConstructor(m));
+        if (redirectingFactories?.contains(m) ?? false) {
+          // Skip redirecting factories (they've already been resolved).
+        } else {
+          jsMethods.add(_emitFactoryConstructor(m));
+        }
       } else if (m.isAccessor) {
         jsMethods.add(_emitMethodDeclaration(m));
         jsMethods.add(_emitSuperAccessorWrapper(m, getters, setters));
@@ -1675,6 +1697,7 @@
       } else {
         jsMethods.add(_emitMethodDeclaration(m));
       }
+      _staticTypeContext.leaveMember(m);
     }
     _currentUri = savedUri;
 
@@ -2027,11 +2050,12 @@
       // Helper functions to test if a constructor invocation is internal and
       // should be eagerly evaluated.
       var isInternalConstructor = (ConstructorInvocation node) {
-        var type = node.getStaticType(_types) as InterfaceType;
+        var type = node.getStaticType(_staticTypeContext) as InterfaceType;
         var library = type.classNode.enclosingLibrary;
         return isSdkInternalRuntime(library);
       };
       for (var field in fields) {
+        _staticTypeContext.enterMember(field);
         var init = field.initializer;
         if (init == null ||
             init is BasicLiteral ||
@@ -2040,7 +2064,7 @@
           if (init is ConstructorInvocation) {
             // This is an eagerly executed constructor invocation.  We need to
             // ensure the class is emitted before this statement.
-            var type = init.getStaticType(_types) as InterfaceType;
+            var type = init.getStaticType(_staticTypeContext) as InterfaceType;
             _emitClass(type.classNode);
           }
           _currentUri = field.fileUri;
@@ -2051,6 +2075,7 @@
         } else {
           lazyFields.add(field);
         }
+        _staticTypeContext.leaveMember(field);
       }
 
       _currentUri = savedUri;
@@ -2071,6 +2096,7 @@
 
     for (var field in fields) {
       _currentUri = field.fileUri;
+      _staticTypeContext.enterMember(field);
       var access = emitFieldName(field);
       accessors.add(js_ast.Method(access, _emitStaticFieldInitializer(field),
           isGetter: true)
@@ -2085,6 +2111,7 @@
             access, js.call('function(_) {}') as js_ast.Fun,
             isSetter: true));
       }
+      _staticTypeContext.leaveMember(field);
     }
     _currentUri = _currentLibrary.fileUri;
 
@@ -2422,6 +2449,7 @@
 
   js_ast.Method _emitLibraryAccessor(Procedure node) {
     var savedUri = _currentUri;
+    _staticTypeContext.enterMember(node);
     _currentUri = node.fileUri;
 
     var name = node.name.name;
@@ -2431,11 +2459,13 @@
       ..sourceInformation = _nodeEnd(node.fileEndOffset);
 
     _currentUri = savedUri;
+    _staticTypeContext.leaveMember(node);
     return result;
   }
 
   js_ast.Statement _emitLibraryFunction(Procedure p) {
     var savedUri = _currentUri;
+    _staticTypeContext.enterMember(p);
     _currentUri = p.fileUri;
 
     var body = <js_ast.Statement>[];
@@ -2461,6 +2491,7 @@
     }
 
     _currentUri = savedUri;
+    _staticTypeContext.leaveMember(p);
     return js_ast.Statement.from(body);
   }
 
@@ -3163,7 +3194,8 @@
     }
 
     if (node is AsExpression && node.isTypeError) {
-      assert(node.getStaticType(_types) == _types.coreTypes.boolLegacyRawType);
+      assert(node.getStaticType(_staticTypeContext) ==
+          _types.coreTypes.boolLegacyRawType);
       return runtimeCall('dtest(#)', [_visitExpression(node.operand)]);
     }
 
@@ -3290,7 +3322,7 @@
   js_ast.Statement visitAssertStatement(AssertStatement node) {
     if (!_options.enableAsserts) return js_ast.EmptyStatement();
     var condition = node.condition;
-    var conditionType = condition.getStaticType(_types);
+    var conditionType = condition.getStaticType(_staticTypeContext);
     var jsCondition = _visitExpression(condition);
 
     var boolType = _coreTypes.boolLegacyRawType;
@@ -3943,7 +3975,7 @@
     // encoded as a different node, or possibly eliminated?
     // (Regardless, we'll still need to handle the callable JS interop classes.)
     if (memberName == 'call' &&
-        _isDirectCallable(receiver.getStaticType(_types))) {
+        _isDirectCallable(receiver.getStaticType(_staticTypeContext))) {
       // Tearoff of `call` on a function type is a no-op;
       return _visitExpression(receiver);
     }
@@ -4068,7 +4100,7 @@
         target.hasGetter &&
         _isDynamicOrFunction(target.getterType);
     if (name == 'call') {
-      var receiverType = receiver.getStaticType(_types);
+      var receiverType = receiver.getStaticType(_staticTypeContext);
       if (isCallingDynamicField || _isDynamicOrFunction(receiverType)) {
         return _emitDynamicInvoke(jsReceiver, null, args, arguments);
       } else if (_isDirectCallable(receiverType)) {
@@ -4332,7 +4364,7 @@
     if (target != null) {
       var targetClass = target.enclosingClass;
       var leftType = _coreTypes.legacyRawType(targetClass);
-      var rightType = right.getStaticType(_types);
+      var rightType = right.getStaticType(_staticTypeContext);
 
       if (_typeRep.binaryOperationIsPrimitive(leftType, rightType) ||
           leftType == _types.coreTypes.stringLegacyRawType && op == '+') {
@@ -4432,7 +4464,7 @@
     var targetClass = target?.enclosingClass;
     var leftType = targetClass != null
         ? _coreTypes.legacyRawType(targetClass)
-        : left.getStaticType(_types);
+        : left.getStaticType(_staticTypeContext);
 
     // Conceptually `x == y` in Dart is defined as:
     //
@@ -4731,15 +4763,16 @@
   }
 
   bool _isNull(Expression expr) =>
-      expr is NullLiteral || expr.getStaticType(_types) == _coreTypes.nullType;
+      expr is NullLiteral ||
+      expr.getStaticType(_staticTypeContext) == _coreTypes.nullType;
 
   bool _doubleEqIsIdentity(Expression left, Expression right) {
     // If we statically know LHS or RHS is null we can use ==.
     if (_isNull(left) || _isNull(right)) return true;
     // If the representation of the  two types will not induce conversion in
     // JS then we can use == .
-    return !_typeRep.equalityMayConvert(
-        left.getStaticType(_types), right.getStaticType(_types));
+    return !_typeRep.equalityMayConvert(left.getStaticType(_staticTypeContext),
+        right.getStaticType(_staticTypeContext));
   }
 
   bool _tripleEqIsIdentity(Expression left, Expression right) {
@@ -4943,11 +4976,11 @@
       if (jsExpr is js_ast.LiteralString && jsExpr.valueWithoutQuotes.isEmpty) {
         continue;
       }
-      parts.add(
-          e.getStaticType(_types) == _types.coreTypes.stringLegacyRawType &&
-                  !isNullable(e)
-              ? jsExpr
-              : runtimeCall('str(#)', [jsExpr]));
+      parts.add(e.getStaticType(_staticTypeContext) ==
+                  _types.coreTypes.stringLegacyRawType &&
+              !isNullable(e)
+          ? jsExpr
+          : runtimeCall('str(#)', [jsExpr]));
     }
     if (parts.isEmpty) return js.string('');
     return js_ast.Expression.binary(parts, '+');
@@ -5005,7 +5038,7 @@
     Expression fromExpr = node.operand;
     var to = node.type;
     var jsFrom = _visitExpression(fromExpr);
-    var from = fromExpr.getStaticType(_types);
+    var from = fromExpr.getStaticType(_staticTypeContext);
 
     // If the check was put here by static analysis to ensure soundness, we
     // can't skip it. For example, one could implement covariant generic caller
@@ -5146,8 +5179,8 @@
 
     // TODO(markzipan): remove const check when we use front-end const eval
     if (!node.isConst) {
-      var mapType =
-          _emitMapImplType(node.getStaticType(_types) as InterfaceType);
+      var mapType = _emitMapImplType(
+          node.getStaticType(_staticTypeContext) as InterfaceType);
       if (node.entries.isEmpty) {
         return js.call('new #.new()', [mapType]);
       }
@@ -5170,7 +5203,8 @@
   js_ast.Expression visitFunctionExpression(FunctionExpression node) {
     var fn = _emitArrowFunction(node);
     if (!_reifyFunctionType(node.function)) return fn;
-    return _emitFunctionTagged(fn, node.getStaticType(_types) as FunctionType);
+    return _emitFunctionTagged(
+        fn, node.getStaticType(_staticTypeContext) as FunctionType);
   }
 
   js_ast.ArrowFun _emitArrowFunction(FunctionExpression node) {
@@ -5251,7 +5285,7 @@
       js_ast.Expression genFn = js_ast.Fun([], jsBlock, isGenerator: true);
       if (usesThisOrSuper(genFn)) genFn = js.call('#.bind(this)', genFn);
       var asyncLibrary = emitLibraryName(_coreTypes.asyncLibrary);
-      var returnType = _emitType(node.getStaticType(_types));
+      var returnType = _emitType(node.getStaticType(_staticTypeContext));
       var asyncCall =
           js.call('#.async(#, #)', [asyncLibrary, returnType, genFn]);
       return js_ast.Yield(asyncCall);
@@ -5450,7 +5484,8 @@
       return js_ast.Property(symbol, constant);
     }
 
-    var type = visitInterfaceType(node.getType(_types) as InterfaceType);
+    var type =
+        visitInterfaceType(node.getType(_staticTypeContext) as InterfaceType);
     var prototype = js.call("#.prototype", [type]);
     var properties = [
       js_ast.Property(propertyName("__proto__"), prototype),
diff --git a/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart b/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart
index c49ba46..f549783 100644
--- a/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart
+++ b/pkg/dev_compiler/lib/src/kernel/nullable_inference.dart
@@ -14,7 +14,7 @@
 /// This class can also analyze the nullability of local variables, if
 /// [enterFunction] and [exitFunction] are used.
 class NullableInference extends ExpressionVisitor<bool> {
-  final TypeEnvironment types;
+  final StaticTypeContext _staticTypeContext;
   final JSTypeRep jsTypeRep;
   final CoreTypes coreTypes;
 
@@ -38,19 +38,22 @@
 
   final _variableInference = _NullableVariableInference();
 
-  NullableInference(this.jsTypeRep)
-      : types = jsTypeRep.types,
-        coreTypes = jsTypeRep.coreTypes {
+  NullableInference(this.jsTypeRep, this._staticTypeContext)
+      : coreTypes = jsTypeRep.coreTypes {
     _variableInference._nullInference = this;
   }
 
   /// Call when entering a function to enable [isNullable] to recognize local
   /// variables that cannot be null.
-  void enterFunction(FunctionNode fn) => _variableInference.enterFunction(fn);
+  void enterFunction(FunctionNode fn) {
+    _variableInference.enterFunction(fn);
+  }
 
   /// Call when exiting a function to clear out the information recorded by
   /// [enterFunction].
-  void exitFunction(FunctionNode fn) => _variableInference.exitFunction(fn);
+  void exitFunction(FunctionNode fn) {
+    _variableInference.exitFunction(fn);
+  }
 
   /// Returns true if [expr] can be null.
   bool isNullable(Expression expr) => expr != null ? expr.accept(this) : false;
@@ -119,7 +122,8 @@
     if (target == null) return true; // dynamic call
     if (target.name.name == 'toString' &&
         receiver != null &&
-        receiver.getStaticType(types) == coreTypes.stringLegacyRawType) {
+        receiver.getStaticType(_staticTypeContext) ==
+            coreTypes.stringLegacyRawType) {
       // TODO(jmesserly): `class String` in dart:core does not explicitly
       // declare `toString`, which results in a target of `Object.toString` even
       // when the reciever type is known to be `String`. So we work around it.
@@ -164,7 +168,9 @@
   @override
   visitStaticInvocation(StaticInvocation node) {
     var target = node.target;
-    if (target == types.coreTypes.identicalProcedure) return false;
+    if (target == coreTypes.identicalProcedure) {
+      return false;
+    }
     if (isInlineJS(target)) {
       var args = node.arguments.positional;
       var first = args.isNotEmpty ? args.first : null;
diff --git a/pkg/dev_compiler/lib/src/kernel/target.dart b/pkg/dev_compiler/lib/src/kernel/target.dart
index 960e92a..7cd1fc0 100644
--- a/pkg/dev_compiler/lib/src/kernel/target.dart
+++ b/pkg/dev_compiler/lib/src/kernel/target.dart
@@ -23,6 +23,11 @@
   @override
   bool get enableSuperMixins => true;
 
+  // TODO(johnniwinther): Change this to `false` when late field lowering is
+  // ready.
+  @override
+  bool get supportsLateFields => true;
+
   @override
   String get name => 'dartdevc';
 
diff --git a/pkg/dev_compiler/test/nullable_inference_test.dart b/pkg/dev_compiler/test/nullable_inference_test.dart
index c7f7e28..4a49356 100644
--- a/pkg/dev_compiler/test/nullable_inference_test.dart
+++ b/pkg/dev_compiler/test/nullable_inference_test.dart
@@ -8,6 +8,7 @@
 import 'package:kernel/core_types.dart';
 import 'package:kernel/kernel.dart';
 import 'package:kernel/class_hierarchy.dart';
+import 'package:kernel/type_environment.dart';
 import 'package:kernel/target/targets.dart';
 import 'package:test/test.dart';
 
@@ -527,16 +528,21 @@
 class _TestRecursiveVisitor extends RecursiveVisitor<void> {
   final Set<Library> librariesFromDill;
   int _functionNesting = 0;
+  TypeEnvironment _typeEnvironment;
+  StatefulStaticTypeContext _staticTypeContext;
 
   _TestRecursiveVisitor(this.librariesFromDill);
 
   @override
   visitComponent(Component node) {
     var hierarchy = ClassHierarchy(node);
-    inference ??= NullableInference(JSTypeRep(
+    var jsTypeRep = JSTypeRep(
       fe.TypeSchemaEnvironment(CoreTypes(node), hierarchy),
       hierarchy,
-    ));
+    );
+    _typeEnvironment = jsTypeRep.types;
+    _staticTypeContext = StatefulStaticTypeContext.stacked(_typeEnvironment);
+    inference ??= NullableInference(jsTypeRep, _staticTypeContext);
 
     if (useAnnotations) {
       inference.allowNotNullDeclarations = useAnnotations;
@@ -547,18 +553,43 @@
 
   @override
   visitLibrary(Library node) {
+    _staticTypeContext.enterLibrary(node);
     if (librariesFromDill.contains(node) ||
         node.importUri.scheme == 'package' &&
             node.importUri.pathSegments[0] == 'meta') {
       return;
     }
     super.visitLibrary(node);
+    _staticTypeContext.leaveLibrary(node);
+  }
+
+  @override
+  visitField(Field node) {
+    _staticTypeContext.enterMember(node);
+    super.visitField(node);
+    _staticTypeContext.leaveMember(node);
+  }
+
+  @override
+  visitConstructor(Constructor node) {
+    _staticTypeContext.enterMember(node);
+    super.visitConstructor(node);
+    _staticTypeContext.leaveMember(node);
+  }
+
+  @override
+  visitProcedure(Procedure node) {
+    _staticTypeContext.enterMember(node);
+    super.visitProcedure(node);
+    _staticTypeContext.leaveMember(node);
   }
 
   @override
   visitFunctionNode(FunctionNode node) {
     _functionNesting++;
-    if (_functionNesting == 1) inference.enterFunction(node);
+    if (_functionNesting == 1) {
+      inference.enterFunction(node);
+    }
     super.visitFunctionNode(node);
     if (_functionNesting == 1) inference.exitFunction(node);
     _functionNesting--;
diff --git a/pkg/dev_compiler/test/sdk_source_map_test.dart b/pkg/dev_compiler/test/sdk_source_map_test.dart
index f4028f5..da0683f 100644
--- a/pkg/dev_compiler/test/sdk_source_map_test.dart
+++ b/pkg/dev_compiler/test/sdk_source_map_test.dart
@@ -27,6 +27,6 @@
     Expect.equals(p.extension(url), '.dart');
     Expect.isFalse(p.isAbsolute(url));
     var fullPath = p.canonicalize(p.join(sdkJsMapDir, url));
-    Expect.isTrue(await File(fullPath).exists());
+    Expect.isTrue(await File(fullPath).exists(), "Missing file: $fullPath");
   }
 }
diff --git a/pkg/dev_compiler/test/sourcemap/README.md b/pkg/dev_compiler/test/sourcemap/README.md
index a855144..65c5ef3 100644
--- a/pkg/dev_compiler/test/sourcemap/README.md
+++ b/pkg/dev_compiler/test/sourcemap/README.md
@@ -7,7 +7,7 @@
 
 Running the tests likely requires the compilation of the correct targets. DDK currently also
 requires `ddc_sdk.dill` inside
-`{sdkroot}/{out,xcodebuild}/ReleaseX64/gen/utils/dartdevc/kernel/ddc_sdk.dill`.
+`{sdkroot}/{out,xcodebuild}/ReleaseX64/ddc_sdk.dill`.
 
 Except for that, running them should simply be a matter of executing the `*_suite.dart` files.
 
diff --git a/pkg/dev_compiler/test/sourcemap/sourcemaps_ddk_suite.dart b/pkg/dev_compiler/test/sourcemap/sourcemaps_ddk_suite.dart
index cec6887..3246bd5 100644
--- a/pkg/dev_compiler/test/sourcemap/sourcemaps_ddk_suite.dart
+++ b/pkg/dev_compiler/test/sourcemap/sourcemaps_ddk_suite.dart
@@ -56,7 +56,7 @@
     File sdkJsFile = findInOutDir("gen/utils/dartdevc/js/es6/dart_sdk.js");
     var jsSdkPath = sdkJsFile.uri;
 
-    File ddcSdkSummary = findInOutDir("gen/utils/dartdevc/kernel/ddc_sdk.dill");
+    File ddcSdkSummary = findInOutDir("ddc_sdk.dill");
 
     List<String> args = <String>[
       "--packages=${sdkRoot.uri.resolve(".packages").toFilePath()}",
diff --git a/pkg/dev_compiler/tool/check_nnbd_sdk.dart b/pkg/dev_compiler/tool/check_nnbd_sdk.dart
new file mode 100644
index 0000000..8d36bb9
--- /dev/null
+++ b/pkg/dev_compiler/tool/check_nnbd_sdk.dart
@@ -0,0 +1,77 @@
+#!/usr/bin/env dart
+// Copyright (c) 2019, 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.
+
+/// Command-line tool that runs dartanalyzer on a sdk under the perspective of
+/// one tool.
+// TODO(sigmund): generalize this to support other tools, not just ddc.
+
+import 'dart:io';
+import 'package:args/args.dart';
+import 'package:front_end/src/fasta/resolve_input_uri.dart';
+
+import 'patch_sdk.dart' as patch;
+
+void main(List<String> argv) {
+  var args = _parser.parse(argv);
+  String baseDir = args['out'] as String;
+  if (baseDir == null) {
+    var tmp = Directory.systemTemp.createTempSync('check_sdk-');
+    baseDir = tmp.path;
+  }
+  var baseUri = resolveInputUri(baseDir.endsWith('/') ? baseDir : '$baseDir/');
+  var sdkDir = baseUri.resolve('sdk/').toFilePath();
+  print('Generating a patched sdk at ${baseUri.path}');
+
+  Uri librariesJson = args['libraries'] != null
+      ? resolveInputUri(args['libraries'] as String)
+      : Platform.script.resolve('../../../sdk_nnbd/lib/libraries.json');
+  patch.main([
+    '--libraries',
+    librariesJson.toFilePath(),
+    '--target',
+    args['target'] as String,
+    '--out',
+    sdkDir,
+    '--merge-parts',
+    '--nnbd',
+  ]);
+
+  var emptyProgramUri = baseUri.resolve('empty_program.dart');
+  File.fromUri(emptyProgramUri).writeAsStringSync('main() {}');
+
+  print('Running dartanalyzer');
+  var dart = Uri.base.resolve(Platform.resolvedExecutable);
+  var analyzerSnapshot = Uri.base
+      .resolve(Platform.resolvedExecutable)
+      .resolve('snapshots/dartanalyzer.dart.snapshot');
+  var result = Process.runSync(dart.toFilePath(), [
+    analyzerSnapshot.toFilePath(),
+    '--dart-sdk=${sdkDir}',
+    '--format',
+    'machine',
+    '--sdk-warnings',
+    '--no-hints',
+    emptyProgramUri.toFilePath()
+  ]);
+
+  stdout.write(result.stdout);
+  String errors = result.stderr as String;
+  var count = errors.trim().split('\n').length;
+  print('$count analyzer errors. Errors emitted to ${baseUri.path}errors.txt');
+  File.fromUri(baseUri.resolve('errors.txt')).writeAsStringSync(errors);
+}
+
+final _parser = ArgParser()
+  ..addOption('libraries',
+      help: 'Path to the nnbd libraries.json (defaults to the one under '
+          'sdk_nnbd/lib/libraries.json.')
+  ..addOption('out',
+      help: 'Path to an output folder (defaults to a new tmp folder).')
+  ..addOption('target',
+      help: 'The target tool. '
+          'This name matches one of the possible targets in libraries.json '
+          'and it is used to pick which patch files will be applied.',
+      allowed: ['dartdevc', 'dart2js', 'dart2js_server', 'vm', 'flutter'],
+      defaultsTo: 'dartdevc');
diff --git a/pkg/dev_compiler/tool/compile_dartdevc_sdk.dart b/pkg/dev_compiler/tool/compile_dartdevc_sdk.dart
new file mode 100644
index 0000000..097a40a
--- /dev/null
+++ b/pkg/dev_compiler/tool/compile_dartdevc_sdk.dart
@@ -0,0 +1,15 @@
+#!/usr/bin/env dart
+// Copyright (c) 2019, 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.
+
+/// Tool that consumes the .dill file of an entire dart-sdk and produces the
+/// corresponding Javascript module.
+
+import 'dart:io';
+import 'package:dev_compiler/src/kernel/command.dart';
+
+main(List<String> args) async {
+  var result = await compileSdkFromDill(args);
+  exitCode = result.exitCode;
+}
diff --git a/pkg/dev_compiler/tool/ddc b/pkg/dev_compiler/tool/ddc
index 4fff33d..cfe8879 100755
--- a/pkg/dev_compiler/tool/ddc
+++ b/pkg/dev_compiler/tool/ddc
@@ -51,7 +51,8 @@
   fi
 fi
 
-GEN_DIR="$OUT_DIR"/"$DART_CONFIGURATION"/gen/utils/dartdevc
+ROOT_OUT_DIR="$OUT_DIR"/"$DART_CONFIGURATION"
+GEN_DIR="$ROOT_OUT_DIR"/gen/utils/dartdevc
 
 KERNEL=false
 if [ "$1" = "-k" ]; then
@@ -64,7 +65,7 @@
 
 if [ "$KERNEL" = true ]; then
 
-  if [ ! -e $GEN_DIR/kernel/ddc_sdk.dill ]; then
+  if [ ! -e $ROOT_OUT_DIR/ddc_sdk.dill ]; then
     echo "DDC SDK must be built first, please run:"
     echo "    pushd $SDKDIR"
     echo "    ./tools/build.py -m release dartdevc_kernel_sdk"
@@ -74,7 +75,7 @@
   NODE_PATH=$GEN_DIR/kernel/common:$LIBROOT:$NODE_PATH
 
   $SDK_DIR/sdk/bin/dartdevc --kernel --modules=node \
-      --dart-sdk-summary=$GEN_DIR/ddc_sdk.sum \
+      --dart-sdk-summary=$ROOT_OUT_DIR/ddc_sdk.dill \
       -o $LIBROOT/$BASENAME.js $*
 else
 
diff --git a/pkg/dev_compiler/tool/kernel_sdk.dart b/pkg/dev_compiler/tool/kernel_sdk.dart
index 81eb813..6c337e6 100755
--- a/pkg/dev_compiler/tool/kernel_sdk.dart
+++ b/pkg/dev_compiler/tool/kernel_sdk.dart
@@ -100,7 +100,7 @@
     'amd': ModuleFormat.amd,
     'common': ModuleFormat.common,
     'es6': ModuleFormat.es6,
-    'legacy': ModuleFormat.legacy,
+    'legacy': ModuleFormat.ddc,
   };
 
   for (var name in moduleFormats.keys) {
diff --git a/pkg/front_end/lib/src/api_prototype/experimental_flags.dart b/pkg/front_end/lib/src/api_prototype/experimental_flags.dart
index d36bd4a..110685b 100644
--- a/pkg/front_end/lib/src/api_prototype/experimental_flags.dart
+++ b/pkg/front_end/lib/src/api_prototype/experimental_flags.dart
@@ -12,6 +12,7 @@
   controlFlowCollections,
   extensionMethods,
   nonNullable,
+  nonfunctionTypeAliases,
   setLiterals,
   spreadCollections,
   tripleShift,
@@ -28,6 +29,8 @@
       return ExperimentalFlag.extensionMethods;
     case "non-nullable":
       return ExperimentalFlag.nonNullable;
+    case "nonfunction-type-aliases":
+      return ExperimentalFlag.nonfunctionTypeAliases;
     case "set-literals":
       return ExperimentalFlag.setLiterals;
     case "spread-collections":
@@ -45,6 +48,7 @@
   ExperimentalFlag.controlFlowCollections: true,
   ExperimentalFlag.extensionMethods: true,
   ExperimentalFlag.nonNullable: false,
+  ExperimentalFlag.nonfunctionTypeAliases: false,
   ExperimentalFlag.setLiterals: true,
   ExperimentalFlag.spreadCollections: true,
   ExperimentalFlag.tripleShift: false,
@@ -56,6 +60,7 @@
   ExperimentalFlag.controlFlowCollections: true,
   ExperimentalFlag.extensionMethods: false,
   ExperimentalFlag.nonNullable: false,
+  ExperimentalFlag.nonfunctionTypeAliases: false,
   ExperimentalFlag.setLiterals: true,
   ExperimentalFlag.spreadCollections: true,
   ExperimentalFlag.tripleShift: false,
diff --git a/pkg/front_end/lib/src/api_prototype/kernel_generator.dart b/pkg/front_end/lib/src/api_prototype/kernel_generator.dart
index ebb705a..8de9131 100644
--- a/pkg/front_end/lib/src/api_prototype/kernel_generator.dart
+++ b/pkg/front_end/lib/src/api_prototype/kernel_generator.dart
@@ -109,6 +109,11 @@
   /// The generated component, if it was requested.
   Component get component;
 
+  Component get sdkComponent;
+
+  /// The components loaded from dill (excluding the sdk).
+  List<Component> get loadedComponents;
+
   /// Dependencies traversed by the compiler. Used only for generating
   /// dependency .GN files in the dart-sdk build system.
   /// Note this might be removed when we switch to compute dependencies without
diff --git a/pkg/front_end/lib/src/fasta/builder/class_builder.dart b/pkg/front_end/lib/src/fasta/builder/class_builder.dart
index 98f0245..8c3c529 100644
--- a/pkg/front_end/lib/src/fasta/builder/class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/class_builder.dart
@@ -15,6 +15,7 @@
         Expression,
         Field,
         FunctionNode,
+        FunctionType,
         InterfaceType,
         InvalidType,
         ListLiteral,
@@ -33,9 +34,8 @@
         TypeParameterType,
         VariableDeclaration,
         Variance,
-        VoidType;
-
-import 'package:kernel/ast.dart' show FunctionType, TypeParameterType;
+        VoidType,
+        getAsTypeArguments;
 
 import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
 
@@ -49,6 +49,7 @@
         computeVariance,
         findTypeArgumentIssues,
         getGenericTypeName;
+
 import 'package:kernel/text/text_serialization_verifier.dart';
 
 import 'package:kernel/type_algebra.dart' show Substitution, substitute;
@@ -383,6 +384,11 @@
   @override
   bool isNullClass = false;
 
+  InterfaceType _legacyRawType;
+  InterfaceType _nullableRawType;
+  InterfaceType _nonNullableRawType;
+  InterfaceType _thisType;
+
   ClassBuilderImpl(
       List<MetadataBuilder> metadata,
       int modifiers,
@@ -604,33 +610,29 @@
     return declaration;
   }
 
-  InterfaceType _legacyRawType;
-  InterfaceType _nullableRawType;
-  InterfaceType _nonNullableRawType;
-
   @override
   ClassBuilder get origin => actualOrigin ?? this;
 
   @override
-  InterfaceType get thisType => cls.thisType;
+  InterfaceType get thisType {
+    return _thisType ??= new InterfaceType(cls, library.nonNullable,
+        getAsTypeArguments(cls.typeParameters, library.library));
+  }
 
   @override
   InterfaceType get legacyRawType {
-    // TODO(dmitryas): Use computeBound instead of DynamicType here?
     return _legacyRawType ??= new InterfaceType(cls, Nullability.legacy,
         new List<DartType>.filled(typeVariablesCount, const DynamicType()));
   }
 
   @override
   InterfaceType get nullableRawType {
-    // TODO(dmitryas): Use computeBound instead of DynamicType here?
     return _nullableRawType ??= new InterfaceType(cls, Nullability.nullable,
         new List<DartType>.filled(typeVariablesCount, const DynamicType()));
   }
 
   @override
   InterfaceType get nonNullableRawType {
-    // TODO(dmitryas): Use computeBound instead of DynamicType here?
     return _nonNullableRawType ??= new InterfaceType(
         cls,
         Nullability.nonNullable,
@@ -804,7 +806,7 @@
 
     List<TypeArgumentIssue> issues = findTypeArgumentIssues(
         new InterfaceType(
-            supertype.classNode, Nullability.legacy, supertype.typeArguments),
+            supertype.classNode, library.nonNullable, supertype.typeArguments),
         typeEnvironment,
         allowSuperBounded: false);
     if (issues != null) {
@@ -1160,7 +1162,7 @@
         target.loader.coreTypes,
         new ThisExpression(),
         prefix + procedure.name.name,
-        new Arguments.forwarded(procedure.function),
+        new Arguments.forwarded(procedure.function, library.library),
         procedure.fileOffset,
         /*isSuper=*/ false);
     Expression result = new MethodInvocation(new ThisExpression(),
@@ -1382,8 +1384,7 @@
     Substitution interfaceSubstitution = Substitution.empty;
     if (interfaceMember.enclosingClass.typeParameters.isNotEmpty) {
       interfaceSubstitution = Substitution.fromInterfaceType(types.hierarchy
-          .getKernelTypeAsInstanceOf(
-              cls.thisType, interfaceMember.enclosingClass));
+          .getKernelTypeAsInstanceOf(thisType, interfaceMember.enclosingClass));
     }
     if (declaredFunction?.typeParameters?.length !=
         interfaceFunction?.typeParameters?.length) {
@@ -1408,8 +1409,9 @@
           <TypeParameter, DartType>{};
       for (int i = 0; i < declaredFunction.typeParameters.length; ++i) {
         substitutionMap[interfaceFunction.typeParameters[i]] =
-            new TypeParameterType(
-                declaredFunction.typeParameters[i], Nullability.legacy);
+            new TypeParameterType.forAlphaRenaming(
+                interfaceFunction.typeParameters[i],
+                declaredFunction.typeParameters[i]);
       }
       Substitution substitution = Substitution.fromMap(substitutionMap);
       for (int i = 0; i < declaredFunction.typeParameters.length; ++i) {
@@ -1454,8 +1456,7 @@
     Substitution declaredSubstitution = Substitution.empty;
     if (declaredMember.enclosingClass.typeParameters.isNotEmpty) {
       declaredSubstitution = Substitution.fromInterfaceType(types.hierarchy
-          .getKernelTypeAsInstanceOf(
-              cls.thisType, declaredMember.enclosingClass));
+          .getKernelTypeAsInstanceOf(thisType, declaredMember.enclosingClass));
     }
     return declaredSubstitution;
   }
diff --git a/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart b/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart
index 8c730f3..dfb0012 100644
--- a/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart
@@ -226,11 +226,12 @@
     List<DartType> typeParameterTypes = new List<DartType>();
     for (int i = 0; i < enclosingClass.typeParameters.length; i++) {
       TypeParameter typeParameter = enclosingClass.typeParameters[i];
-      typeParameterTypes
-          .add(new TypeParameterType(typeParameter, Nullability.legacy));
+      typeParameterTypes.add(
+          new TypeParameterType.withDefaultNullabilityForLibrary(
+              typeParameter, library.library));
     }
     functionNode.returnType = new InterfaceType(
-        enclosingClass, Nullability.legacy, typeParameterTypes);
+        enclosingClass, library.nonNullable, typeParameterTypes);
     return functionNode;
   }
 
@@ -334,13 +335,14 @@
     // stage, there is no easy way to make body building stage skip initializer
     // parsing, so we simply clear parsed initializers and rebuild them
     // again.
+    // For when doing an experimental incremental compilation they are also
+    // potentially done more than once (because it rebuilds the bodies of an old
+    // compile), and so we also clear them.
     // Note: this method clears both initializers from the target Kernel node
     // and internal state associated with parsing initializers.
-    if (_constructor.isConst) {
-      _constructor.initializers.length = 0;
-      redirectingInitializer = null;
-      superInitializer = null;
-      hasMovedSuperInitializer = false;
-    }
+    _constructor.initializers.length = 0;
+    redirectingInitializer = null;
+    superInitializer = null;
+    hasMovedSuperInitializer = false;
   }
 }
diff --git a/pkg/front_end/lib/src/fasta/builder/enum_builder.dart b/pkg/front_end/lib/src/fasta/builder/enum_builder.dart
index 2a17bdcb..2d01cccc 100644
--- a/pkg/front_end/lib/src/fasta/builder/enum_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/enum_builder.dart
@@ -128,9 +128,9 @@
     ///   String toString() => _name;
     /// }
 
-    members["index"] = new FieldBuilderImpl(null, intType, "index",
+    members["index"] = new SourceFieldBuilder(null, intType, "index",
         finalMask | hasInitializerMask, parent, charOffset, charOffset);
-    members["_name"] = new FieldBuilderImpl(null, stringType, "_name",
+    members["_name"] = new SourceFieldBuilder(null, stringType, "_name",
         finalMask | hasInitializerMask, parent, charOffset, charOffset);
     ConstructorBuilder constructorBuilder = new ConstructorBuilderImpl(
         null,
@@ -150,7 +150,7 @@
         charOffset,
         charEndOffset);
     constructors[""] = constructorBuilder;
-    FieldBuilder valuesBuilder = new FieldBuilderImpl(
+    FieldBuilder valuesBuilder = new SourceFieldBuilder(
         null,
         listType,
         "values",
@@ -209,7 +209,7 @@
               name.length,
               parent.fileUri);
         }
-        FieldBuilder fieldBuilder = new FieldBuilderImpl(
+        FieldBuilder fieldBuilder = new SourceFieldBuilder(
             metadata,
             selfType,
             name,
@@ -273,10 +273,12 @@
         coreLibrary.scope, charOffset, fileUri, libraryBuilder);
     listType.resolveIn(coreLibrary.scope, charOffset, fileUri, libraryBuilder);
 
-    FieldBuilderImpl indexFieldBuilder = firstMemberNamed("index");
-    Field indexField = indexFieldBuilder.build(libraryBuilder);
-    FieldBuilderImpl nameFieldBuilder = firstMemberNamed("_name");
-    Field nameField = nameFieldBuilder.build(libraryBuilder);
+    SourceFieldBuilder indexFieldBuilder = firstMemberNamed("index");
+    indexFieldBuilder.build(libraryBuilder);
+    Field indexField = indexFieldBuilder.field;
+    SourceFieldBuilder nameFieldBuilder = firstMemberNamed("_name");
+    nameFieldBuilder.build(libraryBuilder);
+    Field nameField = nameFieldBuilder.field;
     ProcedureBuilder toStringBuilder = firstMemberNamed("toString");
     toStringBuilder.body = new ReturnStatement(
         new DirectPropertyGet(new ThisExpression(), nameField));
@@ -286,16 +288,17 @@
         if (enumConstantInfo != null) {
           Builder declaration = firstMemberNamed(enumConstantInfo.name);
           if (declaration.isField) {
-            FieldBuilderImpl field = declaration;
-            values.add(new StaticGet(field.build(libraryBuilder)));
+            SourceFieldBuilder fieldBuilder = declaration;
+            fieldBuilder.build(libraryBuilder);
+            values.add(new StaticGet(fieldBuilder.field));
           }
         }
       }
     }
-    FieldBuilderImpl valuesBuilder = firstMemberNamed("values");
+    SourceFieldBuilder valuesBuilder = firstMemberNamed("values");
     valuesBuilder.build(libraryBuilder);
-    valuesBuilder.initializer = new ListLiteral(values,
-        typeArgument: rawType(library.nonNullable), isConst: true);
+    valuesBuilder.buildBody(new ListLiteral(values,
+        typeArgument: rawType(library.nonNullable), isConst: true));
     ConstructorBuilderImpl constructorBuilder = constructorScopeBuilder[""];
     Constructor constructor = constructorBuilder.build(libraryBuilder);
     constructor.initializers.insert(
@@ -339,8 +342,8 @@
             new IntLiteral(index++),
             new StringLiteral("$name.$constant")
           ]);
-          field.initializer =
-              new ConstructorInvocation(constructor, arguments, isConst: true);
+          field.buildBody(
+              new ConstructorInvocation(constructor, arguments, isConst: true));
         }
       }
     }
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 941904a..341fe25 100644
--- a/pkg/front_end/lib/src/fasta/builder/field_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/field_builder.dart
@@ -16,8 +16,9 @@
         templateCantInferTypeDueToCircularity;
 
 import '../kernel/body_builder.dart' show BodyBuilder;
-
+import '../kernel/class_hierarchy_builder.dart' show ClassMember;
 import '../kernel/kernel_builder.dart' show ImplicitFieldType;
+import '../kernel/late_lowering.dart' as late_lowering;
 
 import '../modifier.dart' show covariantMask, hasInitializerMask, lateMask;
 
@@ -37,7 +38,6 @@
 
 import '../type_inference/type_schema.dart' show UnknownType;
 
-import 'builder.dart';
 import 'class_builder.dart';
 import 'extension_builder.dart';
 import 'library_builder.dart';
@@ -62,22 +62,39 @@
 
   bool get hasInitializer;
 
-  void set initializer(Expression value);
+  /// Whether the body of this field has been built.
+  ///
+  /// Constant fields have their initializer built in the outline so we avoid
+  /// building them twice as part of the non-outline build.
+  bool get hasBodyBeenBuilt;
+
+  /// Builds the body of this field using [initializer] as the initializer
+  /// expression.
+  void buildBody(Expression initializer);
+
+  /// Builds the field initializers for each field used to encode this field
+  /// using the [fileOffset] for the created nodes and [value] as the initial
+  /// field value.
+  List<Initializer> buildInitializer(int fileOffset, Expression value,
+      {bool isSynthetic});
 
   bool get isEligibleForInference;
 
   DartType get builtType;
+
+  DartType inferType();
+
+  DartType fieldType;
 }
 
-class FieldBuilderImpl extends MemberBuilderImpl implements FieldBuilder {
+class SourceFieldBuilder extends MemberBuilderImpl implements FieldBuilder {
   @override
   final String name;
 
   @override
   final int modifiers;
 
-  @override
-  final Field field;
+  FieldEncoding _fieldEncoding;
 
   @override
   final List<MetadataBuilder> metadata;
@@ -90,14 +107,38 @@
 
   bool hadTypesInferred = false;
 
-  FieldBuilderImpl(this.metadata, this.type, this.name, this.modifiers,
-      Builder compilationUnit, int charOffset, int charEndOffset)
-      : field = new Field(null, fileUri: compilationUnit?.fileUri)
-          ..fileOffset = charOffset
-          ..fileEndOffset = charEndOffset,
-        super(compilationUnit, charOffset);
+  bool hasBodyBeenBuilt = false;
 
-  Member get member => field;
+  SourceFieldBuilder(this.metadata, this.type, this.name, this.modifiers,
+      SourceLibraryBuilder libraryBuilder, int charOffset, int charEndOffset)
+      : super(libraryBuilder, charOffset) {
+    Uri fileUri = libraryBuilder?.fileUri;
+    if (isLate &&
+        !libraryBuilder.loader.target.backendTarget.supportsLateFields) {
+      if (hasInitializer) {
+        if (isFinal) {
+          _fieldEncoding = new LateFinalFieldWithInitializerEncoding(
+              name, fileUri, charOffset, charEndOffset);
+        } else {
+          _fieldEncoding = new LateFieldWithInitializerEncoding(
+              name, fileUri, charOffset, charEndOffset);
+        }
+      } else {
+        if (isFinal) {
+          _fieldEncoding = new LateFinalFieldWithoutInitializerEncoding(
+              name, fileUri, charOffset, charEndOffset);
+        } else {
+          _fieldEncoding = new LateFieldWithoutInitializerEncoding(
+              name, fileUri, charOffset, charEndOffset);
+        }
+      }
+    } else {
+      _fieldEncoding =
+          new RegularFieldEncoding(fileUri, charOffset, charEndOffset);
+    }
+  }
+
+  Member get member => _fieldEncoding.field;
 
   String get debugName => "FieldBuilder";
 
@@ -112,12 +153,26 @@
   @override
   bool get hasInitializer => (modifiers & hasInitializerMask) != 0;
 
-  void set initializer(Expression value) {
-    if (!hasInitializer && value is! NullLiteral && !isConst && !isFinal) {
+  @override
+  void buildBody(Expression initializer) {
+    assert(!hasBodyBeenBuilt);
+    hasBodyBeenBuilt = true;
+    if (!hasInitializer &&
+        initializer != null &&
+        initializer is! NullLiteral &&
+        !isConst &&
+        !isFinal) {
       internalProblem(
           messageInternalProblemAlreadyInitialized, charOffset, fileUri);
     }
-    field.initializer = value..parent = field;
+    _fieldEncoding.createBodies(initializer);
+  }
+
+  @override
+  List<Initializer> buildInitializer(int fileOffset, Expression value,
+      {bool isSynthetic}) {
+    return _fieldEncoding.createInitializer(fileOffset, value,
+        isSynthetic: isSynthetic);
   }
 
   bool get isEligibleForInference {
@@ -137,81 +192,38 @@
   }
 
   @override
-  Member get readTarget => field;
+  Field get field => _fieldEncoding.field;
 
   @override
-  Member get writeTarget => isAssignable ? field : null;
+  Member get readTarget => _fieldEncoding.readTarget;
 
   @override
-  Member get invokeTarget => field;
+  Member get writeTarget {
+    return isAssignable ? _fieldEncoding.writeTarget : null;
+  }
+
+  @override
+  Member get invokeTarget => readTarget;
 
   @override
   void buildMembers(
       LibraryBuilder library, void Function(Member, BuiltMemberKind) f) {
-    Member member = build(library);
-    f(
-        member,
-        isExtensionMember
-            ? BuiltMemberKind.ExtensionField
-            : BuiltMemberKind.Field);
+    build(library);
+    _fieldEncoding.registerMembers(library, this, f);
   }
 
-  Field build(SourceLibraryBuilder libraryBuilder) {
-    field
-      ..isCovariant = isCovariant
-      ..isFinal = isFinal
-      ..isConst = isConst
-      ..isLate = isLate;
-    if (isExtensionMember) {
-      ExtensionBuilder extension = parent;
-      field.name = new Name('${extension.name}|$name', libraryBuilder.library);
-      field
-        ..hasImplicitGetter = false
-        ..hasImplicitSetter = false
-        ..isStatic = true
-        ..isExtensionMember = true;
-    } else {
-      // TODO(johnniwinther): How can the name already have been computed.
-      field.name ??= new Name(name, libraryBuilder.library);
-      bool isInstanceMember = !isStatic && !isTopLevel;
-      field
-        ..hasImplicitGetter = isInstanceMember
-        ..hasImplicitSetter = isInstanceMember && !isConst && !isFinal
-        ..isStatic = !isInstanceMember
-        ..isExtensionMember = false;
-    }
+  void build(SourceLibraryBuilder libraryBuilder) {
     if (type != null) {
-      field.type = type.build(libraryBuilder);
-
-      if (!isFinal && !isConst) {
-        IncludesTypeParametersNonCovariantly needsCheckVisitor;
-        if (parent is ClassBuilder) {
-          ClassBuilder enclosingClassBuilder = parent;
-          Class enclosingClass = enclosingClassBuilder.cls;
-          if (enclosingClass.typeParameters.isNotEmpty) {
-            needsCheckVisitor = new IncludesTypeParametersNonCovariantly(
-                enclosingClass.typeParameters,
-                // We are checking the field type as if it is the type of the
-                // parameter of the implicit setter and this is a contravariant
-                // position.
-                initialVariance: Variance.contravariant);
-          }
-        }
-        if (needsCheckVisitor != null) {
-          if (field.type.accept(needsCheckVisitor)) {
-            field.isGenericCovariantImpl = true;
-          }
-        }
-      }
+      fieldType = type.build(libraryBuilder);
     }
-    return field;
+    _fieldEncoding.build(libraryBuilder, this);
   }
 
   @override
   void buildOutlineExpressions(LibraryBuilder library) {
     ClassBuilder classBuilder = isClassMember ? parent : null;
     MetadataBuilder.buildAnnotations(
-        field, metadata, library, classBuilder, this);
+        _fieldEncoding.field, metadata, library, classBuilder, this);
 
     // For modular compilation we need to include initializers of all const
     // fields and all non-static final fields in classes with const constructors
@@ -228,31 +240,60 @@
               library, classBuilder, this, scope, fileUri);
       bodyBuilder.constantContext =
           isConst ? ConstantContext.inferred : ConstantContext.required;
-      initializer = bodyBuilder.typeInferrer?.inferFieldInitializer(bodyBuilder,
-          field.type, bodyBuilder.parseFieldInitializer(constInitializerToken));
-      if (library.loader is SourceLoader) {
+      Expression initializer = bodyBuilder.typeInferrer?.inferFieldInitializer(
+          bodyBuilder,
+          fieldType,
+          bodyBuilder.parseFieldInitializer(constInitializerToken));
+      if (library.loader is SourceLoader &&
+          (bodyBuilder.transformSetLiterals ||
+              bodyBuilder.transformCollections)) {
+        // Wrap the initializer in a temporary parent expression; the
+        // transformations need a parent relation.
+        Not wrapper = new Not(initializer);
         SourceLoader loader = library.loader;
-        loader.transformPostInference(field, bodyBuilder.transformSetLiterals,
-            bodyBuilder.transformCollections);
+        loader.transformPostInference(wrapper, bodyBuilder.transformSetLiterals,
+            bodyBuilder.transformCollections, library.library);
+        initializer = wrapper.operand;
       }
+      buildBody(initializer);
       bodyBuilder.resolveRedirectingFactoryTargets();
     }
     constInitializerToken = null;
   }
 
-  @override
-  void inferType() {
-    SourceLibraryBuilder library = this.library;
-    if (field.type is! ImplicitFieldType) {
-      // We have already inferred a type.
-      return;
+  DartType get fieldType => _fieldEncoding.type;
+
+  void set fieldType(DartType value) {
+    _fieldEncoding.type = value;
+    if (!isFinal && !isConst && parent is ClassBuilder) {
+      ClassBuilder enclosingClassBuilder = parent;
+      Class enclosingClass = enclosingClassBuilder.cls;
+      if (enclosingClass.typeParameters.isNotEmpty) {
+        IncludesTypeParametersNonCovariantly needsCheckVisitor =
+            new IncludesTypeParametersNonCovariantly(
+                enclosingClass.typeParameters,
+                // We are checking the field type as if it is the type of the
+                // parameter of the implicit setter and this is a contravariant
+                // position.
+                initialVariance: Variance.contravariant);
+        if (value.accept(needsCheckVisitor)) {
+          _fieldEncoding.setGenericCovariantImpl();
+        }
+      }
     }
-    ImplicitFieldType type = field.type;
-    if (type.memberBuilder != this) {
+  }
+
+  @override
+  DartType inferType() {
+    SourceLibraryBuilder library = this.library;
+    if (fieldType is! ImplicitFieldType) {
+      // We have already inferred a type.
+      return fieldType;
+    }
+    ImplicitFieldType type = fieldType;
+    if (type.fieldBuilder != this) {
       // The implicit type was inherited.
-      FieldBuilder other = type.memberBuilder;
-      other.inferCopiedType(field);
-      return;
+      return fieldType = type.inferType();
     }
     if (type.isStarted) {
       library.addProblem(
@@ -260,30 +301,34 @@
           charOffset,
           name.length,
           fileUri);
-      field.type = const InvalidType();
-      return;
+      return fieldType = const InvalidType();
     }
     type.isStarted = true;
+    InterfaceType enclosingClassThisType = field.enclosingClass == null
+        ? null
+        : library.loader.typeInferenceEngine.coreTypes.thisInterfaceType(
+            field.enclosingClass, field.enclosingLibrary.nonNullable);
     TypeInferrerImpl typeInferrer = library.loader.typeInferenceEngine
-        .createTopLevelTypeInferrer(fileUri, field.enclosingClass?.thisType,
-            library, dataForTesting?.inferenceData);
+        .createTopLevelTypeInferrer(fileUri, enclosingClassThisType, library,
+            dataForTesting?.inferenceData);
     BodyBuilder bodyBuilder =
         library.loader.createBodyBuilderForField(this, typeInferrer);
     bodyBuilder.constantContext =
         isConst ? ConstantContext.inferred : ConstantContext.none;
-    initializer = bodyBuilder.parseFieldInitializer(type.initializerToken);
+    Expression initializer =
+        bodyBuilder.parseFieldInitializer(type.initializerToken);
     type.initializerToken = null;
 
     ExpressionInferenceResult result = typeInferrer.inferExpression(
-        field.initializer, const UnknownType(), true,
+        initializer, const UnknownType(), true,
         isVoidAllowed: true);
     DartType inferredType =
         typeInferrer.inferDeclarationType(result.inferredType);
 
-    if (field.type is ImplicitFieldType) {
-      // `field.type` may have changed if a circularity was detected when
+    if (fieldType is ImplicitFieldType) {
+      // `fieldType` may have changed if a circularity was detected when
       // [inferredType] was computed.
-      field.type = inferredType;
+      fieldType = inferredType;
 
       IncludesTypeParametersNonCovariantly needsCheckVisitor;
       if (parent is ClassBuilder) {
@@ -299,24 +344,543 @@
         }
       }
       if (needsCheckVisitor != null) {
-        if (field.type.accept(needsCheckVisitor)) {
+        if (fieldType.accept(needsCheckVisitor)) {
           field.isGenericCovariantImpl = true;
         }
       }
     }
-
-    // The following is a hack. The outline should contain the compiled
-    // initializers, however, as top-level inference is subtly different from
-    // we need to compile the field initializer again when everything else is
-    // compiled.
-    field.initializer = null;
+    return fieldType;
   }
 
-  void inferCopiedType(Field other) {
-    inferType();
-    other.type = field.type;
-    other.initializer = null;
+  DartType get builtType => fieldType;
+
+  @override
+  List<ClassMember> get localMembers => _fieldEncoding.getLocalMembers(this);
+
+  @override
+  List<ClassMember> get localSetters => _fieldEncoding.getLocalSetters(this);
+}
+
+/// Strategy pattern for creating different encodings of a declared field.
+///
+/// This is used to provide lowerings for late fields using synthesized getters
+/// and setters.
+abstract class FieldEncoding {
+  /// The type of the declared field.
+  DartType type;
+
+  /// Creates the bodies needed for the field encoding using [initializer] as
+  /// the declared initializer expression.
+  ///
+  /// This method is not called for fields in outlines unless their are constant
+  /// or part of a const constructor.
+  void createBodies(Expression initializer);
+
+  List<Initializer> createInitializer(int fileOffset, Expression value,
+      {bool isSynthetic});
+
+  /// Registers that the (implicit) setter associated with this field needs to
+  /// contain a runtime type check to deal with generic covariance.
+  void setGenericCovariantImpl();
+
+  /// Returns the field that holds the field value at runtime.
+  Field get field;
+
+  /// Returns the member used to read the field value.
+  Member get readTarget;
+
+  /// Returns the member used to write to the field.
+  Member get writeTarget;
+
+  /// Creates the members necessary for this field encoding.
+  ///
+  /// This method is called for both outline and full compilation so the created
+  /// members should be without body. The member bodies are created through
+  /// [createBodies].
+  void build(
+      SourceLibraryBuilder libraryBuilder, SourceFieldBuilder fieldBuilder);
+
+  /// Calls [f] for each member needed for this field encoding.
+  void registerMembers(
+      SourceLibraryBuilder library,
+      SourceFieldBuilder fieldBuilder,
+      void Function(Member, BuiltMemberKind) f);
+
+  List<ClassMember> getLocalMembers(SourceFieldBuilder fieldBuilder);
+
+  List<ClassMember> getLocalSetters(SourceFieldBuilder fieldBuilder);
+}
+
+class RegularFieldEncoding implements FieldEncoding {
+  Field _field;
+
+  RegularFieldEncoding(Uri fileUri, int charOffset, int charEndOffset) {
+    _field = new Field(null, fileUri: fileUri)
+      ..fileOffset = charOffset
+      ..fileEndOffset = charEndOffset;
   }
 
-  DartType get builtType => field.type;
+  @override
+  DartType get type => _field.type;
+
+  @override
+  void set type(DartType value) {
+    _field.type = value;
+  }
+
+  @override
+  void createBodies(Expression initializer) {
+    if (initializer != null) {
+      _field.initializer = initializer..parent = _field;
+    }
+  }
+
+  @override
+  List<Initializer> createInitializer(int fileOffset, Expression value,
+      {bool isSynthetic}) {
+    return <Initializer>[
+      new FieldInitializer(_field, value)
+        ..fileOffset = fileOffset
+        ..isSynthetic = isSynthetic
+    ];
+  }
+
+  @override
+  void build(
+      SourceLibraryBuilder libraryBuilder, SourceFieldBuilder fieldBuilder) {
+    _field
+      ..isCovariant = fieldBuilder.isCovariant
+      ..isFinal = fieldBuilder.isFinal
+      ..isConst = fieldBuilder.isConst;
+    String fieldName;
+    if (fieldBuilder.isExtensionMember) {
+      ExtensionBuilder extension = fieldBuilder.parent;
+      fieldName = '${extension.name}|${fieldBuilder.name}';
+      _field
+        ..hasImplicitGetter = false
+        ..hasImplicitSetter = false
+        ..isStatic = true
+        ..isExtensionMember = true;
+    } else {
+      fieldName = fieldBuilder.name;
+      bool isInstanceMember =
+          !fieldBuilder.isStatic && !fieldBuilder.isTopLevel;
+      _field
+        ..hasImplicitGetter = isInstanceMember
+        ..hasImplicitSetter =
+            isInstanceMember && !fieldBuilder.isConst && !fieldBuilder.isFinal
+        ..isStatic = !isInstanceMember
+        ..isExtensionMember = false;
+    }
+    // TODO(johnniwinther): How can the name already have been computed?
+    _field.name ??= new Name(fieldName, libraryBuilder.library);
+    _field.isLate = fieldBuilder.isLate;
+  }
+
+  @override
+  void registerMembers(
+      SourceLibraryBuilder library,
+      SourceFieldBuilder fieldBuilder,
+      void Function(Member, BuiltMemberKind) f) {
+    f(
+        _field,
+        fieldBuilder.isExtensionMember
+            ? BuiltMemberKind.ExtensionField
+            : BuiltMemberKind.Field);
+  }
+
+  @override
+  void setGenericCovariantImpl() {
+    _field.isGenericCovariantImpl = true;
+  }
+
+  @override
+  Field get field => _field;
+
+  @override
+  Member get readTarget => _field;
+
+  @override
+  Member get writeTarget => _field;
+
+  @override
+  List<ClassMember> getLocalMembers(SourceFieldBuilder fieldBuilder) =>
+      <ClassMember>[fieldBuilder];
+
+  @override
+  List<ClassMember> getLocalSetters(SourceFieldBuilder fieldBuilder) =>
+      const <ClassMember>[];
+}
+
+abstract class AbstractLateFieldEncoding implements FieldEncoding {
+  final String name;
+  final int fileOffset;
+  DartType _type;
+  Field _field;
+  Field _lateIsSetField;
+  Procedure _lateGetter;
+  Procedure _lateSetter;
+
+  AbstractLateFieldEncoding(
+      this.name, Uri fileUri, int charOffset, int charEndOffset)
+      : fileOffset = charOffset {
+    _field = new Field(null, fileUri: fileUri)
+      ..fileOffset = charOffset
+      ..fileEndOffset = charEndOffset;
+    _lateIsSetField = new Field(null, fileUri: fileUri)
+      ..fileOffset = charOffset
+      ..fileEndOffset = charEndOffset;
+    _lateGetter = new Procedure(
+        null, ProcedureKind.Getter, new FunctionNode(null),
+        fileUri: fileUri)
+      ..fileOffset = charOffset;
+    _lateSetter = _createSetter(name, fileUri, charOffset);
+  }
+
+  @override
+  void createBodies(Expression initializer) {
+    assert(_type != null, "Type has not been computed for field $name.");
+    _field.initializer = new NullLiteral()..parent = _field;
+    if (_type.isPotentiallyNullable) {
+      _lateIsSetField.initializer = new BoolLiteral(false)
+        ..parent = _lateIsSetField;
+    }
+    _lateGetter.function.body = _createGetterBody(name, initializer)
+      ..parent = _lateGetter.function;
+    if (_lateSetter != null) {
+      _lateSetter.function.body = _createSetterBody(
+          name, _lateSetter.function.positionalParameters.first)
+        ..parent = _lateSetter.function;
+    }
+  }
+
+  @override
+  List<Initializer> createInitializer(int fileOffset, Expression value,
+      {bool isSynthetic}) {
+    List<Initializer> initializers = <Initializer>[];
+    if (_lateIsSetField != null) {
+      initializers.add(new FieldInitializer(
+          _lateIsSetField, new BoolLiteral(true)..fileOffset = fileOffset)
+        ..fileOffset = fileOffset
+        ..isSynthetic = isSynthetic);
+    }
+    initializers.add(new FieldInitializer(_field, value)
+      ..fileOffset = fileOffset
+      ..isSynthetic = isSynthetic);
+    return initializers;
+  }
+
+  Expression _createFieldGet(Field field) {
+    if (field.isStatic) {
+      return new StaticGet(field)..fileOffset = fileOffset;
+    } else {
+      return new PropertyGet(
+          new ThisExpression()..fileOffset = fileOffset, field.name, field)
+        ..fileOffset = fileOffset;
+    }
+  }
+
+  Expression _createFieldSet(Field field, Expression value) {
+    if (field.isStatic) {
+      return new StaticSet(field, value)..fileOffset = fileOffset;
+    } else {
+      return new PropertySet(new ThisExpression()..fileOffset = fileOffset,
+          field.name, value, field)
+        ..fileOffset = fileOffset;
+    }
+  }
+
+  Statement _createGetterBody(String name, Expression initializer);
+
+  Procedure _createSetter(String name, Uri fileUri, int charOffset) {
+    VariableDeclaration parameter = new VariableDeclaration(null);
+    return new Procedure(
+        null,
+        ProcedureKind.Setter,
+        new FunctionNode(null,
+            positionalParameters: [parameter], returnType: const VoidType()),
+        fileUri: fileUri)
+      ..fileOffset = charOffset;
+  }
+
+  Statement _createSetterBody(String name, VariableDeclaration parameter);
+
+  @override
+  DartType get type => _type;
+
+  @override
+  void set type(DartType value) {
+    assert(_type == null, "Type has already been computed for field $name.");
+    _type = value;
+    _field.type = value.withNullability(Nullability.nullable);
+    _lateGetter.function.returnType = value;
+    if (_lateSetter != null) {
+      _lateSetter.function.positionalParameters.single.type = value;
+    }
+    if (!_type.isPotentiallyNullable) {
+      // We only need the is-set field if the field is potentially nullable.
+      //  Otherwise we use `null` to signal that the field is uninitialized.
+      _lateIsSetField = null;
+    }
+  }
+
+  @override
+  void setGenericCovariantImpl() {
+    // TODO(johnniwinther): Is this correct? Should the [_lateSetter] be
+    //  annotated instead?
+    _field.isGenericCovariantImpl = true;
+  }
+
+  @override
+  Field get field => _field;
+
+  @override
+  Member get readTarget => _lateGetter;
+
+  @override
+  Member get writeTarget => _lateSetter;
+
+  @override
+  void build(
+      SourceLibraryBuilder libraryBuilder, SourceFieldBuilder fieldBuilder) {
+    _field..isCovariant = fieldBuilder.isCovariant;
+    String fieldName;
+    bool isInstanceMember;
+    bool isExtensionMember = fieldBuilder.isExtensionMember;
+    if (isExtensionMember) {
+      ExtensionBuilder extension = fieldBuilder.parent;
+      fieldName = '${extension.name}|${fieldBuilder.name}';
+      _field
+        ..hasImplicitGetter = false
+        ..hasImplicitSetter = false
+        ..isStatic = true
+        ..isExtensionMember = isExtensionMember;
+      isInstanceMember = false;
+    } else {
+      isInstanceMember = !fieldBuilder.isStatic && !fieldBuilder.isTopLevel;
+      fieldName = fieldBuilder.name;
+      _field
+        ..hasImplicitGetter = isInstanceMember
+        ..hasImplicitSetter = isInstanceMember
+        ..isStatic = !isInstanceMember
+        ..isExtensionMember = false;
+    }
+    _field.name ??= new Name('_#$fieldName', libraryBuilder.library);
+    if (_lateIsSetField != null) {
+      _lateIsSetField
+        ..name = new Name('_#$fieldName#isSet', libraryBuilder.library)
+        ..isStatic = !isInstanceMember
+        ..hasImplicitGetter = isInstanceMember
+        ..hasImplicitSetter = isInstanceMember
+        ..isStatic = _field.isStatic
+        ..isExtensionMember = isExtensionMember;
+      // TODO(johnniwinther): Provide access to a `bool` type here.
+      /*_lateIsSetField.type =
+          libraryBuilder.loader.coreTypes.boolNonNullableRawType;*/
+    }
+    _lateGetter
+      ..name = new Name(fieldName, libraryBuilder.library)
+      ..isStatic = !isInstanceMember
+      ..isExtensionMember = isExtensionMember;
+    if (_lateSetter != null) {
+      _lateSetter
+        ..name = new Name(fieldName, libraryBuilder.library)
+        ..isStatic = !isInstanceMember
+        ..isExtensionMember = isExtensionMember;
+    }
+  }
+
+  @override
+  void registerMembers(
+      SourceLibraryBuilder library,
+      SourceFieldBuilder fieldBuilder,
+      void Function(Member, BuiltMemberKind) f) {
+    f(
+        _field,
+        fieldBuilder.isExtensionMember
+            ? BuiltMemberKind.ExtensionField
+            : BuiltMemberKind.Field);
+    if (_lateIsSetField != null) {
+      f(_lateIsSetField, BuiltMemberKind.LateIsSetField);
+    }
+    f(_lateGetter, BuiltMemberKind.LateGetter);
+    if (_lateSetter != null) {
+      f(_lateSetter, BuiltMemberKind.LateSetter);
+    }
+  }
+
+  @override
+  List<ClassMember> getLocalMembers(SourceFieldBuilder fieldBuilder) {
+    List<ClassMember> list = <ClassMember>[
+      new _ClassMember(fieldBuilder, field),
+      new _ClassMember(fieldBuilder, _lateGetter)
+    ];
+    if (_lateIsSetField != null) {
+      list.add(new _ClassMember(fieldBuilder, _lateIsSetField));
+    }
+    return list;
+  }
+
+  @override
+  List<ClassMember> getLocalSetters(SourceFieldBuilder fieldBuilder) {
+    return _lateSetter == null
+        ? const <ClassMember>[]
+        : <ClassMember>[new _ClassMember(fieldBuilder, _lateSetter)];
+  }
+}
+
+mixin NonFinalLate on AbstractLateFieldEncoding {
+  @override
+  Statement _createSetterBody(String name, VariableDeclaration parameter) {
+    assert(_type != null, "Type has not been computed for field $name.");
+    return late_lowering.createSetterBody(fileOffset, name, parameter, _type,
+        shouldReturnValue: false,
+        createVariableWrite: (Expression value) =>
+            _createFieldSet(_field, value),
+        createIsSetWrite: (Expression value) =>
+            _createFieldSet(_lateIsSetField, value));
+  }
+}
+
+mixin LateWithInitializer on AbstractLateFieldEncoding {
+  @override
+  Statement _createGetterBody(String name, Expression initializer) {
+    assert(_type != null, "Type has not been computed for field $name.");
+    return late_lowering.createGetterWithInitializer(
+        fileOffset, name, _type, initializer,
+        createVariableRead: () => _createFieldGet(_field),
+        createVariableWrite: (Expression value) =>
+            _createFieldSet(_field, value),
+        createIsSetRead: () => _createFieldGet(_lateIsSetField),
+        createIsSetWrite: (Expression value) =>
+            _createFieldSet(_lateIsSetField, value));
+  }
+
+  @override
+  void createBodies(Expression initializer) {
+    super.createBodies(initializer);
+  }
+}
+
+mixin LateWithoutInitializer on AbstractLateFieldEncoding {
+  @override
+  Statement _createGetterBody(String name, Expression initializer) {
+    assert(_type != null, "Type has not been computed for field $name.");
+    return late_lowering.createGetterBodyWithoutInitializer(
+        fileOffset, name, type, 'Field',
+        createVariableRead: () => _createFieldGet(_field),
+        createIsSetRead: () => _createFieldGet(_lateIsSetField));
+  }
+}
+
+class LateFieldWithoutInitializerEncoding extends AbstractLateFieldEncoding
+    with NonFinalLate, LateWithoutInitializer {
+  LateFieldWithoutInitializerEncoding(
+      String name, Uri fileUri, int charOffset, int charEndOffset)
+      : super(name, fileUri, charOffset, charEndOffset);
+}
+
+class LateFieldWithInitializerEncoding extends AbstractLateFieldEncoding
+    with NonFinalLate, LateWithInitializer {
+  LateFieldWithInitializerEncoding(
+      String name, Uri fileUri, int charOffset, int charEndOffset)
+      : super(name, fileUri, charOffset, charEndOffset);
+}
+
+class LateFinalFieldWithoutInitializerEncoding extends AbstractLateFieldEncoding
+    with LateWithoutInitializer {
+  LateFinalFieldWithoutInitializerEncoding(
+      String name, Uri fileUri, int charOffset, int charEndOffset)
+      : super(name, fileUri, charOffset, charEndOffset);
+
+  @override
+  Statement _createSetterBody(String name, VariableDeclaration parameter) {
+    assert(_type != null, "Type has not been computed for field $name.");
+    return late_lowering.createSetterBodyFinal(
+        fileOffset, name, parameter, type, 'Field',
+        shouldReturnValue: false,
+        createVariableRead: () => _createFieldGet(_field),
+        createVariableWrite: (Expression value) =>
+            _createFieldSet(_field, value),
+        createIsSetRead: () => _createFieldGet(_lateIsSetField),
+        createIsSetWrite: (Expression value) =>
+            _createFieldSet(_lateIsSetField, value));
+  }
+}
+
+class LateFinalFieldWithInitializerEncoding extends AbstractLateFieldEncoding
+    with LateWithInitializer {
+  LateFinalFieldWithInitializerEncoding(
+      String name, Uri fileUri, int charOffset, int charEndOffset)
+      : super(name, fileUri, charOffset, charEndOffset);
+
+  @override
+  Procedure _createSetter(String name, Uri fileUri, int charOffset) => null;
+
+  @override
+  Statement _createSetterBody(String name, VariableDeclaration parameter) =>
+      null;
+}
+
+class _ClassMember implements ClassMember {
+  final SourceFieldBuilder fieldBuilder;
+
+  @override
+  final Member member;
+
+  _ClassMember(this.fieldBuilder, this.member);
+
+  @override
+  ClassBuilder get classBuilder => fieldBuilder.classBuilder;
+
+  @override
+  bool get isDuplicate => fieldBuilder.isDuplicate;
+
+  @override
+  bool get isStatic => fieldBuilder.isStatic;
+
+  @override
+  bool get isField => member is Field;
+
+  @override
+  bool get isAssignable {
+    Member field = member;
+    return field is Field && field.hasSetter;
+  }
+
+  @override
+  bool get isSetter {
+    Member procedure = member;
+    return procedure is Procedure && procedure.kind == ProcedureKind.Setter;
+  }
+
+  @override
+  bool get isGetter {
+    Member procedure = member;
+    return procedure is Procedure && procedure.kind == ProcedureKind.Getter;
+  }
+
+  @override
+  bool get isFinal {
+    Member field = member;
+    return field is Field && field.isFinal;
+  }
+
+  @override
+  bool get isConst {
+    Member field = member;
+    return field is Field && field.isConst;
+  }
+
+  @override
+  String get fullNameForErrors => fieldBuilder.fullNameForErrors;
+
+  @override
+  Uri get fileUri => fieldBuilder.fileUri;
+
+  @override
+  int get charOffset => fieldBuilder.charOffset;
+
+  @override
+  String toString() => '_ClassMember($fieldBuilder,$member)';
 }
diff --git a/pkg/front_end/lib/src/fasta/builder/fixed_type_builder.dart b/pkg/front_end/lib/src/fasta/builder/fixed_type_builder.dart
index 3bbc2f1..8d18032 100644
--- a/pkg/front_end/lib/src/fasta/builder/fixed_type_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/fixed_type_builder.dart
@@ -28,7 +28,7 @@
     return buffer;
   }
 
-  DartType build(LibraryBuilder library) => type;
+  DartType build(LibraryBuilder library, [TypedefType origin]) => type;
 
   Supertype buildSupertype(
       LibraryBuilder library, int charOffset, Uri fileUri) {
diff --git a/pkg/front_end/lib/src/fasta/builder/formal_parameter_builder.dart b/pkg/front_end/lib/src/fasta/builder/formal_parameter_builder.dart
index b85d421..14cc3ac 100644
--- a/pkg/front_end/lib/src/fasta/builder/formal_parameter_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/formal_parameter_builder.dart
@@ -29,7 +29,7 @@
 
 import '../kernel/body_builder.dart' show BodyBuilder;
 
-import '../kernel/kernel_shadow_ast.dart' show VariableDeclarationImpl;
+import '../kernel/internal_ast.dart' show VariableDeclarationImpl;
 
 import 'builder.dart';
 import 'class_builder.dart';
@@ -67,6 +67,8 @@
   /// [buildOutlineExpressions].
   Token initializerToken;
 
+  bool initializerWasInferred = false;
+
   FormalParameterBuilder(this.metadata, this.modifiers, this.type, this.name,
       LibraryBuilder compilationUnit, int charOffset,
       [Uri fileUri])
@@ -174,6 +176,7 @@
           .createBodyBuilderForOutlineExpression(
               library, classBuilder, this, scope, fileUri);
       bodyBuilder.constantContext = ConstantContext.required;
+      assert(!initializerWasInferred);
       Expression initializer =
           bodyBuilder.parseFieldInitializer(initializerToken);
       initializer = bodyBuilder.typeInferrer
@@ -181,9 +184,13 @@
       variable.initializer = initializer..parent = variable;
       if (library.loader is SourceLoader) {
         SourceLoader loader = library.loader;
-        loader.transformPostInference(variable,
-            bodyBuilder.transformSetLiterals, bodyBuilder.transformCollections);
+        loader.transformPostInference(
+            variable,
+            bodyBuilder.transformSetLiterals,
+            bodyBuilder.transformCollections,
+            library.library);
       }
+      initializerWasInferred = true;
       bodyBuilder.resolveRedirectingFactoryTargets();
     }
     initializerToken = null;
diff --git a/pkg/front_end/lib/src/fasta/builder/function_builder.dart b/pkg/front_end/lib/src/fasta/builder/function_builder.dart
index bd2d60d..15d3f43 100644
--- a/pkg/front_end/lib/src/fasta/builder/function_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/function_builder.dart
@@ -11,10 +11,11 @@
 
 import 'package:kernel/type_algebra.dart';
 
+import '../identifiers.dart';
 import '../scope.dart';
 
-import '../kernel/kernel_shadow_ast.dart' show VariableDeclarationImpl;
-
+import '../kernel/class_hierarchy_builder.dart' show ClassMember;
+import '../kernel/internal_ast.dart' show VariableDeclarationImpl;
 import '../kernel/redirecting_factory_body.dart' show RedirectingFactoryBody;
 
 import '../loader.dart' show Loader;
@@ -87,7 +88,7 @@
   /// to support generic methods.
   Scope computeTypeParameterScope(Scope parent);
 
-  FormalParameterBuilder getFormal(String name);
+  FormalParameterBuilder getFormal(Identifier identifier);
 
   String get nativeMethodName;
 
@@ -274,11 +275,16 @@
   }
 
   @override
-  FormalParameterBuilder getFormal(String name) {
+  FormalParameterBuilder getFormal(Identifier identifier) {
     if (formals != null) {
       for (FormalParameterBuilder formal in formals) {
-        if (formal.name == name) return formal;
+        if (formal.name == identifier.name &&
+            formal.charOffset == identifier.charOffset) {
+          return formal;
+        }
       }
+      // If we have any formals we should find the one we're looking for.
+      assert(false, "$identifier not found in $formals");
     }
     return null;
   }
@@ -531,4 +537,12 @@
       messagePatchDeclarationOrigin.withLocation(fileUri, charOffset, noLength)
     ]);
   }
+
+  @override
+  List<ClassMember> get localMembers =>
+      isSetter ? const <ClassMember>[] : <ClassMember>[this];
+
+  @override
+  List<ClassMember> get localSetters =>
+      isSetter ? <ClassMember>[this] : const <ClassMember>[];
 }
diff --git a/pkg/front_end/lib/src/fasta/builder/member_builder.dart b/pkg/front_end/lib/src/fasta/builder/member_builder.dart
index 6e0219e..5e5a6d0 100644
--- a/pkg/front_end/lib/src/fasta/builder/member_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/member_builder.dart
@@ -55,9 +55,19 @@
 
   void buildOutlineExpressions(LibraryBuilder library);
 
-  void inferType();
+  /// Returns the [ClassMember]s for the non-setter members created for this
+  /// member builder.
+  ///
+  /// This is normally the member itself, if not a setter, but for instance for
+  /// lowered late fields this can be synthesized members.
+  List<ClassMember> get localMembers;
 
-  void inferCopiedType(covariant Object other);
+  /// Returns the [ClassMember]s for the setters created for this member
+  /// builder.
+  ///
+  /// This is normally the member itself, if a setter, but for instance
+  /// lowered late fields this can be synthesized setters.
+  List<ClassMember> get localSetters;
 }
 
 abstract class MemberBuilderImpl extends ModifierBuilderImpl
@@ -132,14 +142,6 @@
   String get fullNameForErrors => name;
 
   @override
-  void inferType() => unsupported("inferType", charOffset, fileUri);
-
-  @override
-  void inferCopiedType(covariant Object other) {
-    unsupported("inferType", charOffset, fileUri);
-  }
-
-  @override
   ClassBuilder get classBuilder => parent is ClassBuilder ? parent : null;
 }
 
@@ -154,6 +156,9 @@
   ExtensionSetter,
   ExtensionOperator,
   ExtensionTearOff,
+  LateIsSetField,
+  LateGetter,
+  LateSetter,
 }
 
 class MemberDataForTesting {
diff --git a/pkg/front_end/lib/src/fasta/builder/mixin_application_builder.dart b/pkg/front_end/lib/src/fasta/builder/mixin_application_builder.dart
index a9a572d..4387c8e 100644
--- a/pkg/front_end/lib/src/fasta/builder/mixin_application_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/mixin_application_builder.dart
@@ -4,7 +4,7 @@
 
 library fasta.mixin_application_builder;
 
-import 'package:kernel/ast.dart' show InterfaceType, Supertype;
+import 'package:kernel/ast.dart' show InterfaceType, Supertype, TypedefType;
 
 import '../problems.dart' show unsupported;
 
@@ -43,7 +43,7 @@
   }
 
   @override
-  InterfaceType build(LibraryBuilder library) {
+  InterfaceType build(LibraryBuilder library, [TypedefType origin]) {
     int charOffset = -1; // TODO(ahe): Provide these.
     Uri fileUri = null; // TODO(ahe): Provide these.
     return unsupported("build", charOffset, fileUri);
diff --git a/pkg/front_end/lib/src/fasta/builder/named_type_builder.dart b/pkg/front_end/lib/src/fasta/builder/named_type_builder.dart
index a653514..8991ca3 100644
--- a/pkg/front_end/lib/src/fasta/builder/named_type_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/named_type_builder.dart
@@ -6,7 +6,7 @@
 
 import 'package:_fe_analyzer_shared/src/messages/severity.dart' show Severity;
 
-import 'package:kernel/ast.dart' show DartType, Supertype;
+import 'package:kernel/ast.dart' show DartType, Supertype, TypedefType;
 
 import '../fasta_codes.dart'
     show
@@ -204,7 +204,8 @@
     return null;
   }
 
-  DartType build(LibraryBuilder library) {
+  // TODO(johnniwinther): Store [origin] on the built type.
+  DartType build(LibraryBuilder library, [TypedefType origin]) {
     assert(declaration != null, "Declaration has not been resolved on $this.");
     return declaration.buildType(library, nullabilityBuilder, arguments);
   }
diff --git a/pkg/front_end/lib/src/fasta/builder/procedure_builder.dart b/pkg/front_end/lib/src/fasta/builder/procedure_builder.dart
index 766bb6d..dc46cb5 100644
--- a/pkg/front_end/lib/src/fasta/builder/procedure_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/procedure_builder.dart
@@ -321,7 +321,8 @@
       TypeParameter newTypeParameter = new TypeParameter(typeParameter.name);
       typeParameters.add(newTypeParameter);
       typeArguments.add(substitutionMap[typeParameter] =
-          new TypeParameterType(newTypeParameter, Nullability.legacy));
+          new TypeParameterType.forAlphaRenaming(
+              typeParameter, newTypeParameter));
     }
 
     List<TypeParameter> tearOffTypeParameters = <TypeParameter>[];
@@ -536,8 +537,9 @@
       if (function.typeParameters != null) {
         Map<TypeParameter, DartType> substitution = <TypeParameter, DartType>{};
         for (int i = 0; i < function.typeParameters.length; i++) {
-          substitution[function.typeParameters[i]] = new TypeParameterType(
-              actualOrigin.function.typeParameters[i], Nullability.legacy);
+          substitution[function.typeParameters[i]] =
+              new TypeParameterType.withDefaultNullabilityForLibrary(
+                  actualOrigin.function.typeParameters[i], library.library);
         }
         List<DartType> newTypeArguments =
             new List<DartType>(typeArguments.length);
diff --git a/pkg/front_end/lib/src/fasta/builder/type_alias_builder.dart b/pkg/front_end/lib/src/fasta/builder/type_alias_builder.dart
index c284797..7b36c75 100644
--- a/pkg/front_end/lib/src/fasta/builder/type_alias_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/type_alias_builder.dart
@@ -4,16 +4,19 @@
 
 library fasta.function_type_alias_builder;
 
+import 'package:front_end/src/fasta/builder/fixed_type_builder.dart';
+import 'package:front_end/src/fasta/builder/named_type_builder.dart';
 import 'package:kernel/ast.dart'
     show
         DartType,
         DynamicType,
-        FunctionType,
         InvalidType,
         Nullability,
         TypeParameter,
         Typedef,
-        VariableDeclaration;
+        TypedefType,
+        VariableDeclaration,
+        getAsTypeArguments;
 
 import 'package:kernel/type_algebra.dart'
     show FreshTypeParameters, getFreshTypeParameters, substitute;
@@ -86,6 +89,8 @@
           }
         }
       }
+    } else if (type is NamedTypeBuilder || type is FixedTypeBuilder) {
+      // No error, but also no additional setup work.
     } else if (type != null) {
       unhandled("${type.fullNameForErrors}", "build", charOffset, fileUri);
     }
@@ -93,6 +98,38 @@
     return typedef;
   }
 
+  TypedefType thisTypedefType(Typedef typedef, LibraryBuilder clientLibrary) {
+    // At this point the bounds of `typedef.typeParameters` may not be assigned
+    // yet, so [getAsTypeArguments] may crash trying to compute the nullability
+    // of the created types from the bounds.  To avoid that, we use "dynamic"
+    // for the bound of all boundless variables and add them to the list for
+    // being recomputed later, when the bounds are assigned.
+    List<DartType> bounds =
+        new List<DartType>.filled(typedef.typeParameters.length, null);
+    for (int i = 0; i < bounds.length; ++i) {
+      bounds[i] = typedef.typeParameters[i].bound;
+      if (bounds[i] == null) {
+        typedef.typeParameters[i].bound = const DynamicType();
+      }
+    }
+    List<DartType> asTypeArguments =
+        getAsTypeArguments(typedef.typeParameters, clientLibrary.library);
+    TypedefType result =
+        new TypedefType(typedef, clientLibrary.nonNullable, asTypeArguments);
+    for (int i = 0; i < bounds.length; ++i) {
+      if (bounds[i] == null) {
+        // If the bound is not assigned yet, put the corresponding
+        // type-parameter type into the list for the nullability re-computation.
+        // At this point, [parent] should be a [SourceLibraryBuilder] because
+        // otherwise it's a compiled library loaded from a dill file, and the
+        // bounds should have been assigned.
+        SourceLibraryBuilder parentLibrary = parent;
+        parentLibrary.pendingNullabilities.add(asTypeArguments[i]);
+      }
+    }
+    return result;
+  }
+
   DartType buildThisType(LibraryBuilder library) {
     if (thisType != null) {
       if (identical(thisType, cyclicTypeAliasMarker)) {
@@ -107,8 +144,9 @@
     // instance of InvalidType that isn't identical to `const InvalidType()`.
     thisType = cyclicTypeAliasMarker;
     TypeBuilder type = this.type;
-    if (type is FunctionTypeBuilder) {
-      FunctionType builtType = type?.build(library, typedef.thisType);
+    if (type != null) {
+      DartType builtType =
+          type.build(library, thisTypedefType(typedef, library));
       if (builtType != null) {
         if (typeVariables != null) {
           for (TypeVariableBuilder tv in typeVariables) {
@@ -120,12 +158,8 @@
       } else {
         return thisType = const InvalidType();
       }
-    } else if (type == null) {
-      return thisType = const InvalidType();
-    } else {
-      return unhandled(
-          "${type.fullNameForErrors}", "buildThisType", charOffset, fileUri);
     }
+    return thisType = const InvalidType();
   }
 
   /// [arguments] have already been built.
@@ -133,7 +167,7 @@
       Nullability nullability, List<DartType> arguments) {
     DartType thisType = buildThisType(library);
     if (const DynamicType() == thisType) return thisType;
-    FunctionType result = thisType.withNullability(nullability);
+    DartType result = thisType.withNullability(nullability);
     if (typedef.typeParameters.isEmpty && arguments == null) return result;
     Map<TypeParameter, DartType> substitution = <TypeParameter, DartType>{};
     for (int i = 0; i < typedef.typeParameters.length; i++) {
diff --git a/pkg/front_end/lib/src/fasta/builder/type_builder.dart b/pkg/front_end/lib/src/fasta/builder/type_builder.dart
index 7a8440e..f365eb2 100644
--- a/pkg/front_end/lib/src/fasta/builder/type_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/type_builder.dart
@@ -4,7 +4,7 @@
 
 library fasta.type_builder;
 
-import 'package:kernel/ast.dart' show DartType, Supertype;
+import 'package:kernel/ast.dart' show DartType, Supertype, TypedefType;
 
 import '../scope.dart';
 import 'library_builder.dart';
@@ -58,7 +58,7 @@
 
   String get fullNameForErrors => "${printOn(new StringBuffer())}";
 
-  DartType build(LibraryBuilder library);
+  DartType build(LibraryBuilder library, [TypedefType origin]);
 
   Supertype buildSupertype(LibraryBuilder library, int charOffset, Uri fileUri);
 
diff --git a/pkg/front_end/lib/src/fasta/builder/type_variable_builder.dart b/pkg/front_end/lib/src/fasta/builder/type_variable_builder.dart
index 4e7da64..1e5c652 100644
--- a/pkg/front_end/lib/src/fasta/builder/type_variable_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/type_variable_builder.dart
@@ -114,7 +114,6 @@
 
   DartType buildTypesWithBuiltArguments(LibraryBuilder library,
       Nullability nullability, List<DartType> arguments) {
-    // TODO(dmitryas): Use [nullability].
     if (arguments != null) {
       int charOffset = -1; // TODO(ahe): Provide these.
       Uri fileUri = null; // TODO(ahe): Provide these.
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_member_builder.dart b/pkg/front_end/lib/src/fasta/dill/dill_member_builder.dart
index d384778..a496c3f 100644
--- a/pkg/front_end/lib/src/fasta/dill/dill_member_builder.dart
+++ b/pkg/front_end/lib/src/fasta/dill/dill_member_builder.dart
@@ -11,6 +11,7 @@
 import '../builder/member_builder.dart';
 import '../builder/library_builder.dart';
 
+import '../kernel/class_hierarchy_builder.dart' show ClassMember;
 import '../kernel/kernel_builder.dart'
     show isRedirectingGenerativeConstructorImplementation;
 
@@ -127,6 +128,14 @@
       LibraryBuilder library, void Function(Member, BuiltMemberKind) f) {
     throw new UnsupportedError('DillMemberBuilder.buildMembers');
   }
+
+  @override
+  List<ClassMember> get localMembers =>
+      isSetter ? const <ClassMember>[] : <ClassMember>[this];
+
+  @override
+  List<ClassMember> get localSetters =>
+      isSetter ? <ClassMember>[this] : const <ClassMember>[];
 }
 
 int computeModifiers(Member member) {
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_target.dart b/pkg/front_end/lib/src/fasta/dill/dill_target.dart
index b79b11a..9c3ff9a 100644
--- a/pkg/front_end/lib/src/fasta/dill/dill_target.dart
+++ b/pkg/front_end/lib/src/fasta/dill/dill_target.dart
@@ -72,4 +72,8 @@
     libraryBuilders[library.importUri] =
         new DillLibraryBuilder(library, loader);
   }
+
+  void releaseAncillaryResources() {
+    libraryBuilders.clear();
+  }
 }
diff --git a/pkg/front_end/lib/src/fasta/fasta_codes_cfe_generated.dart b/pkg/front_end/lib/src/fasta/fasta_codes_cfe_generated.dart
index d9a60cb..2cd6217 100644
--- a/pkg/front_end/lib/src/fasta/fasta_codes_cfe_generated.dart
+++ b/pkg/front_end/lib/src/fasta/fasta_codes_cfe_generated.dart
@@ -1282,46 +1282,6 @@
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Template<
     Message Function(
-        String name,
-        DartType _type,
-        DartType
-            _type2)> templateIntersectionTypeAsTypeArgument = const Template<
-        Message Function(String name, DartType _type, DartType _type2)>(
-    messageTemplate:
-        r"""Can't infer a type for '#name', it can be either '#type' or '#type2'.""",
-    tipTemplate:
-        r"""Try adding a type argument selecting one of the options.""",
-    withArguments: _withArgumentsIntersectionTypeAsTypeArgument);
-
-// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const Code<Message Function(String name, DartType _type, DartType _type2)>
-    codeIntersectionTypeAsTypeArgument =
-    const Code<Message Function(String name, DartType _type, DartType _type2)>(
-  "IntersectionTypeAsTypeArgument",
-  templateIntersectionTypeAsTypeArgument,
-);
-
-// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-Message _withArgumentsIntersectionTypeAsTypeArgument(
-    String name, DartType _type, DartType _type2) {
-  if (name.isEmpty) throw 'No name provided';
-  name = demangleMixinApplicationName(name);
-  TypeLabeler labeler = new TypeLabeler();
-  List<Object> typeParts = labeler.labelType(_type);
-  List<Object> type2Parts = labeler.labelType(_type2);
-  String type = typeParts.join();
-  String type2 = type2Parts.join();
-  return new Message(codeIntersectionTypeAsTypeArgument,
-      message:
-          """Can't infer a type for '${name}', it can be either '${type}' or '${type2}'.""" +
-              labeler.originMessages,
-      tip: """Try adding a type argument selecting one of the options.""",
-      arguments: {'name': name, 'type': _type, 'type2': _type2});
-}
-
-// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const Template<
-    Message Function(
         DartType _type,
         DartType
             _type2)> templateInvalidAssignment = const Template<
diff --git a/pkg/front_end/lib/src/fasta/incremental_compiler.dart b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
index a184705..4ebcdbb 100644
--- a/pkg/front_end/lib/src/fasta/incremental_compiler.dart
+++ b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
@@ -51,7 +51,9 @@
 import '../api_prototype/memory_file_system.dart' show MemoryFileSystem;
 
 import 'builder/builder.dart';
+
 import 'builder/class_builder.dart';
+
 import 'builder/library_builder.dart';
 
 import 'builder_graph.dart' show BuilderGraph;
@@ -68,6 +70,8 @@
 
 import 'util/error_reporter_file_copier.dart' show saveAsGzip;
 
+import 'util/textual_outline.dart' show textualOutline;
+
 import 'fasta_codes.dart'
     show
         DiagnosticMessageFromJson,
@@ -80,7 +84,7 @@
 
 import 'kernel/kernel_builder.dart' show ClassHierarchyBuilder;
 
-import 'kernel/kernel_shadow_ast.dart' show VariableDeclarationImpl;
+import 'kernel/internal_ast.dart' show VariableDeclarationImpl;
 
 import 'kernel/kernel_target.dart' show KernelTarget;
 
@@ -120,6 +124,7 @@
       new Map<Uri, List<DiagnosticMessageFromJson>>();
   List<Component> modulesToLoad;
   IncrementalSerializer incrementalSerializer;
+  bool useExperimentalInvalidation = false;
 
   static final Uri debugExprUri =
       new Uri(scheme: "org-dartlang-debug", path: "synthetic_debug_expression");
@@ -243,9 +248,107 @@
 
       ClassHierarchy hierarchy = userCode?.loader?.hierarchy;
       Set<LibraryBuilder> notReusedLibraries = new Set<LibraryBuilder>();
+      List<LibraryBuilder> directlyInvalidated = new List<LibraryBuilder>();
+      // TODO(jensj): Do something smarter than this.
+      List<bool> invalidatedBecauseOfPackageUpdate = new List<bool>();
       List<LibraryBuilder> reusedLibraries = computeReusedLibraries(
           invalidatedUris, uriTranslator,
-          notReused: notReusedLibraries);
+          notReused: notReusedLibraries,
+          directlyInvalidated: directlyInvalidated,
+          invalidatedBecauseOfPackageUpdate: invalidatedBecauseOfPackageUpdate);
+
+      bool apiUnchanged = false;
+      List<SourceLibraryBuilder> rebuildBodies =
+          new List<SourceLibraryBuilder>();
+      Set<LibraryBuilder> originalNotReusedLibraries;
+      Set<Uri> missingSources = new Set<Uri>();
+      if (useExperimentalInvalidation &&
+          modulesToLoad == null &&
+          directlyInvalidated.isNotEmpty &&
+          invalidatedBecauseOfPackageUpdate.isEmpty) {
+        // Figure out if the file(s) have changed outline, or we can just
+        // rebuild the bodies. This (at least currently) only works for
+        // SourceLibraryBuilder.
+        apiUnchanged = true;
+        for (int i = 0; i < directlyInvalidated.length; i++) {
+          LibraryBuilder builder = directlyInvalidated[i];
+          if (builder is! SourceLibraryBuilder) {
+            apiUnchanged = false;
+            break;
+          }
+          List<int> previousSource =
+              CompilerContext.current.uriToSource[builder.fileUri].source;
+          if (previousSource == null || previousSource.isEmpty) {
+            apiUnchanged = false;
+            break;
+          }
+          String before = textualOutline(previousSource);
+          String now;
+          FileSystemEntity entity =
+              c.options.fileSystem.entityForUri(builder.fileUri);
+          if (await entity.exists()) {
+            now = textualOutline(await entity.readAsBytes());
+          }
+          if (before != now) {
+            apiUnchanged = false;
+            break;
+          }
+          // TODO(jensj): We should only do this when we're sure we're going to
+          // do it!
+          CompilerContext.current.uriToSource.remove(builder.fileUri);
+          missingSources.add(builder.fileUri);
+          LibraryBuilder partOfLibrary = builder.partOfLibrary;
+          if (partOfLibrary != null) {
+            if (partOfLibrary is! SourceLibraryBuilder) {
+              apiUnchanged = false;
+              break;
+            }
+            rebuildBodies.add(partOfLibrary);
+          } else {
+            rebuildBodies.add(builder);
+          }
+        }
+
+        if (apiUnchanged) {
+          // TODO(jensj): Check for mixins in a smarter and faster way.
+          for (LibraryBuilder builder in notReusedLibraries) {
+            if (missingSources.contains(builder.fileUri)) continue;
+            Library lib = builder.library;
+            for (Class c in lib.classes) {
+              if (!c.isAnonymousMixin && !c.isEliminatedMixin) continue;
+              for (Supertype supertype in c.implementedTypes) {
+                if (missingSources.contains(supertype.classNode.fileUri)) {
+                  // This is probably a mixin from one of the libraries we want
+                  // to rebuild only the body of.
+                  apiUnchanged = false;
+                  break;
+                }
+              }
+            }
+          }
+        }
+
+        if (apiUnchanged) {
+          originalNotReusedLibraries = new Set<LibraryBuilder>();
+          Set<Uri> seenUris = new Set<Uri>();
+          for (LibraryBuilder builder in notReusedLibraries) {
+            if (builder.isPart) continue;
+            if (builder.isPatch) continue;
+            if (!seenUris.add(builder.uri)) continue;
+            reusedLibraries.add(builder);
+            originalNotReusedLibraries.add(builder);
+          }
+          notReusedLibraries.clear();
+          for (int i = 0; i < rebuildBodies.length; i++) {
+            SourceLibraryBuilder builder = rebuildBodies[i];
+            builder.issueLexicalErrorsOnBodyBuild = true;
+          }
+        } else {
+          missingSources.clear();
+          rebuildBodies.clear();
+        }
+      }
+      recordRebuildBodiesCountForTesting(missingSources.length);
 
       bool removedDillBuilders = false;
       for (LibraryBuilder builder in notReusedLibraries) {
@@ -358,6 +461,18 @@
       }
       Component componentWithDill = await userCode.buildOutlines();
 
+      for (int i = 0; i < rebuildBodies.length; i++) {
+        SourceLibraryBuilder builder = rebuildBodies[i];
+        builder.loader = userCode.loader;
+        Library lib = builder.library;
+        lib.problemsAsJson = null;
+        // Remove component problems for libraries we don't reuse.
+        if (remainingComponentProblems.isNotEmpty) {
+          removeLibraryFromRemainingComponentProblems(lib, uriTranslator);
+        }
+        userCode.loader.libraries.add(lib);
+      }
+
       // This is not the full component. It is the component consisting of all
       // newly compiled libraries and all libraries loaded from .dill files or
       // directly from components.
@@ -389,19 +504,35 @@
         this.invalidatedUris.clear();
         hasToCheckPackageUris = false;
         userCodeOld?.loader?.releaseAncillaryResources();
-        userCodeOld?.loader?.builders?.clear();
         userCodeOld = null;
       }
 
       List<Library> compiledLibraries =
           new List<Library>.from(userCode.loader.libraries);
+      Map<Uri, Source> uriToSource = componentWithDill?.uriToSource;
+      if (originalNotReusedLibraries != null) {
+        // Make sure "compiledLibraries" contains what it would have, had we not
+        // only re-done the bodies, but invalidated everything.
+        originalNotReusedLibraries.removeAll(rebuildBodies);
+        for (LibraryBuilder builder in originalNotReusedLibraries) {
+          compiledLibraries.add(builder.library);
+        }
+
+        // uriToSources are created in the outline stage which we skipped for
+        // some of the libraries.
+        for (Uri uri in missingSources) {
+          // TODO(jensj): KernelTargets "link" takes some "excludeSource"
+          // setting into account.
+          uriToSource[uri] = CompilerContext.current.uriToSource[uri];
+        }
+      }
+
       Procedure mainMethod = componentWithDill == null
           ? data.userLoadedUriMain
           : componentWithDill.mainMethod;
 
       List<Library> outputLibraries;
       Set<Library> allLibraries;
-      Map<Uri, Source> uriToSource = componentWithDill?.uriToSource;
       if (data.component != null || fullComponent) {
         outputLibraries = computeTransitiveClosure(
             compiledLibraries,
@@ -1011,7 +1142,9 @@
   /// Internal method.
   List<LibraryBuilder> computeReusedLibraries(
       Set<Uri> invalidatedUris, UriTranslator uriTranslator,
-      {Set<LibraryBuilder> notReused}) {
+      {Set<LibraryBuilder> notReused,
+      List<LibraryBuilder> directlyInvalidated,
+      List<bool> invalidatedBecauseOfPackageUpdate}) {
     List<LibraryBuilder> result = <LibraryBuilder>[];
     result.addAll(platformBuilders);
     if (userCode == null && userBuilders == null) {
@@ -1042,6 +1175,7 @@
                 currentPackagesMap[packageName])) {
           Uri newFileUri = uriTranslator.translate(importUri, false);
           if (newFileUri != fileUri) {
+            invalidatedBecauseOfPackageUpdate?.add(true);
             return true;
           }
         }
@@ -1091,6 +1225,11 @@
     }
 
     recordInvalidatedImportUrisForTesting(invalidatedImportUris);
+    if (directlyInvalidated != null) {
+      for (Uri uri in invalidatedImportUris) {
+        directlyInvalidated.add(builders[uri]);
+      }
+    }
 
     BuilderGraph graph = new BuilderGraph(builders);
 
@@ -1169,6 +1308,9 @@
   void recordInvalidatedImportUrisForTesting(List<Uri> uris) {}
 
   /// Internal method.
+  void recordRebuildBodiesCountForTesting(int count) {}
+
+  /// Internal method.
   void recordTemporaryFileForTesting(Uri uri) {}
 }
 
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 377f607..fd64898 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -140,7 +140,7 @@
 
 import 'kernel_ast_api.dart';
 
-import 'kernel_shadow_ast.dart';
+import 'internal_ast.dart';
 
 import 'kernel_builder.dart';
 
@@ -553,8 +553,8 @@
   void inferAnnotations(TreeNode parent, List<Expression> annotations) {
     if (annotations != null) {
       typeInferrer?.inferMetadata(this, parent, annotations);
-      libraryBuilder.loader.transformListPostInference(
-          annotations, transformSetLiterals, transformCollections);
+      libraryBuilder.loader.transformListPostInference(annotations,
+          transformSetLiterals, transformCollections, libraryBuilder.library);
     }
   }
 
@@ -675,20 +675,33 @@
       }
       fields.add(fieldBuilder);
       if (initializer != null) {
-        if (fieldBuilder.next != null) {
+        if (fieldBuilder.isDuplicate) {
           // Duplicate definition. The field might not be the correct one,
           // so we skip inference of the initializer.
           // Error reporting and recovery is handled elsewhere.
-        } else if (fieldBuilder.field.initializer != null) {
+        } else if (fieldBuilder.hasBodyBeenBuilt) {
           // The initializer was already compiled (e.g., if it appear in the
           // outline, like constant field initializers) so we do not need to
           // perform type inference or transformations.
         } else {
-          fieldBuilder.initializer = typeInferrer?.inferFieldInitializer(
+          initializer = typeInferrer?.inferFieldInitializer(
               this, fieldBuilder.builtType, initializer);
-          libraryBuilder.loader.transformPostInference(
-              fieldBuilder.field, transformSetLiterals, transformCollections);
+
+          if (transformCollections || transformSetLiterals) {
+            // Wrap the initializer in a temporary parent expression; the
+            // transformations need a parent relation.
+            Not wrapper = new Not(initializer);
+            libraryBuilder.loader.transformPostInference(
+                wrapper,
+                transformSetLiterals,
+                transformCollections,
+                libraryBuilder.library);
+            initializer = wrapper.operand;
+          }
+          fieldBuilder.buildBody(initializer);
         }
+      } else if (!fieldBuilder.hasBodyBeenBuilt) {
+        fieldBuilder.buildBody(null);
       }
     }
     {
@@ -733,16 +746,18 @@
       if (member.formals != null) {
         for (FormalParameterBuilder formal in member.formals) {
           if (formal.isInitializingFormal) {
-            Initializer initializer;
+            List<Initializer> initializers;
             if (member.isExternal) {
-              initializer = buildInvalidInitializer(
-                  buildProblem(
-                      fasta.messageExternalConstructorWithFieldInitializers,
-                      formal.charOffset,
-                      formal.name.length),
-                  formal.charOffset);
+              initializers = <Initializer>[
+                buildInvalidInitializer(
+                    buildProblem(
+                        fasta.messageExternalConstructorWithFieldInitializers,
+                        formal.charOffset,
+                        formal.name.length),
+                    formal.charOffset)
+              ];
             } else {
-              initializer = buildFieldInitializer(
+              initializers = buildFieldInitializer(
                   true,
                   formal.name,
                   formal.charOffset,
@@ -750,7 +765,9 @@
                   new VariableGet(formal.variable),
                   formalType: formal.variable.type);
             }
-            member.addInitializer(initializer, this);
+            for (Initializer initializer in initializers) {
+              member.addInitializer(initializer, this);
+            }
           }
         }
       }
@@ -796,25 +813,33 @@
     assert(!inInitializer);
     final ModifierBuilder member = this.member;
     Object node = pop();
-    Initializer initializer;
+    List<Initializer> initializers;
     if (node is Initializer) {
-      initializer = node;
+      initializers = <Initializer>[node];
     } else if (node is Generator) {
-      initializer = node.buildFieldInitializer(initializedFields);
+      initializers = node.buildFieldInitializer(initializedFields);
     } else if (node is ConstructorInvocation) {
-      initializer = buildSuperInitializer(
-          false, node.target, node.arguments, token.charOffset);
+      initializers = <Initializer>[
+        buildSuperInitializer(
+            false, node.target, node.arguments, token.charOffset)
+      ];
     } else {
       Expression value = toValue(node);
       if (!forest.isThrow(node)) {
         value =
             wrapInProblem(value, fasta.messageExpectedAnInitializer, noLength);
       }
-      initializer = buildInvalidInitializer(node, token.charOffset);
+      initializers = <Initializer>[
+        buildInvalidInitializer(node, token.charOffset)
+      ];
     }
-    typeInferrer?.inferInitializer(this, initializer);
+    for (Initializer initializer in initializers) {
+      typeInferrer?.inferInitializer(this, initializer);
+    }
     if (member is ConstructorBuilder && !member.isExternal) {
-      member.addInitializer(initializer, this);
+      for (Initializer initializer in initializers) {
+        member.addInitializer(initializer, this);
+      }
     } else {
       addProblem(
           fasta.templateInitializerOutsideConstructor
@@ -846,18 +871,24 @@
         FormalParameterBuilder parameter = formals.parameters[i];
         Expression initializer = parameter.variable.initializer;
         if (parameter.isOptional || initializer != null) {
-          if (parameter.isOptional) {
-            initializer ??= forest.createNullLiteral(
-                // TODO(ahe): Should store: originParameter.fileOffset
-                // https://github.com/dart-lang/sdk/issues/32289
-                noLocation);
+          if (!parameter.initializerWasInferred) {
+            parameter.initializerWasInferred = true;
+            if (parameter.isOptional) {
+              initializer ??= forest.createNullLiteral(
+                  // TODO(ahe): Should store: originParameter.fileOffset
+                  // https://github.com/dart-lang/sdk/issues/32289
+                  noLocation);
+            }
+            VariableDeclaration originParameter = builder.getFormalParameter(i);
+            initializer = typeInferrer?.inferParameterInitializer(
+                this, initializer, originParameter.type);
+            originParameter.initializer = initializer..parent = originParameter;
+            libraryBuilder.loader.transformPostInference(
+                originParameter,
+                transformSetLiterals,
+                transformCollections,
+                libraryBuilder.library);
           }
-          VariableDeclaration originParameter = builder.getFormalParameter(i);
-          initializer = typeInferrer?.inferParameterInitializer(
-              this, initializer, originParameter.type);
-          originParameter.initializer = initializer..parent = originParameter;
-          libraryBuilder.loader.transformPostInference(
-              originParameter, transformSetLiterals, transformCollections);
 
           VariableDeclaration extensionTearOffParameter =
               builder.getExtensionTearOffParameter(i);
@@ -869,16 +900,21 @@
             libraryBuilder.loader.transformPostInference(
                 extensionTearOffParameter,
                 transformSetLiterals,
-                transformCollections);
+                transformCollections,
+                libraryBuilder.library);
           }
         }
       }
     }
-    typeInferrer?.inferFunctionBody(this, _computeReturnTypeContext(member),
-        asyncModifier, builder.member.function, body);
     if (body != null) {
-      libraryBuilder.loader.transformPostInference(
-          body, transformSetLiterals, transformCollections);
+      body = typeInferrer?.inferFunctionBody(
+          this,
+          _computeReturnTypeContext(member),
+          asyncModifier,
+          builder.member.function,
+          body);
+      libraryBuilder.loader.transformPostInference(body, transformSetLiterals,
+          transformCollections, libraryBuilder.library);
     }
 
     if (builder.returnType != null) {
@@ -1334,8 +1370,8 @@
       constructor.initializers.add(initializer);
     }
     setParents(constructor.initializers, constructor);
-    libraryBuilder.loader.transformListPostInference(
-        constructor.initializers, transformSetLiterals, transformCollections);
+    libraryBuilder.loader.transformListPostInference(constructor.initializers,
+        transformSetLiterals, transformCollections, libraryBuilder.library);
     if (constructor.function.body == null) {
       /// >If a generative constructor c is not a redirecting constructor
       /// >and no body is provided, then c implicitly has an empty body {}.
@@ -1481,7 +1517,8 @@
     } else {
       VariableDeclaration variable =
           forest.createVariableDeclarationForValue(expression);
-      push(new Cascade(variable)..fileOffset = expression.fileOffset);
+      push(new Cascade(variable, isNullAware: optional('?..', token))
+        ..fileOffset = expression.fileOffset);
       push(_createReadOnlyVariableAccess(
           variable, token, expression.fileOffset, null));
     }
@@ -3151,8 +3188,10 @@
         functionNestingLevel == 0 &&
         memberKind != MemberKind.GeneralizedFunctionType) {
       FunctionBuilder member = this.member;
-      parameter = member.getFormal(name.name);
+      parameter = member.getFormal(name);
       if (parameter == null) {
+        // This happens when the list of formals (originally) contains a
+        // ParserRecovery - then the popped list becomes null.
         push(new ParserRecovery(nameToken.charOffset));
         return;
       }
@@ -3172,7 +3211,9 @@
             initializer.fileOffset,
             noLength);
       } else {
-        variable.initializer = initializer..parent = variable;
+        if (!parameter.initializerWasInferred) {
+          variable.initializer = initializer..parent = variable;
+        }
       }
     } else if (kind != FormalParameterKind.mandatory) {
       variable.initializer ??= forest.createNullLiteral(noLocation)
@@ -3182,6 +3223,7 @@
       if (functionNestingLevel == 0) {
         inferAnnotations(variable, annotations);
       }
+      variable.clearAnnotations();
       for (Expression annotation in annotations) {
         variable.addAnnotation(annotation);
       }
@@ -3424,15 +3466,18 @@
     debugEvent("IndexedExpression");
     Expression index = popForValue();
     Object receiver = pop();
+    bool isNullAware = optional('?.[', openSquareBracket);
     if (receiver is Generator) {
-      push(receiver.buildIndexedAccess(index, openSquareBracket));
+      push(receiver.buildIndexedAccess(index, openSquareBracket,
+          isNullAware: isNullAware));
     } else if (receiver is Expression) {
-      push(IndexedAccessGenerator.make(
-          this, openSquareBracket, receiver, index));
+      push(IndexedAccessGenerator.make(this, openSquareBracket, receiver, index,
+          isNullAware: isNullAware));
     } else {
       assert(receiver is Initializer);
       push(IndexedAccessGenerator.make(
-          this, openSquareBracket, toValue(receiver), index));
+          this, openSquareBracket, toValue(receiver), index,
+          isNullAware: isNullAware));
     }
   }
 
@@ -3489,7 +3534,7 @@
     Object generator = pop();
     if (generator is Generator) {
       push(new DelayedPostfixIncrement(
-          this, token, generator, incrementOperator(token), null));
+          this, token, generator, incrementOperator(token)));
     } else {
       push(wrapInProblem(
           toValue(generator), fasta.messageNotAnLvalue, noLength));
@@ -5245,22 +5290,26 @@
   /// immediately enclosing class.  It is a static warning if the static type of
   /// _id_ is not a subtype of _Tid_."
   @override
-  Initializer buildFieldInitializer(bool isSynthetic, String name,
+  List<Initializer> buildFieldInitializer(bool isSynthetic, String name,
       int fieldNameOffset, int assignmentOffset, Expression expression,
       {DartType formalType}) {
     Builder builder = declarationBuilder.lookupLocalMember(name);
     if (builder?.next != null) {
       // Duplicated name, already reported.
-      return new LocalInitializer(new VariableDeclaration.forValue(buildProblem(
-          fasta.templateDuplicatedDeclarationUse.withArguments(name),
-          fieldNameOffset,
-          name.length)))
-        ..fileOffset = fieldNameOffset;
+      return <Initializer>[
+        new LocalInitializer(new VariableDeclaration.forValue(buildProblem(
+            fasta.templateDuplicatedDeclarationUse.withArguments(name),
+            fieldNameOffset,
+            name.length)))
+          ..fileOffset = fieldNameOffset
+      ];
     } else if (builder is FieldBuilder && builder.isDeclarationInstanceMember) {
       initializedFields ??= <String, int>{};
       if (initializedFields.containsKey(name)) {
-        return buildDuplicatedInitializer(builder.field, expression, name,
-            assignmentOffset, initializedFields[name]);
+        return <Initializer>[
+          buildDuplicatedInitializer(builder.field, expression, name,
+              assignmentOffset, initializedFields[name])
+        ];
       }
       initializedFields[name] = assignmentOffset;
       if (builder.isFinal && builder.hasInitializer) {
@@ -5283,12 +5332,14 @@
             ]),
             constness: Constness.explicitNew,
             charOffset: assignmentOffset);
-        return new ShadowInvalidFieldInitializer(
-            builder.field,
-            expression,
-            new VariableDeclaration.forValue(
-                forest.createThrow(assignmentOffset, invocation)))
-          ..fileOffset = assignmentOffset;
+        return <Initializer>[
+          new ShadowInvalidFieldInitializer(
+              builder.field,
+              expression,
+              new VariableDeclaration.forValue(
+                  forest.createThrow(assignmentOffset, invocation)))
+            ..fileOffset = assignmentOffset
+        ];
       } else {
         if (formalType != null &&
             !typeEnvironment.isSubtypeOf(formalType, builder.field.type,
@@ -5304,17 +5355,18 @@
                     .withLocation(builder.fileUri, builder.charOffset, noLength)
               ]);
         }
-        return new FieldInitializer(builder.field, expression)
-          ..fileOffset = assignmentOffset
-          ..isSynthetic = isSynthetic;
+        return builder.buildInitializer(assignmentOffset, expression,
+            isSynthetic: isSynthetic);
       }
     } else {
-      return buildInvalidInitializer(
-          buildProblem(
-              fasta.templateInitializerForStaticField.withArguments(name),
-              fieldNameOffset,
-              name.length),
-          fieldNameOffset);
+      return <Initializer>[
+        buildInvalidInitializer(
+            buildProblem(
+                fasta.templateInitializerForStaticField.withArguments(name),
+                fieldNameOffset,
+                name.length),
+            fieldNameOffset)
+      ];
     }
   }
 
diff --git a/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart b/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart
index 76a4af6..a1798c4 100644
--- a/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart
@@ -12,6 +12,7 @@
         FunctionNode,
         InterfaceType,
         InvalidType,
+        Library,
         Member,
         Name,
         Nullability,
@@ -159,7 +160,8 @@
   if (typeParameterCount != 0) {
     List<DartType> types = new List<DartType>(typeParameterCount);
     for (int i = 0; i < typeParameterCount; i++) {
-      types[i] = new TypeParameterType(aTypeParameters[i], Nullability.legacy);
+      types[i] = new TypeParameterType.forAlphaRenaming(
+          bTypeParameters[i], aTypeParameters[i]);
     }
     substitution = Substitution.fromPairs(bTypeParameters, types);
     for (int i = 0; i < typeParameterCount; i++) {
@@ -659,8 +661,8 @@
       }
       List<DartType> types = new List<DartType>(typeParameterCount);
       for (int i = 0; i < typeParameterCount; i++) {
-        types[i] =
-            new TypeParameterType(aTypeParameters[i], Nullability.legacy);
+        types[i] = new TypeParameterType.forAlphaRenaming(
+            bTypeParameters[i], aTypeParameters[i]);
       }
       substitution = Substitution.fromPairs(bTypeParameters, types);
       for (int i = 0; i < typeParameterCount; i++) {
@@ -979,8 +981,10 @@
         if (inheritedType is ImplicitFieldType) {
           SourceLibraryBuilder library = classBuilder.library;
           (library.implicitlyTypedFields ??= <FieldBuilder>[]).add(a);
+          a.fieldType = inheritedType.createAlias(a);
+        } else {
+          a.fieldType = inheritedType;
         }
-        a.field.type = inheritedType;
       }
     }
     return result;
@@ -1204,14 +1208,23 @@
     }
 
     /// Members (excluding setters) declared in [cls].
-    List<ClassMember> localMembers =
-        new List<ClassMember>.from(scope.localMembers)
-          ..sort(compareDeclarations);
+    List<ClassMember> localMembers = <ClassMember>[];
 
     /// Setters declared in [cls].
-    List<ClassMember> localSetters =
-        new List<ClassMember>.from(scope.localSetters)
-          ..sort(compareDeclarations);
+    List<ClassMember> localSetters = <ClassMember>[];
+
+    for (MemberBuilder memberBuilder in scope.localMembers) {
+      localMembers.addAll(memberBuilder.localMembers);
+      localSetters.addAll(memberBuilder.localSetters);
+    }
+
+    for (MemberBuilder memberBuilder in scope.localSetters) {
+      localMembers.addAll(memberBuilder.localMembers);
+      localSetters.addAll(memberBuilder.localSetters);
+    }
+
+    localMembers.sort(compareDeclarations);
+    localSetters.sort(compareDeclarations);
 
     // Add implied setters from fields in [localMembers].
     localSetters = mergeAccessors(localMembers, localSetters);
@@ -1677,8 +1690,8 @@
     new BuilderMixinInferrer(
             classBuilder,
             hierarchy.coreTypes,
-            new TypeBuilderConstraintGatherer(
-                hierarchy, mixedInType.classNode.typeParameters))
+            new TypeBuilderConstraintGatherer(hierarchy,
+                mixedInType.classNode.typeParameters, cls.enclosingLibrary))
         .infer(cls);
     List<TypeBuilder> inferredArguments =
         new List<TypeBuilder>(typeArguments.length);
@@ -1782,8 +1795,8 @@
     return result..last = this;
   }
 
-  String toString([StringBuffer sb]) {
-    sb ??= new StringBuffer();
+  String toString() {
+    StringBuffer sb = new StringBuffer();
     sb
       ..write(classBuilder.fullNameForErrors)
       ..writeln(":");
@@ -1967,9 +1980,9 @@
     with StandardBounds {
   final ClassHierarchyBuilder hierarchy;
 
-  TypeBuilderConstraintGatherer(
-      this.hierarchy, Iterable<TypeParameter> typeParameters)
-      : super.subclassing(typeParameters);
+  TypeBuilderConstraintGatherer(this.hierarchy,
+      Iterable<TypeParameter> typeParameters, Library currentLibrary)
+      : super.subclassing(typeParameters, currentLibrary);
 
   @override
   Class get objectClass => hierarchy.objectClass;
@@ -2071,7 +2084,9 @@
           if (type != null) {
             type = Substitution.fromInterfaceType(
                     hierarchy.getKernelTypeAsInstanceOf(
-                        classBuilder.cls.thisType, b.member.enclosingClass))
+                        hierarchy.coreTypes.thisInterfaceType(
+                            classBuilder.cls, classBuilder.library.nonNullable),
+                        b.member.enclosingClass))
                 .substituteType(type);
             if (!a.hadTypesInferred || !b.isSetter) {
               inferReturnType(
@@ -2093,7 +2108,9 @@
           if (type != null) {
             type = Substitution.fromInterfaceType(
                     hierarchy.getKernelTypeAsInstanceOf(
-                        classBuilder.cls.thisType, b.member.enclosingClass))
+                        hierarchy.coreTypes.thisInterfaceType(
+                            classBuilder.cls, classBuilder.library.nonNullable),
+                        b.member.enclosingClass))
                 .substituteType(type);
             if (!a.hadTypesInferred || !b.isGetter) {
               inferParameterType(classBuilder, a, a.formals.single, type,
@@ -2117,22 +2134,24 @@
         if (type != null) {
           type = Substitution.fromInterfaceType(
                   hierarchy.getKernelTypeAsInstanceOf(
-                      classBuilder.cls.thisType, b.member.enclosingClass))
+                      hierarchy.coreTypes.thisInterfaceType(
+                          classBuilder.cls, classBuilder.library.nonNullable),
+                      b.member.enclosingClass))
               .substituteType(type);
-          if (type != a.field.type) {
+          if (type != a.fieldType) {
             if (a.hadTypesInferred) {
               if (b.isSetter &&
                   (!impliesSetter(a) ||
-                      hierarchy.types.isSubtypeOfKernel(type, a.field.type,
+                      hierarchy.types.isSubtypeOfKernel(type, a.fieldType,
                           SubtypeCheckMode.ignoringNullabilities))) {
-                type = a.field.type;
+                type = a.fieldType;
               } else {
                 reportCantInferFieldType(classBuilder, a);
                 type = const InvalidType();
               }
             }
             debug?.log("Inferred type ${type} for ${fullName(a)}");
-            a.field.type = type;
+            a.fieldType = type;
           }
         }
         a.hadTypesInferred = true;
@@ -2320,7 +2339,8 @@
     if (classBuilder.library is! SourceLibraryBuilder) {
       return combinedMemberSignatureResult = declarations.first.member;
     }
-    DartType thisType = classBuilder.cls.thisType;
+    DartType thisType = hierarchy.coreTypes
+        .thisInterfaceType(classBuilder.cls, classBuilder.library.nonNullable);
     ClassMember bestSoFar;
     DartType bestTypeSoFar;
     for (int i = declarations.length - 1; i >= 0; i--) {
diff --git a/pkg/front_end/lib/src/fasta/kernel/collections.dart b/pkg/front_end/lib/src/fasta/kernel/collections.dart
index ce5307c..1e907ea 100644
--- a/pkg/front_end/lib/src/fasta/kernel/collections.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/collections.dart
@@ -18,7 +18,7 @@
         transformList,
         visitList;
 
-import 'package:kernel/type_environment.dart' show TypeEnvironment;
+import 'package:kernel/type_environment.dart' show StaticTypeContext;
 
 import 'package:kernel/visitor.dart'
     show
@@ -45,7 +45,7 @@
   /// Spread and control-flow elements are not expressions and do not have a
   /// static type.
   @override
-  DartType getStaticType(TypeEnvironment types) {
+  DartType getStaticType(StaticTypeContext context) {
     return unsupported("getStaticType", fileOffset, getFileUri(this));
   }
 
diff --git a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
index fe48a98..35868d9 100644
--- a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
@@ -123,6 +123,7 @@
   final ConstantsBackend backend;
   final ConstantEvaluator constantEvaluator;
   final TypeEnvironment typeEnvironment;
+  StaticTypeContext _staticTypeContext;
 
   /// Whether to preserve constant [Field]s.  All use-sites will be rewritten.
   final bool keepFields;
@@ -150,6 +151,9 @@
   // Transform the library/class members:
 
   void convertLibrary(Library library) {
+    _staticTypeContext =
+        new StaticTypeContext.forAnnotations(library, typeEnvironment);
+
     transformAnnotations(library.annotations, library);
 
     transformList(library.dependencies, this, library);
@@ -166,6 +170,7 @@
         return reference.node is Field && reference.canonicalName == null;
       });
     }
+    _staticTypeContext = null;
   }
 
   @override
@@ -186,6 +191,9 @@
 
   @override
   Class visitClass(Class node) {
+    StaticTypeContext oldStaticTypeContext = _staticTypeContext;
+    _staticTypeContext = new StaticTypeContext.forAnnotations(
+        node.enclosingLibrary, typeEnvironment);
     constantEvaluator.withNewEnvironment(() {
       transformAnnotations(node.annotations, node);
       transformList(node.fields, this, node);
@@ -194,25 +202,32 @@
       transformList(node.procedures, this, node);
       transformList(node.redirectingFactoryConstructors, this, node);
     });
+    _staticTypeContext = oldStaticTypeContext;
     return node;
   }
 
   @override
   Procedure visitProcedure(Procedure node) {
+    StaticTypeContext oldStaticTypeContext = _staticTypeContext;
+    _staticTypeContext = new StaticTypeContext(node, typeEnvironment);
     constantEvaluator.withNewEnvironment(() {
       transformAnnotations(node.annotations, node);
       node.function = node.function.accept<TreeNode>(this)..parent = node;
     });
+    _staticTypeContext = oldStaticTypeContext;
     return node;
   }
 
   @override
   Constructor visitConstructor(Constructor node) {
+    StaticTypeContext oldStaticTypeContext = _staticTypeContext;
+    _staticTypeContext = new StaticTypeContext(node, typeEnvironment);
     constantEvaluator.withNewEnvironment(() {
       transformAnnotations(node.annotations, node);
       transformList(node.initializers, this, node);
       node.function = node.function.accept<TreeNode>(this)..parent = node;
     });
+    _staticTypeContext = oldStaticTypeContext;
     return node;
   }
 
@@ -231,12 +246,15 @@
   @override
   RedirectingFactoryConstructor visitRedirectingFactoryConstructor(
       RedirectingFactoryConstructor node) {
+    StaticTypeContext oldStaticTypeContext = _staticTypeContext;
+    _staticTypeContext = new StaticTypeContext(node, typeEnvironment);
     constantEvaluator.withNewEnvironment(() {
       transformAnnotations(node.annotations, node);
       transformList(node.typeParameters, this, node);
       transformList(node.positionalParameters, this, node);
       transformList(node.namedParameters, this, node);
     });
+    _staticTypeContext = oldStaticTypeContext;
     return node;
   }
 
@@ -320,7 +338,9 @@
 
   @override
   Field visitField(Field node) {
-    return constantEvaluator.withNewEnvironment(() {
+    StaticTypeContext oldStaticTypeContext = _staticTypeContext;
+    _staticTypeContext = new StaticTypeContext(node, typeEnvironment);
+    Field field = constantEvaluator.withNewEnvironment(() {
       if (node.isConst) {
         transformAnnotations(node.annotations, node);
         node.initializer =
@@ -340,13 +360,16 @@
       }
       return node;
     });
+    _staticTypeContext = oldStaticTypeContext;
+    return field;
   }
 
   // Handle use-sites of constants (and "inline" constant expressions):
 
   @override
   Expression visitSymbolLiteral(SymbolLiteral node) {
-    return makeConstantExpression(constantEvaluator.evaluate(node), node);
+    return makeConstantExpression(
+        constantEvaluator.evaluate(_staticTypeContext, node), node);
   }
 
   @override
@@ -460,11 +483,11 @@
 
   Constant evaluateWithContext(TreeNode treeContext, Expression node) {
     if (treeContext == node) {
-      return constantEvaluator.evaluate(node);
+      return constantEvaluator.evaluate(_staticTypeContext, node);
     }
 
     return constantEvaluator.runInsideContext(treeContext, () {
-      return constantEvaluator.evaluate(node);
+      return constantEvaluator.evaluate(_staticTypeContext, node);
     });
   }
 
@@ -473,7 +496,8 @@
         constant.expression is InvalidExpression) {
       return constant.expression;
     }
-    return new ConstantExpression(constant, node.getStaticType(typeEnvironment))
+    return new ConstantExpression(
+        constant, node.getStaticType(_staticTypeContext))
       ..fileOffset = node.fileOffset;
   }
 
@@ -493,6 +517,7 @@
   final bool errorOnUnevaluatedConstant;
   final CoreTypes coreTypes;
   final TypeEnvironment typeEnvironment;
+  StaticTypeContext _staticTypeContext;
   final ErrorReporter errorReporter;
 
   final bool desugarSets;
@@ -582,7 +607,8 @@
   /// Returns UnevaluatedConstant if the constant could not be evaluated.
   /// If the expression in the UnevaluatedConstant is an InvalidExpression,
   /// an error occurred during constant evaluation.
-  Constant evaluate(Expression node) {
+  Constant evaluate(StaticTypeContext context, Expression node) {
+    _staticTypeContext = context;
     seenUnevaluatedChild = false;
     lazyDepth = 0;
     try {
@@ -1243,7 +1269,7 @@
               templateConstEvalInvalidType.withArguments(
                   message,
                   typeEnvironment.coreTypes.stringLegacyRawType,
-                  message.getType(typeEnvironment)));
+                  message.getType(_staticTypeContext)));
         }
       }
     } else {
@@ -1252,7 +1278,7 @@
           templateConstEvalInvalidType.withArguments(
               condition,
               typeEnvironment.coreTypes.boolLegacyRawType,
-              condition.getType(typeEnvironment)));
+              condition.getType(_staticTypeContext)));
     }
   }
 
@@ -1298,7 +1324,7 @@
         return report(
             node,
             templateConstEvalInvalidEqualsOperandType.withArguments(
-                receiver, receiver.getType(typeEnvironment)));
+                receiver, receiver.getType(_staticTypeContext)));
       }
     }
 
@@ -1318,7 +1344,7 @@
                     '+',
                     receiver,
                     typeEnvironment.coreTypes.stringLegacyRawType,
-                    other.getType(typeEnvironment)));
+                    other.getType(_staticTypeContext)));
         }
       }
     } else if (intFolder.isInt(receiver)) {
@@ -1338,7 +1364,7 @@
                     op,
                     other,
                     typeEnvironment.coreTypes.intLegacyRawType,
-                    other.getType(typeEnvironment)));
+                    other.getType(_staticTypeContext)));
           }
           num receiverValue = (receiver as PrimitiveConstant<num>).value;
           return canonicalize(evaluateBinaryNumericOperation(
@@ -1350,7 +1376,7 @@
                 op,
                 receiver,
                 typeEnvironment.coreTypes.numLegacyRawType,
-                other.getType(typeEnvironment)));
+                other.getType(_staticTypeContext)));
       }
     } else if (receiver is DoubleConstant) {
       if ((op == '|' || op == '&' || op == '^') ||
@@ -1361,7 +1387,7 @@
                 op,
                 receiver,
                 typeEnvironment.coreTypes.intLegacyRawType,
-                receiver.getType(typeEnvironment)));
+                receiver.getType(_staticTypeContext)));
       }
       if (arguments.length == 0) {
         switch (op) {
@@ -1382,7 +1408,7 @@
                 op,
                 receiver,
                 typeEnvironment.coreTypes.numLegacyRawType,
-                other.getType(typeEnvironment)));
+                other.getType(_staticTypeContext)));
       }
     } else if (receiver is BoolConstant) {
       if (arguments.length == 1) {
@@ -1435,7 +1461,7 @@
                   node.operator,
                   left,
                   typeEnvironment.coreTypes.boolLegacyRawType,
-                  right.getType(typeEnvironment)));
+                  right.getType(_staticTypeContext)));
         }
         return report(
             node,
@@ -1456,7 +1482,7 @@
                   node.operator,
                   left,
                   typeEnvironment.coreTypes.boolLegacyRawType,
-                  right.getType(typeEnvironment)));
+                  right.getType(_staticTypeContext)));
         }
         return report(
             node,
@@ -1496,7 +1522,7 @@
           templateConstEvalInvalidType.withArguments(
               condition,
               typeEnvironment.coreTypes.boolLegacyRawType,
-              condition.getType(typeEnvironment)));
+              condition.getType(_staticTypeContext)));
     }
   }
 
@@ -1780,7 +1806,7 @@
         templateConstEvalInvalidType.withArguments(
             constant,
             typeEnvironment.coreTypes.boolLegacyRawType,
-            constant.getType(typeEnvironment)));
+            constant.getType(_staticTypeContext)));
   }
 
   @override
@@ -1839,7 +1865,7 @@
 
   bool hasPrimitiveEqual(Constant constant) {
     if (intFolder.isInt(constant)) return true;
-    DartType type = constant.getType(typeEnvironment);
+    DartType type = constant.getType(_staticTypeContext);
     return !(type is InterfaceType && !classHasPrimitiveEqual(type.classNode));
   }
 
@@ -1863,7 +1889,7 @@
       value ? trueConstant : falseConstant;
 
   bool isSubtype(Constant constant, DartType type) {
-    DartType constantType = constant.getType(typeEnvironment);
+    DartType constantType = constant.getType(_staticTypeContext);
     if (targetingJavaScript) {
       if (constantType is InterfaceType &&
           constantType.classNode == typeEnvironment.coreTypes.intClass &&
@@ -1892,7 +1918,7 @@
       return report(
           node,
           templateConstEvalInvalidType.withArguments(
-              constant, type, constant.getType(typeEnvironment)));
+              constant, type, constant.getType(_staticTypeContext)));
     }
     return constant;
   }
diff --git a/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart b/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
index 3fac4c1..ac47c4d 100644
--- a/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
@@ -81,7 +81,7 @@
 
 import 'kernel_builder.dart' show LoadLibraryBuilder;
 
-import 'kernel_shadow_ast.dart';
+import 'internal_ast.dart';
 
 /// A generator represents a subexpression for which we can't yet build an
 /// expression because we don't yet know the context in which it's used.
@@ -149,16 +149,13 @@
   Expression buildCompoundAssignment(Name binaryOperator, Expression value,
       {int offset: TreeNode.noOffset,
       bool voidContext: false,
-      Procedure interfaceTarget,
       bool isPreIncDec: false,
       bool isPostIncDec: false});
 
   /// Returns a [Expression] representing a pre-increment or pre-decrement of
   /// the generator.
   Expression buildPrefixIncrement(Name binaryOperator,
-      {int offset: TreeNode.noOffset,
-      bool voidContext: false,
-      Procedure interfaceTarget}) {
+      {int offset: TreeNode.noOffset, bool voidContext: false}) {
     return buildCompoundAssignment(
         binaryOperator, _forest.createIntLiteral(offset, 1),
         offset: offset,
@@ -166,21 +163,19 @@
         // instance `++a?.b;` is not providing a void context making it default
         // `true`.
         voidContext: voidContext,
-        interfaceTarget: interfaceTarget,
         isPreIncDec: true);
   }
 
   /// Returns a [Expression] representing a post-increment or post-decrement of
   /// the generator.
   Expression buildPostfixIncrement(Name binaryOperator,
-      {int offset: TreeNode.noOffset,
-      bool voidContext: false,
-      Procedure interfaceTarget});
+      {int offset: TreeNode.noOffset, bool voidContext: false});
 
   /// Returns a [Generator] or [Expression] representing an index access
   /// (e.g. `a[b]`) with the generator on the receiver and [index] as the
   /// index expression.
-  Generator buildIndexedAccess(Expression index, Token token);
+  Generator buildIndexedAccess(Expression index, Token token,
+      {bool isNullAware});
 
   /// Returns a [Expression] representing a compile-time error.
   ///
@@ -206,11 +201,13 @@
 
   Expression buildForEffect() => buildSimpleRead();
 
-  Initializer buildFieldInitializer(Map<String, int> initializedFields) {
-    return _helper.buildInvalidInitializer(
-        _helper.buildProblem(
-            messageInvalidInitializer, fileOffset, lengthForToken(token)),
-        fileOffset);
+  List<Initializer> buildFieldInitializer(Map<String, int> initializedFields) {
+    return <Initializer>[
+      _helper.buildInvalidInitializer(
+          _helper.buildProblem(
+              messageInvalidInitializer, fileOffset, lengthForToken(token)),
+          fileOffset)
+    ];
   }
 
   /// Returns an expression, generator or initializer for an invocation of this
@@ -383,39 +380,25 @@
   Expression buildCompoundAssignment(Name binaryOperator, Expression value,
       {int offset: TreeNode.noOffset,
       bool voidContext: false,
-      Procedure interfaceTarget,
       bool isPreIncDec: false,
       bool isPostIncDec: false}) {
-    MethodInvocation binary = _helper.forest.createMethodInvocation(
-        offset,
-        _createRead(),
-        binaryOperator,
-        _helper.forest.createArguments(offset, <Expression>[value]),
-        interfaceTarget: interfaceTarget);
+    Expression binary = _helper.forest
+        .createBinary(offset, _createRead(), binaryOperator, value);
     return _createWrite(fileOffset, binary);
   }
 
   @override
   Expression buildPostfixIncrement(Name binaryOperator,
-      {int offset = TreeNode.noOffset,
-      bool voidContext = false,
-      Procedure interfaceTarget}) {
+      {int offset = TreeNode.noOffset, bool voidContext = false}) {
     Expression value = _forest.createIntLiteral(offset, 1);
     if (voidContext) {
       return buildCompoundAssignment(binaryOperator, value,
-          offset: offset,
-          voidContext: voidContext,
-          interfaceTarget: interfaceTarget,
-          isPostIncDec: true);
+          offset: offset, voidContext: voidContext, isPostIncDec: true);
     }
     VariableDeclaration read =
         _helper.forest.createVariableDeclarationForValue(_createRead());
-    MethodInvocation binary = _helper.forest.createMethodInvocation(
-        offset,
-        _helper.createVariableGet(read, fileOffset),
-        binaryOperator,
-        _helper.forest.createArguments(offset, <Expression>[value]),
-        interfaceTarget: interfaceTarget);
+    Expression binary = _helper.forest.createBinary(offset,
+        _helper.createVariableGet(read, fileOffset), binaryOperator, value);
     VariableDeclaration write = _helper.forest
         .createVariableDeclarationForValue(_createWrite(offset, binary));
     return new LocalPostIncDec(read, write)..fileOffset = offset;
@@ -429,8 +412,11 @@
   }
 
   @override
-  Generator buildIndexedAccess(Expression index, Token token) {
-    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index);
+  Generator buildIndexedAccess(Expression index, Token token,
+      {bool isNullAware}) {
+    assert(isNullAware != null);
+    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index,
+        isNullAware: isNullAware);
   }
 
   @override
@@ -519,7 +505,6 @@
   Expression buildCompoundAssignment(Name binaryOperator, Expression value,
       {int offset: TreeNode.noOffset,
       bool voidContext: false,
-      Procedure interfaceTarget,
       bool isPreIncDec: false,
       bool isPostIncDec: false}) {
     return new CompoundPropertySet(receiver, name, binaryOperator, value,
@@ -533,28 +518,19 @@
 
   @override
   Expression buildPostfixIncrement(Name binaryOperator,
-      {int offset = TreeNode.noOffset,
-      bool voidContext = false,
-      Procedure interfaceTarget}) {
+      {int offset = TreeNode.noOffset, bool voidContext = false}) {
     Expression value = _forest.createIntLiteral(offset, 1);
     if (voidContext) {
       return buildCompoundAssignment(binaryOperator, value,
-          offset: offset,
-          voidContext: voidContext,
-          interfaceTarget: interfaceTarget,
-          isPostIncDec: true);
+          offset: offset, voidContext: voidContext, isPostIncDec: true);
     }
     VariableDeclaration variable =
         _helper.forest.createVariableDeclarationForValue(receiver);
     VariableDeclaration read = _helper.forest.createVariableDeclarationForValue(
         _forest.createPropertyGet(fileOffset,
             _helper.createVariableGet(variable, receiver.fileOffset), name));
-    MethodInvocation binary = _helper.forest.createMethodInvocation(
-        offset,
-        _helper.createVariableGet(read, fileOffset),
-        binaryOperator,
-        _helper.forest.createArguments(offset, <Expression>[value]),
-        interfaceTarget: interfaceTarget);
+    Expression binary = _helper.forest.createBinary(offset,
+        _helper.createVariableGet(read, fileOffset), binaryOperator, value);
     VariableDeclaration write = _helper.forest
         .createVariableDeclarationForValue(_helper.forest.createPropertySet(
             fileOffset,
@@ -566,8 +542,11 @@
   }
 
   @override
-  Generator buildIndexedAccess(Expression index, Token token) {
-    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index);
+  Generator buildIndexedAccess(Expression index, Token token,
+      {bool isNullAware}) {
+    assert(isNullAware != null);
+    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index,
+        isNullAware: isNullAware);
   }
 
   /// Creates a [Generator] for the access of property [name] on [receiver].
@@ -661,41 +640,36 @@
   Expression buildCompoundAssignment(Name binaryOperator, Expression value,
       {int offset: TreeNode.noOffset,
       bool voidContext: false,
-      Procedure interfaceTarget,
       bool isPreIncDec: false,
       bool isPostIncDec: false}) {
-    MethodInvocation binary = _helper.forest.createMethodInvocation(
+    _helper.forest.createBinary(
         offset,
         _forest.createPropertyGet(
             fileOffset, _forest.createThisExpression(fileOffset), name),
         binaryOperator,
-        _helper.forest.createArguments(offset, <Expression>[value]),
-        interfaceTarget: interfaceTarget);
+        value);
+    Expression binary = _helper.forest.createBinary(
+        offset,
+        _forest.createPropertyGet(
+            fileOffset, _forest.createThisExpression(fileOffset), name),
+        binaryOperator,
+        value);
     return _createWrite(fileOffset, binary, forEffect: voidContext);
   }
 
   @override
   Expression buildPostfixIncrement(Name binaryOperator,
-      {int offset = TreeNode.noOffset,
-      bool voidContext = false,
-      Procedure interfaceTarget}) {
+      {int offset = TreeNode.noOffset, bool voidContext = false}) {
     Expression value = _forest.createIntLiteral(offset, 1);
     if (voidContext) {
       return buildCompoundAssignment(binaryOperator, value,
-          offset: offset,
-          voidContext: voidContext,
-          interfaceTarget: interfaceTarget,
-          isPostIncDec: true);
+          offset: offset, voidContext: voidContext, isPostIncDec: true);
     }
     VariableDeclaration read = _helper.forest.createVariableDeclarationForValue(
         _forest.createPropertyGet(
             fileOffset, _forest.createThisExpression(fileOffset), name));
-    MethodInvocation binary = _helper.forest.createMethodInvocation(
-        offset,
-        _helper.createVariableGet(read, fileOffset),
-        binaryOperator,
-        _helper.forest.createArguments(offset, <Expression>[value]),
-        interfaceTarget: interfaceTarget);
+    Expression binary = _helper.forest.createBinary(offset,
+        _helper.createVariableGet(read, fileOffset), binaryOperator, value);
     VariableDeclaration write = _helper.forest
         .createVariableDeclarationForValue(
             _createWrite(fileOffset, binary, forEffect: true));
@@ -709,8 +683,11 @@
   }
 
   @override
-  Generator buildIndexedAccess(Expression index, Token token) {
-    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index);
+  Generator buildIndexedAccess(Expression index, Token token,
+      {bool isNullAware}) {
+    assert(isNullAware != null);
+    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index,
+        isNullAware: isNullAware);
   }
 
   @override
@@ -729,7 +706,8 @@
 
   NullAwarePropertyAccessGenerator(ExpressionGeneratorHelper helper,
       Token token, this.receiverExpression, this.name)
-      : this.receiver = makeOrReuseVariable(receiverExpression),
+      : this.receiver =
+            helper.forest.createVariableDeclarationForValue(receiverExpression),
         super(helper, token);
 
   @override
@@ -780,7 +758,6 @@
   Expression buildCompoundAssignment(Name binaryOperator, Expression value,
       {int offset: TreeNode.noOffset,
       bool voidContext: false,
-      Procedure interfaceTarget,
       bool isPreIncDec: false,
       bool isPostIncDec: false}) {
     return new NullAwareCompoundSet(
@@ -793,15 +770,10 @@
   }
 
   Expression buildPostfixIncrement(Name binaryOperator,
-      {int offset: TreeNode.noOffset,
-      bool voidContext: false,
-      Procedure interfaceTarget}) {
+      {int offset: TreeNode.noOffset, bool voidContext: false}) {
     return buildCompoundAssignment(
         binaryOperator, _forest.createIntLiteral(offset, 1),
-        offset: offset,
-        voidContext: voidContext,
-        interfaceTarget: interfaceTarget,
-        isPostIncDec: true);
+        offset: offset, voidContext: voidContext, isPostIncDec: true);
   }
 
   @override
@@ -810,8 +782,11 @@
   }
 
   @override
-  Generator buildIndexedAccess(Expression index, Token token) {
-    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index);
+  Generator buildIndexedAccess(Expression index, Token token,
+      {bool isNullAware}) {
+    assert(isNullAware != null);
+    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index,
+        isNullAware: isNullAware);
   }
 
   @override
@@ -873,39 +848,25 @@
   Expression buildCompoundAssignment(Name binaryOperator, Expression value,
       {int offset = TreeNode.noOffset,
       bool voidContext = false,
-      Procedure interfaceTarget,
       bool isPreIncDec = false,
       bool isPostIncDec = false}) {
-    MethodInvocation binary = _helper.forest.createMethodInvocation(
-        offset,
-        _createRead(),
-        binaryOperator,
-        _helper.forest.createArguments(offset, <Expression>[value]),
-        interfaceTarget: interfaceTarget);
+    Expression binary = _helper.forest
+        .createBinary(offset, _createRead(), binaryOperator, value);
     return _createWrite(fileOffset, binary);
   }
 
   @override
   Expression buildPostfixIncrement(Name binaryOperator,
-      {int offset = TreeNode.noOffset,
-      bool voidContext = false,
-      Procedure interfaceTarget}) {
+      {int offset = TreeNode.noOffset, bool voidContext = false}) {
     Expression value = _forest.createIntLiteral(offset, 1);
     if (voidContext) {
       return buildCompoundAssignment(binaryOperator, value,
-          offset: offset,
-          voidContext: voidContext,
-          interfaceTarget: interfaceTarget,
-          isPostIncDec: true);
+          offset: offset, voidContext: voidContext, isPostIncDec: true);
     }
     VariableDeclaration read =
         _helper.forest.createVariableDeclarationForValue(_createRead());
-    MethodInvocation binary = _helper.forest.createMethodInvocation(
-        offset,
-        _helper.createVariableGet(read, fileOffset),
-        binaryOperator,
-        _helper.forest.createArguments(offset, <Expression>[value]),
-        interfaceTarget: interfaceTarget);
+    Expression binary = _helper.forest.createBinary(offset,
+        _helper.createVariableGet(read, fileOffset), binaryOperator, value);
     VariableDeclaration write = _helper.forest
         .createVariableDeclarationForValue(_createWrite(fileOffset, binary));
     return new StaticPostIncDec(read, write)..fileOffset = offset;
@@ -940,8 +901,11 @@
   }
 
   @override
-  Generator buildIndexedAccess(Expression index, Token token) {
-    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index);
+  Generator buildIndexedAccess(Expression index, Token token,
+      {bool isNullAware}) {
+    assert(isNullAware != null);
+    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index,
+        isNullAware: isNullAware);
   }
 
   @override
@@ -965,8 +929,9 @@
 
   IndexedAccessGenerator(
       ExpressionGeneratorHelper helper, Token token, this.receiver, this.index,
-      {this.isNullAware: false})
-      : super(helper, token);
+      {this.isNullAware})
+      : assert(isNullAware != null),
+        super(helper, token);
 
   @override
   String get _plainNameForRead => "[]";
@@ -976,56 +941,113 @@
 
   @override
   Expression buildSimpleRead() {
-    return _helper.buildMethodInvocation(
-        receiver,
-        indexGetName,
-        _helper.forest.createArguments(fileOffset, <Expression>[index]),
-        fileOffset);
+    VariableDeclaration variable;
+    Expression receiverValue;
+    if (isNullAware) {
+      variable = _forest.createVariableDeclarationForValue(receiver);
+      receiverValue = _helper.createVariableGet(variable, fileOffset);
+    } else {
+      receiverValue = receiver;
+    }
+    Expression result =
+        _forest.createIndexGet(fileOffset, receiverValue, index);
+    if (isNullAware) {
+      result = new NullAwareMethodInvocation(variable, result)
+        ..fileOffset = fileOffset;
+    }
+    return result;
   }
 
   @override
   Expression buildAssignment(Expression value, {bool voidContext: false}) {
-    return new IndexSet(receiver, index, value,
-        forEffect: voidContext, readOnlyReceiver: false)
-      ..fileOffset = fileOffset;
+    VariableDeclaration variable;
+    Expression receiverValue;
+    bool readOnlyReceiver;
+    if (isNullAware) {
+      variable = _forest.createVariableDeclarationForValue(receiver);
+      receiverValue = _helper.createVariableGet(variable, fileOffset);
+      readOnlyReceiver = true;
+    } else {
+      receiverValue = receiver;
+      readOnlyReceiver = false;
+    }
+    Expression result = _forest.createIndexSet(
+        fileOffset, receiverValue, index, value,
+        forEffect: voidContext, readOnlyReceiver: readOnlyReceiver);
+    if (isNullAware) {
+      result = new NullAwareMethodInvocation(variable, result)
+        ..fileOffset = fileOffset;
+    }
+    return result;
   }
 
   @override
   Expression buildIfNullAssignment(Expression value, DartType type, int offset,
       {bool voidContext: false}) {
-    return new IfNullIndexSet(receiver, index, value,
+    VariableDeclaration variable;
+    Expression receiverValue;
+    bool readOnlyReceiver;
+    if (isNullAware) {
+      variable = _forest.createVariableDeclarationForValue(receiver);
+      receiverValue = _helper.createVariableGet(variable, fileOffset);
+      readOnlyReceiver = true;
+    } else {
+      receiverValue = receiver;
+      readOnlyReceiver = false;
+    }
+
+    Expression result = new IfNullIndexSet(receiverValue, index, value,
         readOffset: fileOffset,
         testOffset: offset,
         writeOffset: fileOffset,
-        forEffect: voidContext)
+        forEffect: voidContext,
+        readOnlyReceiver: readOnlyReceiver)
       ..fileOffset = offset;
+    if (isNullAware) {
+      result = new NullAwareMethodInvocation(variable, result)
+        ..fileOffset = fileOffset;
+    }
+    return result;
   }
 
   Expression buildCompoundAssignment(Name binaryOperator, Expression value,
       {int offset: TreeNode.noOffset,
       bool voidContext: false,
-      Procedure interfaceTarget,
       bool isPreIncDec: false,
       bool isPostIncDec: false}) {
-    return new CompoundIndexSet(receiver, index, binaryOperator, value,
+    VariableDeclaration variable;
+    Expression receiverValue;
+    bool readOnlyReceiver;
+    if (isNullAware) {
+      variable = _forest.createVariableDeclarationForValue(receiver);
+      receiverValue = _helper.createVariableGet(variable, fileOffset);
+      readOnlyReceiver = true;
+    } else {
+      receiverValue = receiver;
+      readOnlyReceiver = false;
+    }
+
+    Expression result = new CompoundIndexSet(
+        receiverValue, index, binaryOperator, value,
         readOffset: fileOffset,
         binaryOffset: offset,
         writeOffset: fileOffset,
         forEffect: voidContext,
-        forPostIncDec: isPostIncDec);
+        forPostIncDec: isPostIncDec,
+        readOnlyReceiver: readOnlyReceiver);
+    if (isNullAware) {
+      result = new NullAwareMethodInvocation(variable, result)
+        ..fileOffset = fileOffset;
+    }
+    return result;
   }
 
   @override
   Expression buildPostfixIncrement(Name binaryOperator,
-      {int offset = TreeNode.noOffset,
-      bool voidContext = false,
-      Procedure interfaceTarget}) {
+      {int offset = TreeNode.noOffset, bool voidContext = false}) {
     Expression value = _forest.createIntLiteral(offset, 1);
     return buildCompoundAssignment(binaryOperator, value,
-        offset: offset,
-        voidContext: voidContext,
-        interfaceTarget: interfaceTarget,
-        isPostIncDec: true);
+        offset: offset, voidContext: voidContext, isPostIncDec: true);
   }
 
   @override
@@ -1036,9 +1058,11 @@
   }
 
   @override
-  Generator buildIndexedAccess(Expression index, Token token) {
+  Generator buildIndexedAccess(Expression index, Token token,
+      {bool isNullAware}) {
+    assert(isNullAware != null);
     return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index,
-        isNullAware: false);
+        isNullAware: isNullAware);
   }
 
   @override
@@ -1048,14 +1072,18 @@
     printNodeOn(receiver, sink, syntheticNames: syntheticNames);
     sink.write(", index: ");
     printNodeOn(index, sink, syntheticNames: syntheticNames);
+    sink.write(", isNullAware: ${isNullAware}");
   }
 
   static Generator make(ExpressionGeneratorHelper helper, Token token,
-      Expression receiver, Expression index) {
+      Expression receiver, Expression index,
+      {bool isNullAware}) {
+    assert(isNullAware != null);
     if (helper.forest.isThisExpression(receiver)) {
       return new ThisIndexedAccessGenerator(helper, token, index);
     } else {
-      return new IndexedAccessGenerator(helper, token, receiver, index);
+      return new IndexedAccessGenerator(helper, token, receiver, index,
+          isNullAware: isNullAware);
     }
   }
 }
@@ -1078,19 +1106,14 @@
   @override
   Expression buildSimpleRead() {
     Expression receiver = _helper.forest.createThisExpression(fileOffset);
-    return _helper.buildMethodInvocation(
-        receiver,
-        indexGetName,
-        _helper.forest.createArguments(fileOffset, <Expression>[index]),
-        fileOffset);
+    return _forest.createIndexGet(fileOffset, receiver, index);
   }
 
   @override
   Expression buildAssignment(Expression value, {bool voidContext: false}) {
     Expression receiver = _helper.forest.createThisExpression(fileOffset);
-    return new IndexSet(receiver, index, value,
-        forEffect: voidContext, readOnlyReceiver: true)
-      ..fileOffset = fileOffset;
+    return _forest.createIndexSet(fileOffset, receiver, index, value,
+        forEffect: voidContext, readOnlyReceiver: true);
   }
 
   @override
@@ -1109,7 +1132,6 @@
   Expression buildCompoundAssignment(Name binaryOperator, Expression value,
       {int offset: TreeNode.noOffset,
       bool voidContext: false,
-      Procedure interfaceTarget,
       bool isPreIncDec: false,
       bool isPostIncDec: false}) {
     Expression receiver = _helper.forest.createThisExpression(fileOffset);
@@ -1124,15 +1146,10 @@
 
   @override
   Expression buildPostfixIncrement(Name binaryOperator,
-      {int offset = TreeNode.noOffset,
-      bool voidContext = false,
-      Procedure interfaceTarget}) {
+      {int offset = TreeNode.noOffset, bool voidContext = false}) {
     Expression value = _forest.createIntLiteral(offset, 1);
     return buildCompoundAssignment(binaryOperator, value,
-        offset: offset,
-        voidContext: voidContext,
-        interfaceTarget: interfaceTarget,
-        isPostIncDec: true);
+        offset: offset, voidContext: voidContext, isPostIncDec: true);
   }
 
   @override
@@ -1143,8 +1160,11 @@
   }
 
   @override
-  Generator buildIndexedAccess(Expression index, Token token) {
-    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index);
+  Generator buildIndexedAccess(Expression index, Token token,
+      {bool isNullAware}) {
+    assert(isNullAware != null);
+    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index,
+        isNullAware: isNullAware);
   }
 
   @override
@@ -1213,7 +1233,6 @@
   Expression buildCompoundAssignment(Name binaryOperator, Expression value,
       {int offset: TreeNode.noOffset,
       bool voidContext: false,
-      Procedure interfaceTarget,
       bool isPreIncDec: false,
       bool isPostIncDec: false}) {
     return new CompoundSuperIndexSet(
@@ -1227,15 +1246,10 @@
 
   @override
   Expression buildPostfixIncrement(Name binaryOperator,
-      {int offset = TreeNode.noOffset,
-      bool voidContext = false,
-      Procedure interfaceTarget}) {
+      {int offset = TreeNode.noOffset, bool voidContext = false}) {
     Expression value = _forest.createIntLiteral(offset, 1);
     return buildCompoundAssignment(binaryOperator, value,
-        offset: offset,
-        voidContext: voidContext,
-        interfaceTarget: interfaceTarget,
-        isPostIncDec: true);
+        offset: offset, voidContext: voidContext, isPostIncDec: true);
   }
 
   @override
@@ -1246,8 +1260,11 @@
   }
 
   @override
-  Generator buildIndexedAccess(Expression index, Token token) {
-    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index);
+  Generator buildIndexedAccess(Expression index, Token token,
+      {bool isNullAware}) {
+    assert(isNullAware != null);
+    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index,
+        isNullAware: isNullAware);
   }
 
   @override
@@ -1326,7 +1343,7 @@
       MemberBuilder getterBuilder,
       MemberBuilder setterBuilder) {
     return new StaticAccessGenerator(helper, token, targetName,
-        getterBuilder?.member, setterBuilder?.member);
+        getterBuilder?.readTarget, setterBuilder?.writeTarget);
   }
 
   @override
@@ -1377,39 +1394,25 @@
   Expression buildCompoundAssignment(Name binaryOperator, Expression value,
       {int offset = TreeNode.noOffset,
       bool voidContext = false,
-      Procedure interfaceTarget,
       bool isPreIncDec = false,
       bool isPostIncDec = false}) {
-    MethodInvocation binary = _helper.forest.createMethodInvocation(
-        offset,
-        _createRead(),
-        binaryOperator,
-        _helper.forest.createArguments(offset, <Expression>[value]),
-        interfaceTarget: interfaceTarget);
+    Expression binary = _helper.forest
+        .createBinary(offset, _createRead(), binaryOperator, value);
     return _createWrite(fileOffset, binary);
   }
 
   @override
   Expression buildPostfixIncrement(Name binaryOperator,
-      {int offset = TreeNode.noOffset,
-      bool voidContext = false,
-      Procedure interfaceTarget}) {
+      {int offset = TreeNode.noOffset, bool voidContext = false}) {
     Expression value = _forest.createIntLiteral(offset, 1);
     if (voidContext) {
       return buildCompoundAssignment(binaryOperator, value,
-          offset: offset,
-          voidContext: voidContext,
-          interfaceTarget: interfaceTarget,
-          isPostIncDec: true);
+          offset: offset, voidContext: voidContext, isPostIncDec: true);
     }
     VariableDeclaration read =
         _helper.forest.createVariableDeclarationForValue(_createRead());
-    MethodInvocation binary = _helper.forest.createMethodInvocation(
-        offset,
-        _helper.createVariableGet(read, fileOffset),
-        binaryOperator,
-        _helper.forest.createArguments(offset, <Expression>[value]),
-        interfaceTarget: interfaceTarget);
+    Expression binary = _helper.forest.createBinary(offset,
+        _helper.createVariableGet(read, fileOffset), binaryOperator, value);
     VariableDeclaration write = _helper.forest
         .createVariableDeclarationForValue(_createWrite(offset, binary));
     return new StaticPostIncDec(read, write)..fileOffset = offset;
@@ -1438,8 +1441,11 @@
   }
 
   @override
-  Generator buildIndexedAccess(Expression index, Token token) {
-    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index);
+  Generator buildIndexedAccess(Expression index, Token token,
+      {bool isNullAware}) {
+    assert(isNullAware != null);
+    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index,
+        isNullAware: isNullAware);
   }
 
   @override
@@ -1590,8 +1596,9 @@
     if (extensionTypeParameters != null) {
       extensionTypeArguments = [];
       for (TypeParameter typeParameter in extensionTypeParameters) {
-        extensionTypeArguments
-            .add(_forest.createTypeParameterType(typeParameter));
+        extensionTypeArguments.add(
+            _forest.createTypeParameterTypeWithDefaultNullabilityForLibrary(
+                typeParameter, extension.enclosingLibrary));
       }
     }
     return extensionTypeArguments;
@@ -1657,39 +1664,25 @@
   Expression buildCompoundAssignment(Name binaryOperator, Expression value,
       {int offset: TreeNode.noOffset,
       bool voidContext: false,
-      Procedure interfaceTarget,
       bool isPreIncDec: false,
       bool isPostIncDec: false}) {
-    MethodInvocation binary = _helper.forest.createMethodInvocation(
-        offset,
-        _createRead(),
-        binaryOperator,
-        _helper.forest.createArguments(offset, <Expression>[value]),
-        interfaceTarget: interfaceTarget);
+    Expression binary = _helper.forest
+        .createBinary(offset, _createRead(), binaryOperator, value);
     return _createWrite(fileOffset, binary, forEffect: voidContext);
   }
 
   @override
   Expression buildPostfixIncrement(Name binaryOperator,
-      {int offset = TreeNode.noOffset,
-      bool voidContext = false,
-      Procedure interfaceTarget}) {
+      {int offset = TreeNode.noOffset, bool voidContext = false}) {
     Expression value = _forest.createIntLiteral(offset, 1);
     if (voidContext) {
       return buildCompoundAssignment(binaryOperator, value,
-          offset: offset,
-          voidContext: voidContext,
-          interfaceTarget: interfaceTarget,
-          isPostIncDec: true);
+          offset: offset, voidContext: voidContext, isPostIncDec: true);
     }
     VariableDeclaration read =
         _helper.forest.createVariableDeclarationForValue(_createRead());
-    MethodInvocation binary = _helper.forest.createMethodInvocation(
-        offset,
-        _helper.createVariableGet(read, fileOffset),
-        binaryOperator,
-        _helper.forest.createArguments(offset, <Expression>[value]),
-        interfaceTarget: interfaceTarget);
+    Expression binary = _helper.forest.createBinary(offset,
+        _helper.createVariableGet(read, fileOffset), binaryOperator, value);
     VariableDeclaration write = _helper.forest
         .createVariableDeclarationForValue(
             _createWrite(fileOffset, binary, forEffect: true));
@@ -1721,8 +1714,11 @@
   }
 
   @override
-  Generator buildIndexedAccess(Expression index, Token token) {
-    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index);
+  Generator buildIndexedAccess(Expression index, Token token,
+      {bool isNullAware}) {
+    assert(isNullAware != null);
+    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index,
+        isNullAware: isNullAware);
   }
 
   @override
@@ -2013,18 +2009,16 @@
   Expression buildCompoundAssignment(Name binaryOperator, Expression value,
       {int offset: TreeNode.noOffset,
       bool voidContext: false,
-      Procedure interfaceTarget,
       bool isPreIncDec: false,
       bool isPostIncDec: false}) {
     if (isNullAware) {
       VariableDeclaration variable =
           _helper.forest.createVariableDeclarationForValue(receiver);
-      MethodInvocation binary = _helper.forest.createMethodInvocation(
+      Expression binary = _helper.forest.createBinary(
           offset,
           _createRead(_helper.createVariableGet(variable, receiver.fileOffset)),
           binaryOperator,
-          _helper.forest.createArguments(offset, <Expression>[value]),
-          interfaceTarget: interfaceTarget);
+          value);
       Expression write = _createWrite(fileOffset,
           _helper.createVariableGet(variable, receiver.fileOffset), binary,
           forEffect: voidContext, readOnlyReceiver: true);
@@ -2043,28 +2037,19 @@
 
   @override
   Expression buildPostfixIncrement(Name binaryOperator,
-      {int offset = TreeNode.noOffset,
-      bool voidContext = false,
-      Procedure interfaceTarget}) {
+      {int offset = TreeNode.noOffset, bool voidContext = false}) {
     Expression value = _forest.createIntLiteral(offset, 1);
     if (voidContext) {
       return buildCompoundAssignment(binaryOperator, value,
-          offset: offset,
-          voidContext: voidContext,
-          interfaceTarget: interfaceTarget,
-          isPostIncDec: true);
+          offset: offset, voidContext: voidContext, isPostIncDec: true);
     } else if (isNullAware) {
       VariableDeclaration variable =
           _helper.forest.createVariableDeclarationForValue(receiver);
       VariableDeclaration read = _helper.forest
           .createVariableDeclarationForValue(_createRead(
               _helper.createVariableGet(variable, receiver.fileOffset)));
-      MethodInvocation binary = _helper.forest.createMethodInvocation(
-          offset,
-          _helper.createVariableGet(read, fileOffset),
-          binaryOperator,
-          _helper.forest.createArguments(offset, <Expression>[value]),
-          interfaceTarget: interfaceTarget);
+      Expression binary = _helper.forest.createBinary(offset,
+          _helper.createVariableGet(read, fileOffset), binaryOperator, value);
       VariableDeclaration write = _helper.forest
           .createVariableDeclarationForValue(_createWrite(fileOffset,
               _helper.createVariableGet(variable, receiver.fileOffset), binary,
@@ -2079,12 +2064,8 @@
       VariableDeclaration read = _helper.forest
           .createVariableDeclarationForValue(_createRead(
               _helper.createVariableGet(variable, receiver.fileOffset)));
-      MethodInvocation binary = _helper.forest.createMethodInvocation(
-          offset,
-          _helper.createVariableGet(read, fileOffset),
-          binaryOperator,
-          _helper.forest.createArguments(offset, <Expression>[value]),
-          interfaceTarget: interfaceTarget);
+      Expression binary = _helper.forest.createBinary(offset,
+          _helper.createVariableGet(read, fileOffset), binaryOperator, value);
       VariableDeclaration write = _helper.forest
           .createVariableDeclarationForValue(_createWrite(fileOffset,
               _helper.createVariableGet(variable, receiver.fileOffset), binary,
@@ -2139,8 +2120,11 @@
   }
 
   @override
-  Generator buildIndexedAccess(Expression index, Token token) {
-    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index);
+  Generator buildIndexedAccess(Expression index, Token token,
+      {bool isNullAware}) {
+    assert(isNullAware != null);
+    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index,
+        isNullAware: isNullAware);
   }
 
   @override
@@ -2186,6 +2170,8 @@
   /// The number of type parameters declared on the extension declaration.
   final int extensionTypeParameterCount;
 
+  final bool isNullAware;
+
   ExplicitExtensionIndexedAccessGenerator(
       ExpressionGeneratorHelper helper,
       Token token,
@@ -2196,9 +2182,11 @@
       this.receiver,
       this.index,
       this.explicitTypeArguments,
-      this.extensionTypeParameterCount)
+      this.extensionTypeParameterCount,
+      {this.isNullAware})
       : assert(readTarget != null || writeTarget != null),
         assert(receiver != null),
+        assert(isNullAware != null),
         super(helper, token);
 
   factory ExplicitExtensionIndexedAccessGenerator.fromBuilder(
@@ -2211,7 +2199,9 @@
       Expression receiver,
       Expression index,
       List<DartType> explicitTypeArguments,
-      int extensionTypeParameterCount) {
+      int extensionTypeParameterCount,
+      {bool isNullAware}) {
+    assert(isNullAware != null);
     Procedure readTarget;
     if (getterBuilder != null) {
       if (getterBuilder is AccessErrorBuilder) {
@@ -2246,7 +2236,8 @@
         receiver,
         index,
         explicitTypeArguments,
-        extensionTypeParameterCount);
+        extensionTypeParameterCount,
+        isNullAware: isNullAware);
   }
 
   List<DartType> _createExtensionTypeArguments() {
@@ -2262,15 +2253,28 @@
     if (readTarget == null) {
       return _makeInvalidRead();
     }
-    return _helper.buildExtensionMethodInvocation(
+    VariableDeclaration variable;
+    Expression receiverValue;
+    if (isNullAware) {
+      variable = _forest.createVariableDeclarationForValue(receiver);
+      receiverValue = _helper.createVariableGet(variable, fileOffset);
+    } else {
+      receiverValue = receiver;
+    }
+    Expression result = _helper.buildExtensionMethodInvocation(
         fileOffset,
         readTarget,
         _forest.createArgumentsForExtensionMethod(
-            fileOffset, extensionTypeParameterCount, 0, receiver,
+            fileOffset, extensionTypeParameterCount, 0, receiverValue,
             extensionTypeArguments: _createExtensionTypeArguments(),
             extensionTypeArgumentOffset: extensionTypeArgumentOffset,
             positionalArguments: <Expression>[index]),
         isTearOff: false);
+    if (isNullAware) {
+      result = new NullAwareMethodInvocation(variable, result)
+        ..fileOffset = fileOffset;
+    }
+    return result;
   }
 
   @override
@@ -2278,61 +2282,116 @@
     if (writeTarget == null) {
       return _makeInvalidWrite(value);
     }
+    VariableDeclaration variable;
+    Expression receiverValue;
+    if (isNullAware) {
+      variable = _forest.createVariableDeclarationForValue(receiver);
+      receiverValue = _helper.createVariableGet(variable, fileOffset);
+    } else {
+      receiverValue = receiver;
+    }
+    Expression result;
     if (voidContext) {
-      return _helper.buildExtensionMethodInvocation(
+      result = _helper.buildExtensionMethodInvocation(
           fileOffset,
           writeTarget,
           _forest.createArgumentsForExtensionMethod(
-              fileOffset, extensionTypeParameterCount, 0, receiver,
+              fileOffset, extensionTypeParameterCount, 0, receiverValue,
               extensionTypeArguments: _createExtensionTypeArguments(),
               extensionTypeArgumentOffset: extensionTypeArgumentOffset,
               positionalArguments: <Expression>[index, value]),
           isTearOff: false);
     } else {
-      return new ExtensionIndexSet(
-          extension, explicitTypeArguments, receiver, writeTarget, index, value)
+      result = new ExtensionIndexSet(extension, explicitTypeArguments,
+          receiverValue, writeTarget, index, value)
         ..fileOffset = fileOffset;
     }
+    if (isNullAware) {
+      result = new NullAwareMethodInvocation(variable, result)
+        ..fileOffset = fileOffset;
+    }
+    return result;
   }
 
   @override
   Expression buildIfNullAssignment(Expression value, DartType type, int offset,
       {bool voidContext: false}) {
-    return new IfNullExtensionIndexSet(extension, explicitTypeArguments,
-        receiver, readTarget, writeTarget, index, value,
+    VariableDeclaration variable;
+    Expression receiverValue;
+    bool readOnlyReceiver;
+    if (isNullAware) {
+      variable = _forest.createVariableDeclarationForValue(receiver);
+      receiverValue = _helper.createVariableGet(variable, fileOffset);
+      readOnlyReceiver = true;
+    } else {
+      receiverValue = receiver;
+      readOnlyReceiver = false;
+    }
+    Expression result = new IfNullExtensionIndexSet(
+        extension,
+        explicitTypeArguments,
+        receiverValue,
+        readTarget,
+        writeTarget,
+        index,
+        value,
         readOffset: fileOffset,
         testOffset: offset,
         writeOffset: fileOffset,
-        forEffect: voidContext)
+        forEffect: voidContext,
+        readOnlyReceiver: readOnlyReceiver)
       ..fileOffset = offset;
+    if (isNullAware) {
+      result = new NullAwareMethodInvocation(variable, result)
+        ..fileOffset = fileOffset;
+    }
+    return result;
   }
 
   Expression buildCompoundAssignment(Name binaryOperator, Expression value,
       {int offset: TreeNode.noOffset,
       bool voidContext: false,
-      Procedure interfaceTarget,
       bool isPreIncDec: false,
       bool isPostIncDec: false}) {
-    return new CompoundExtensionIndexSet(extension, explicitTypeArguments,
-        receiver, readTarget, writeTarget, index, binaryOperator, value,
+    VariableDeclaration variable;
+    Expression receiverValue;
+    bool readOnlyReceiver;
+    if (isNullAware) {
+      variable = _forest.createVariableDeclarationForValue(receiver);
+      receiverValue = _helper.createVariableGet(variable, fileOffset);
+      readOnlyReceiver = true;
+    } else {
+      receiverValue = receiver;
+      readOnlyReceiver = false;
+    }
+    Expression result = new CompoundExtensionIndexSet(
+        extension,
+        explicitTypeArguments,
+        receiverValue,
+        readTarget,
+        writeTarget,
+        index,
+        binaryOperator,
+        value,
         readOffset: fileOffset,
         binaryOffset: offset,
         writeOffset: fileOffset,
         forEffect: voidContext,
-        forPostIncDec: isPostIncDec);
+        forPostIncDec: isPostIncDec,
+        readOnlyReceiver: readOnlyReceiver);
+    if (isNullAware) {
+      result = new NullAwareMethodInvocation(variable, result)
+        ..fileOffset = fileOffset;
+    }
+    return result;
   }
 
   @override
   Expression buildPostfixIncrement(Name binaryOperator,
-      {int offset = TreeNode.noOffset,
-      bool voidContext = false,
-      Procedure interfaceTarget}) {
+      {int offset = TreeNode.noOffset, bool voidContext = false}) {
     Expression value = _forest.createIntLiteral(offset, 1);
     return buildCompoundAssignment(binaryOperator, value,
-        offset: offset,
-        voidContext: voidContext,
-        interfaceTarget: interfaceTarget,
-        isPostIncDec: true);
+        offset: offset, voidContext: voidContext, isPostIncDec: true);
   }
 
   @override
@@ -2343,8 +2402,11 @@
   }
 
   @override
-  Generator buildIndexedAccess(Expression index, Token token) {
-    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index);
+  Generator buildIndexedAccess(Expression index, Token token,
+      {bool isNullAware}) {
+    assert(isNullAware != null);
+    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index,
+        isNullAware: isNullAware);
   }
 
   @override
@@ -2423,16 +2485,13 @@
   Expression buildCompoundAssignment(Name binaryOperator, Expression value,
       {int offset: TreeNode.noOffset,
       bool voidContext: false,
-      Procedure interfaceTarget,
       bool isPreIncDec: false,
       bool isPostIncDec: false}) {
     return _makeInvalidRead();
   }
 
   Expression buildPostfixIncrement(Name binaryOperator,
-      {int offset: TreeNode.noOffset,
-      bool voidContext: false,
-      Procedure interfaceTarget}) {
+      {int offset: TreeNode.noOffset, bool voidContext: false}) {
     return _makeInvalidRead();
   }
 
@@ -2517,7 +2576,9 @@
   }
 
   @override
-  Generator buildIndexedAccess(Expression index, Token token) {
+  Generator buildIndexedAccess(Expression index, Token token,
+      {bool isNullAware}) {
+    assert(isNullAware != null);
     Builder getter = extensionBuilder.lookupLocalMemberByName(indexGetName);
     Builder setter = extensionBuilder.lookupLocalMemberByName(indexSetName);
     if (getter == null && setter == null) {
@@ -2537,7 +2598,8 @@
         receiver,
         index,
         explicitTypeArguments,
-        extensionBuilder.typeParameters?.length ?? 0);
+        extensionBuilder.typeParameters?.length ?? 0,
+        isNullAware: isNullAware);
   }
 
   @override
@@ -2589,29 +2651,19 @@
   Expression buildCompoundAssignment(Name binaryOperator, Expression value,
       {int offset: TreeNode.noOffset,
       bool voidContext: false,
-      Procedure interfaceTarget,
       bool isPreIncDec: false,
       bool isPostIncDec: false}) {
-    MethodInvocation binary = _helper.forest.createMethodInvocation(
-        offset,
-        buildSimpleRead(),
-        binaryOperator,
-        _helper.forest.createArguments(offset, <Expression>[value]),
-        interfaceTarget: interfaceTarget);
+    Expression binary = _helper.forest
+        .createBinary(offset, buildSimpleRead(), binaryOperator, value);
     return _makeInvalidWrite(binary);
   }
 
   @override
   Expression buildPostfixIncrement(Name binaryOperator,
-      {int offset = TreeNode.noOffset,
-      bool voidContext = false,
-      Procedure interfaceTarget}) {
+      {int offset = TreeNode.noOffset, bool voidContext = false}) {
     Expression value = _forest.createIntLiteral(offset, 1);
     return buildCompoundAssignment(binaryOperator, value,
-        offset: offset,
-        voidContext: voidContext,
-        interfaceTarget: interfaceTarget,
-        isPostIncDec: true);
+        offset: offset, voidContext: voidContext, isPostIncDec: true);
   }
 
   @override
@@ -2625,8 +2677,11 @@
   }
 
   @override
-  Generator buildIndexedAccess(Expression index, Token token) {
-    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index);
+  Generator buildIndexedAccess(Expression index, Token token,
+      {bool isNullAware}) {
+    assert(isNullAware != null);
+    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index,
+        isNullAware: isNullAware);
   }
 
   @override
@@ -2673,14 +2728,12 @@
   Expression buildCompoundAssignment(Name binaryOperator, Expression value,
       {int offset: TreeNode.noOffset,
       bool voidContext: false,
-      Procedure interfaceTarget,
       bool isPreIncDec: false,
       bool isPostIncDec: false}) {
     return _helper.wrapInDeferredCheck(
         suffixGenerator.buildCompoundAssignment(binaryOperator, value,
             offset: offset,
             voidContext: voidContext,
-            interfaceTarget: interfaceTarget,
             isPreIncDec: isPreIncDec,
             isPostIncDec: isPostIncDec),
         prefixGenerator.prefix,
@@ -2689,14 +2742,10 @@
 
   @override
   Expression buildPostfixIncrement(Name binaryOperator,
-      {int offset: TreeNode.noOffset,
-      bool voidContext: false,
-      Procedure interfaceTarget}) {
+      {int offset: TreeNode.noOffset, bool voidContext: false}) {
     return _helper.wrapInDeferredCheck(
         suffixGenerator.buildPostfixIncrement(binaryOperator,
-            offset: offset,
-            voidContext: voidContext,
-            interfaceTarget: interfaceTarget),
+            offset: offset, voidContext: voidContext),
         prefixGenerator.prefix,
         token.charOffset);
   }
@@ -2781,8 +2830,11 @@
   }
 
   @override
-  Generator buildIndexedAccess(Expression index, Token token) {
-    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index);
+  Generator buildIndexedAccess(Expression index, Token token,
+      {bool isNullAware}) {
+    assert(isNullAware != null);
+    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index,
+        isNullAware: isNullAware);
   }
 
   @override
@@ -3080,29 +3132,19 @@
   Expression buildCompoundAssignment(Name binaryOperator, Expression value,
       {int offset: TreeNode.noOffset,
       bool voidContext: false,
-      Procedure interfaceTarget,
       bool isPreIncDec: false,
       bool isPostIncDec: false}) {
-    MethodInvocation binary = _helper.forest.createMethodInvocation(
-        offset,
-        _createRead(),
-        binaryOperator,
-        _helper.forest.createArguments(offset, <Expression>[value]),
-        interfaceTarget: interfaceTarget);
+    Expression binary = _helper.forest
+        .createBinary(offset, _createRead(), binaryOperator, value);
     return _makeInvalidWrite(binary);
   }
 
   @override
   Expression buildPostfixIncrement(Name binaryOperator,
-      {int offset = TreeNode.noOffset,
-      bool voidContext = false,
-      Procedure interfaceTarget}) {
+      {int offset = TreeNode.noOffset, bool voidContext = false}) {
     Expression value = _forest.createIntLiteral(offset, 1);
     return buildCompoundAssignment(binaryOperator, value,
-        offset: offset,
-        voidContext: voidContext,
-        interfaceTarget: interfaceTarget,
-        isPostIncDec: true);
+        offset: offset, voidContext: voidContext, isPostIncDec: true);
   }
 
   @override
@@ -3113,10 +3155,13 @@
   }
 
   @override
-  Generator buildIndexedAccess(Expression index, Token token) {
+  Generator buildIndexedAccess(Expression index, Token token,
+      {bool isNullAware}) {
+    assert(isNullAware != null);
     // TODO(johnniwinther): The read-only quality of the variable should be
     // passed on to the generator.
-    return new IndexedAccessGenerator(_helper, token, _createRead(), index);
+    return new IndexedAccessGenerator(_helper, token, _createRead(), index,
+        isNullAware: isNullAware);
   }
 
   @override
@@ -3149,9 +3194,11 @@
   withReceiver(Object receiver, int operatorOffset, {bool isNullAware}) => this;
 
   @override
-  Initializer buildFieldInitializer(Map<String, int> initializedFields) {
-    return _helper.buildInvalidInitializer(
-        buildError(_forest.createArgumentsEmpty(fileOffset), isSetter: true));
+  List<Initializer> buildFieldInitializer(Map<String, int> initializedFields) {
+    return <Initializer>[
+      _helper.buildInvalidInitializer(
+          buildError(_forest.createArgumentsEmpty(fileOffset), isSetter: true))
+    ];
   }
 
   @override
@@ -3176,7 +3223,6 @@
   Expression buildCompoundAssignment(Name binaryOperator, Expression value,
       {int offset: -1,
       bool voidContext: false,
-      Procedure interfaceTarget,
       bool isPreIncDec: false,
       bool isPostIncDec: false}) {
     return buildError(_forest.createArguments(fileOffset, <Expression>[value]),
@@ -3185,7 +3231,7 @@
 
   @override
   Expression buildPrefixIncrement(Name binaryOperator,
-      {int offset: -1, bool voidContext: false, Procedure interfaceTarget}) {
+      {int offset: -1, bool voidContext: false}) {
     return buildError(
         _forest.createArguments(
             fileOffset, <Expression>[_forest.createIntLiteral(offset, 1)]),
@@ -3195,7 +3241,7 @@
 
   @override
   Expression buildPostfixIncrement(Name binaryOperator,
-      {int offset: -1, bool voidContext: false, Procedure interfaceTarget}) {
+      {int offset: -1, bool voidContext: false}) {
     return buildError(
         _forest.createArguments(
             fileOffset, <Expression>[_forest.createIntLiteral(offset, 1)]),
@@ -3243,8 +3289,11 @@
   }
 
   @override
-  Generator buildIndexedAccess(Expression index, Token token) {
-    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index);
+  Generator buildIndexedAccess(Expression index, Token token,
+      {bool isNullAware}) {
+    assert(isNullAware != null);
+    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index,
+        isNullAware: isNullAware);
   }
 }
 
@@ -3295,7 +3344,6 @@
   Expression buildCompoundAssignment(Name binaryOperator, Expression value,
       {int offset: TreeNode.noOffset,
       bool voidContext: false,
-      Procedure interfaceTarget,
       bool isPreIncDec: false,
       bool isPostIncDec: false}) {
     return _buildUnresolvedVariableAssignment(true, value);
@@ -3320,8 +3368,11 @@
   }
 
   @override
-  Generator buildIndexedAccess(Expression index, Token token) {
-    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index);
+  Generator buildIndexedAccess(Expression index, Token token,
+      {bool isNullAware}) {
+    assert(isNullAware != null);
+    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index,
+        isNullAware: isNullAware);
   }
 }
 
@@ -3357,7 +3408,6 @@
   Expression buildCompoundAssignment(Name binaryOperator, Expression value,
       {int offset: -1,
       bool voidContext: false,
-      Procedure interfaceTarget,
       bool isPreIncDec: false,
       bool isPostIncDec: false}) {
     return _makeInvalidWrite(value);
@@ -3365,13 +3415,13 @@
 
   @override
   Expression buildPrefixIncrement(Name binaryOperator,
-      {int offset: -1, bool voidContext: false, Procedure interfaceTarget}) {
+      {int offset: -1, bool voidContext: false}) {
     return _makeInvalidWrite(null);
   }
 
   @override
   Expression buildPostfixIncrement(Name binaryOperator,
-      {int offset: -1, bool voidContext: false, Procedure interfaceTarget}) {
+      {int offset: -1, bool voidContext: false}) {
     return _makeInvalidWrite(null);
   }
 
@@ -3387,8 +3437,11 @@
   }
 
   @override
-  Generator buildIndexedAccess(Expression index, Token token) {
-    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index);
+  Generator buildIndexedAccess(Expression index, Token token,
+      {bool isNullAware}) {
+    assert(isNullAware != null);
+    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index,
+        isNullAware: isNullAware);
   }
 }
 
@@ -3468,7 +3521,7 @@
   }
 
   @override
-  Initializer buildFieldInitializer(Map<String, int> initializedFields) {
+  List<Initializer> buildFieldInitializer(Map<String, int> initializedFields) {
     if (!identical("=", assignmentOperator) ||
         generator is! ThisPropertyAccessGenerator) {
       return generator.buildFieldInitializer(initializedFields);
@@ -3489,10 +3542,8 @@
 class DelayedPostfixIncrement extends ContextAwareGenerator {
   final Name binaryOperator;
 
-  final Procedure interfaceTarget;
-
   DelayedPostfixIncrement(ExpressionGeneratorHelper helper, Token token,
-      Generator generator, this.binaryOperator, this.interfaceTarget)
+      Generator generator, this.binaryOperator)
       : super(helper, token, generator);
 
   @override
@@ -3501,25 +3552,19 @@
   @override
   Expression buildSimpleRead() {
     return generator.buildPostfixIncrement(binaryOperator,
-        offset: fileOffset,
-        voidContext: false,
-        interfaceTarget: interfaceTarget);
+        offset: fileOffset, voidContext: false);
   }
 
   @override
   Expression buildForEffect() {
     return generator.buildPostfixIncrement(binaryOperator,
-        offset: fileOffset,
-        voidContext: true,
-        interfaceTarget: interfaceTarget);
+        offset: fileOffset, voidContext: true);
   }
 
   @override
   void printOn(StringSink sink) {
     sink.write(", binaryOperator: ");
     sink.write(binaryOperator.name);
-    sink.write(", interfaceTarget: ");
-    printQualifiedNameOn(interfaceTarget, sink);
   }
 }
 
@@ -3553,7 +3598,6 @@
   Expression buildCompoundAssignment(Name binaryOperator, Expression value,
       {int offset: TreeNode.noOffset,
       bool voidContext: false,
-      Procedure interfaceTarget,
       bool isPreIncDec: false,
       bool isPostIncDec: false}) {
     return _makeInvalidRead();
@@ -3561,9 +3605,7 @@
 
   @override
   Expression buildPostfixIncrement(Name binaryOperator,
-      {int offset: TreeNode.noOffset,
-      bool voidContext: false,
-      Procedure interfaceTarget}) {
+      {int offset: TreeNode.noOffset, bool voidContext: false}) {
     return _makeInvalidRead();
   }
 
@@ -3631,8 +3673,11 @@
   Expression _makeInvalidWrite(Expression value) => _makeInvalidRead();
 
   @override
-  Generator buildIndexedAccess(Expression index, Token token) {
-    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index);
+  Generator buildIndexedAccess(Expression index, Token token,
+      {bool isNullAware}) {
+    assert(isNullAware != null);
+    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index,
+        isNullAware: isNullAware);
   }
 
   @override
@@ -3678,7 +3723,6 @@
   Expression buildCompoundAssignment(Name binaryOperator, Expression value,
       {int offset: TreeNode.noOffset,
       bool voidContext: false,
-      Procedure interfaceTarget,
       bool isPreIncDec: false,
       bool isPostIncDec: false}) {
     return _makeInvalidRead();
@@ -3686,9 +3730,7 @@
 
   @override
   Expression buildPostfixIncrement(Name binaryOperator,
-      {int offset = TreeNode.noOffset,
-      bool voidContext = false,
-      Procedure interfaceTarget}) {
+      {int offset = TreeNode.noOffset, bool voidContext = false}) {
     return _makeInvalidRead();
   }
 
@@ -3721,8 +3763,11 @@
   }
 
   @override
-  Generator buildIndexedAccess(Expression index, Token token) {
-    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index);
+  Generator buildIndexedAccess(Expression index, Token token,
+      {bool isNullAware}) {
+    assert(isNullAware != null);
+    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index,
+        isNullAware: isNullAware);
   }
 
   @override
@@ -3767,23 +3812,18 @@
   Expression buildCompoundAssignment(Name binaryOperator, Expression value,
       {int offset: TreeNode.noOffset,
       bool voidContext: false,
-      Procedure interfaceTarget,
       bool isPreIncDec: false,
       bool isPostIncDec: false}) {
     return buildProblem();
   }
 
   Expression buildPrefixIncrement(Name binaryOperator,
-      {int offset: TreeNode.noOffset,
-      bool voidContext: false,
-      Procedure interfaceTarget}) {
+      {int offset: TreeNode.noOffset, bool voidContext: false}) {
     return buildProblem();
   }
 
   Expression buildPostfixIncrement(Name binaryOperator,
-      {int offset: TreeNode.noOffset,
-      bool voidContext: false,
-      Procedure interfaceTarget}) {
+      {int offset: TreeNode.noOffset, bool voidContext: false}) {
     return buildProblem();
   }
 
@@ -3791,8 +3831,8 @@
 
   Expression _makeInvalidWrite(Expression value) => buildProblem();
 
-  Initializer buildFieldInitializer(Map<String, int> initializedFields) {
-    return _helper.buildInvalidInitializer(buildProblem());
+  List<Initializer> buildFieldInitializer(Map<String, int> initializedFields) {
+    return <Initializer>[_helper.buildInvalidInitializer(buildProblem())];
   }
 
   Expression doInvocation(int offset, Arguments arguments) {
@@ -3829,8 +3869,11 @@
   }
 
   @override
-  Generator buildIndexedAccess(Expression index, Token token) {
-    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index);
+  Generator buildIndexedAccess(Expression index, Token token,
+      {bool isNullAware}) {
+    assert(isNullAware != null);
+    return new IndexedAccessGenerator(_helper, token, buildSimpleRead(), index,
+        isNullAware: isNullAware);
   }
 }
 
@@ -3928,9 +3971,11 @@
   }
 
   @override
-  Initializer buildFieldInitializer(Map<String, int> initializedFields) {
+  List<Initializer> buildFieldInitializer(Map<String, int> initializedFields) {
     Expression error = buildFieldInitializerError(initializedFields);
-    return _helper.buildInvalidInitializer(error, error.fileOffset);
+    return <Initializer>[
+      _helper.buildInvalidInitializer(error, error.fileOffset)
+    ];
   }
 
   buildPropertyAccess(
@@ -4089,28 +4134,25 @@
   Expression buildCompoundAssignment(Name binaryOperator, Expression value,
       {int offset: TreeNode.noOffset,
       bool voidContext: false,
-      Procedure interfaceTarget,
       bool isPreIncDec: false,
       bool isPostIncDec: false}) {
     return buildAssignmentError();
   }
 
   Expression buildPrefixIncrement(Name binaryOperator,
-      {int offset: TreeNode.noOffset,
-      bool voidContext: false,
-      Procedure interfaceTarget}) {
+      {int offset: TreeNode.noOffset, bool voidContext: false}) {
     return buildAssignmentError();
   }
 
   Expression buildPostfixIncrement(Name binaryOperator,
-      {int offset: TreeNode.noOffset,
-      bool voidContext: false,
-      Procedure interfaceTarget}) {
+      {int offset: TreeNode.noOffset, bool voidContext: false}) {
     return buildAssignmentError();
   }
 
   @override
-  Generator buildIndexedAccess(Expression index, Token token) {
+  Generator buildIndexedAccess(Expression index, Token token,
+      {bool isNullAware}) {
+    assert(isNullAware != null);
     if (isSuper) {
       return new SuperIndexedAccessGenerator(
           _helper,
@@ -4238,23 +4280,18 @@
   Expression buildCompoundAssignment(Name binaryOperator, Expression value,
       {int offset: TreeNode.noOffset,
       bool voidContext: false,
-      Procedure interfaceTarget,
       bool isPreIncDec: false,
       bool isPostIncDec: false}) {
     return unsupported("buildCompoundAssignment", offset ?? fileOffset, _uri);
   }
 
   Expression buildPrefixIncrement(Name binaryOperator,
-      {int offset: TreeNode.noOffset,
-      bool voidContext: false,
-      Procedure interfaceTarget}) {
+      {int offset: TreeNode.noOffset, bool voidContext: false}) {
     return unsupported("buildPrefixIncrement", offset ?? fileOffset, _uri);
   }
 
   Expression buildPostfixIncrement(Name binaryOperator,
-      {int offset: TreeNode.noOffset,
-      bool voidContext: false,
-      Procedure interfaceTarget}) {
+      {int offset: TreeNode.noOffset, bool voidContext: false}) {
     return unsupported("buildPostfixIncrement", offset ?? fileOffset, _uri);
   }
 
@@ -4263,7 +4300,9 @@
   }
 
   @override
-  Generator buildIndexedAccess(Expression index, Token token) {
+  Generator buildIndexedAccess(Expression index, Token token,
+      {bool isNullAware}) {
+    assert(isNullAware != null);
     return unsupported("buildIndexedAccess", offsetForToken(token), _uri);
   }
 
@@ -4317,23 +4356,18 @@
   Expression buildCompoundAssignment(Name binaryOperator, Expression value,
       {int offset: TreeNode.noOffset,
       bool voidContext: false,
-      Procedure interfaceTarget,
       bool isPreIncDec: false,
       bool isPostIncDec: false}) {
     return unsupported("buildCompoundAssignment", offset ?? fileOffset, _uri);
   }
 
   Expression buildPrefixIncrement(Name binaryOperator,
-      {int offset: TreeNode.noOffset,
-      bool voidContext: false,
-      Procedure interfaceTarget}) {
+      {int offset: TreeNode.noOffset, bool voidContext: false}) {
     return unsupported("buildPrefixIncrement", offset ?? fileOffset, _uri);
   }
 
   Expression buildPostfixIncrement(Name binaryOperator,
-      {int offset: TreeNode.noOffset,
-      bool voidContext: false,
-      Procedure interfaceTarget}) {
+      {int offset: TreeNode.noOffset, bool voidContext: false}) {
     return unsupported("buildPostfixIncrement", offset ?? fileOffset, _uri);
   }
 
@@ -4342,7 +4376,9 @@
   }
 
   @override
-  Generator buildIndexedAccess(Expression index, Token token) {
+  Generator buildIndexedAccess(Expression index, Token token,
+      {bool isNullAware}) {
+    assert(isNullAware != null);
     return unsupported("buildIndexedAccess", offsetForToken(token), _uri);
   }
 
@@ -4406,33 +4442,6 @@
   }
 }
 
-Expression makeLet(VariableDeclaration variable, Expression body) {
-  if (variable == null) return body;
-  return new Let(variable, body);
-}
-
-Expression makeBinary(Expression left, Name operator, Procedure interfaceTarget,
-    Expression right, ExpressionGeneratorHelper helper,
-    {int offset: TreeNode.noOffset}) {
-  return new MethodInvocationImpl(left, operator,
-      helper.forest.createArguments(offset, <Expression>[right]),
-      interfaceTarget: interfaceTarget)
-    ..fileOffset = offset;
-}
-
-Expression buildIsNull(
-    Expression value, int offset, ExpressionGeneratorHelper helper) {
-  return makeBinary(
-      value, equalsName, null, helper.forest.createNullLiteral(offset), helper,
-      offset: offset);
-}
-
-VariableDeclaration makeOrReuseVariable(Expression value) {
-  // TODO: Devise a way to remember if a variable declaration was reused
-  // or is fresh (hence needs a let binding).
-  return new VariableDeclaration.forValue(value);
-}
-
 int adjustForImplicitCall(String name, int offset) {
   // Normally the offset is at the start of the token, but in this case,
   // because we insert a '.call', we want it at the end instead.
diff --git a/pkg/front_end/lib/src/fasta/kernel/expression_generator_helper.dart b/pkg/front_end/lib/src/fasta/kernel/expression_generator_helper.dart
index 9930e0b..c83a89b 100644
--- a/pkg/front_end/lib/src/fasta/kernel/expression_generator_helper.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/expression_generator_helper.dart
@@ -63,7 +63,7 @@
 
   Initializer buildInvalidInitializer(Expression expression, [int offset]);
 
-  Initializer buildFieldInitializer(bool isSynthetic, String name,
+  List<Initializer> buildFieldInitializer(bool isSynthetic, String name,
       int fieldNameOffset, int assignmentOffset, Expression expression,
       {DartType formalType});
 
diff --git a/pkg/front_end/lib/src/fasta/kernel/forest.dart b/pkg/front_end/lib/src/fasta/kernel/forest.dart
index 0b0b77f..391ea59 100644
--- a/pkg/front_end/lib/src/fasta/kernel/forest.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/forest.dart
@@ -22,7 +22,7 @@
         IfMapEntry,
         SpreadElement;
 
-import 'kernel_shadow_ast.dart';
+import 'internal_ast.dart';
 
 /// A shadow tree factory.
 class Forest {
@@ -607,8 +607,15 @@
     return new TypeParameter(name);
   }
 
-  TypeParameterType createTypeParameterType(TypeParameter typeParameter) {
-    return new TypeParameterType(typeParameter, Nullability.legacy);
+  TypeParameterType createTypeParameterType(
+      TypeParameter typeParameter, Nullability nullability) {
+    return new TypeParameterType(typeParameter, nullability);
+  }
+
+  TypeParameterType createTypeParameterTypeWithDefaultNullabilityForLibrary(
+      TypeParameter typeParameter, Library library) {
+    return new TypeParameterType.withDefaultNullabilityForLibrary(
+        typeParameter, library);
   }
 
   FunctionExpression createFunctionExpression(
@@ -676,6 +683,23 @@
       ..fileOffset = fileOffset;
   }
 
+  IndexGet createIndexGet(
+      int fileOffset, Expression receiver, Expression index) {
+    assert(fileOffset != null);
+    return new IndexGet(receiver, index)..fileOffset = fileOffset;
+  }
+
+  IndexSet createIndexSet(
+      int fileOffset, Expression receiver, Expression index, Expression value,
+      {bool forEffect, bool readOnlyReceiver}) {
+    assert(fileOffset != null);
+    assert(forEffect != null);
+    assert(readOnlyReceiver != null);
+    return new IndexSet(receiver, index, value,
+        forEffect: forEffect, readOnlyReceiver: readOnlyReceiver)
+      ..fileOffset = fileOffset;
+  }
+
   EqualsExpression createEquals(
       int fileOffset, Expression left, Expression right,
       {bool isNot}) {
diff --git a/pkg/front_end/lib/src/fasta/kernel/forwarding_node.dart b/pkg/front_end/lib/src/fasta/kernel/forwarding_node.dart
index 958b6c0..4e1e2a5 100644
--- a/pkg/front_end/lib/src/fasta/kernel/forwarding_node.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/forwarding_node.dart
@@ -13,7 +13,6 @@
         Member,
         Name,
         NamedExpression,
-        Nullability,
         Procedure,
         ProcedureKind,
         ReturnStatement,
@@ -272,7 +271,8 @@
         .toList();
     List<DartType> typeArguments = function.typeParameters
         .map<DartType>((typeParameter) =>
-            new TypeParameterType(typeParameter, Nullability.legacy))
+            new TypeParameterType.withDefaultNullabilityForLibrary(
+                typeParameter, enclosingClass.enclosingLibrary))
         .toList();
     Arguments arguments = new Arguments(positionalArguments,
         types: typeArguments, named: namedArguments);
@@ -322,7 +322,8 @@
           ..isGenericCovariantImpl = targetTypeParameter.isGenericCovariantImpl;
         typeParameters[i] = typeParameter;
         additionalSubstitution[targetTypeParameter] =
-            new TypeParameterType(typeParameter, Nullability.legacy);
+            new TypeParameterType.forAlphaRenaming(
+                targetTypeParameter, typeParameter);
       }
       substitution = Substitution.combine(
           substitution, Substitution.fromMap(additionalSubstitution));
@@ -381,7 +382,9 @@
 
   Substitution _substitutionFor(Member candidate, Class class_) {
     return Substitution.fromInterfaceType(hierarchy.getKernelTypeAsInstanceOf(
-        class_.thisType, candidate.enclosingClass));
+        hierarchy.coreTypes
+            .thisInterfaceType(class_, class_.enclosingLibrary.nonNullable),
+        candidate.enclosingClass));
   }
 
   List<VariableDeclaration> getPositionalParameters(Member member) {
diff --git a/pkg/front_end/lib/src/fasta/kernel/implicit_field_type.dart b/pkg/front_end/lib/src/fasta/kernel/implicit_field_type.dart
index edd980c..8070c5d 100644
--- a/pkg/front_end/lib/src/fasta/kernel/implicit_field_type.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/implicit_field_type.dart
@@ -9,37 +9,96 @@
 import 'package:kernel/ast.dart'
     show DartType, DartTypeVisitor, DartTypeVisitor1, Nullability, Visitor;
 
-import '../builder/member_builder.dart';
+import '../builder/field_builder.dart';
 
 import '../problems.dart' show unsupported;
 
-class ImplicitFieldType extends DartType {
-  final MemberBuilder memberBuilder;
+abstract class ImplicitFieldType extends DartType {
+  SourceFieldBuilder get fieldBuilder;
+  Token get initializerToken;
+  void set initializerToken(Token value);
+  bool get isStarted;
+  void set isStarted(bool value);
+
+  ImplicitFieldType._();
+
+  factory ImplicitFieldType(
+          SourceFieldBuilder fieldBuilder, Token initializerToken) =
+      _ImplicitFieldTypeRoot;
+
+  @override
+  Nullability get nullability =>
+      unsupported("nullability", fieldBuilder.charOffset, fieldBuilder.fileUri);
+
+  @override
+  R accept<R>(DartTypeVisitor<R> v) {
+    throw unsupported("accept", fieldBuilder.charOffset, fieldBuilder.fileUri);
+  }
+
+  @override
+  R accept1<R, A>(DartTypeVisitor1<R, A> v, arg) {
+    throw unsupported("accept1", fieldBuilder.charOffset, fieldBuilder.fileUri);
+  }
+
+  @override
+  visitChildren(Visitor<Object> v) {
+    unsupported("visitChildren", fieldBuilder.charOffset, fieldBuilder.fileUri);
+  }
+
+  @override
+  ImplicitFieldType withNullability(Nullability nullability) {
+    return unsupported(
+        "withNullability", fieldBuilder.charOffset, fieldBuilder.fileUri);
+  }
+
+  ImplicitFieldType createAlias(SourceFieldBuilder target) =>
+      new _ImplicitFieldTypeAlias(this, target);
+
+  @override
+  bool operator ==(Object other) {
+    if (identical(this, other)) return true;
+    return other is ImplicitFieldType && fieldBuilder == other.fieldBuilder;
+  }
+
+  @override
+  int get hashCode => fieldBuilder.hashCode;
+
+  DartType inferType();
+}
+
+class _ImplicitFieldTypeRoot extends ImplicitFieldType {
+  final SourceFieldBuilder fieldBuilder;
   Token initializerToken;
   bool isStarted = false;
 
-  ImplicitFieldType(this.memberBuilder, this.initializerToken);
+  _ImplicitFieldTypeRoot(this.fieldBuilder, this.initializerToken) : super._();
 
-  Nullability get nullability => unsupported(
-      "nullability", memberBuilder.charOffset, memberBuilder.fileUri);
+  DartType inferType() => fieldBuilder.inferType();
+}
 
-  R accept<R>(DartTypeVisitor<R> v) {
-    throw unsupported(
-        "accept", memberBuilder.charOffset, memberBuilder.fileUri);
+class _ImplicitFieldTypeAlias extends ImplicitFieldType {
+  final ImplicitFieldType _root;
+  final SourceFieldBuilder _targetFieldBuilder;
+
+  _ImplicitFieldTypeAlias(this._root, this._targetFieldBuilder)
+      : assert(_root.fieldBuilder != _targetFieldBuilder),
+        super._();
+
+  SourceFieldBuilder get fieldBuilder => _root.fieldBuilder;
+
+  Token get initializerToken => _root.initializerToken;
+
+  void set initializerToken(Token value) {
+    _root.initializerToken = value;
   }
 
-  R accept1<R, A>(DartTypeVisitor1<R, A> v, arg) {
-    throw unsupported(
-        "accept1", memberBuilder.charOffset, memberBuilder.fileUri);
+  bool get isStarted => _root.isStarted;
+
+  void set isStarted(bool value) {
+    _root.isStarted = value;
   }
 
-  visitChildren(Visitor<Object> v) {
-    unsupported(
-        "visitChildren", memberBuilder.charOffset, memberBuilder.fileUri);
-  }
-
-  ImplicitFieldType withNullability(Nullability nullability) {
-    return unsupported(
-        "withNullability", memberBuilder.charOffset, memberBuilder.fileUri);
+  DartType inferType() {
+    return _targetFieldBuilder.fieldType = _root.inferType();
   }
 }
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 f1f9283..26597c3 100644
--- a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
@@ -2,12 +2,78 @@
 // 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 "kernel_shadow_ast.dart";
+import 'dart:core' hide MapEntry;
+
+import 'package:kernel/ast.dart';
+
+import 'package:kernel/type_algebra.dart' show Substitution;
+
+import 'package:kernel/type_environment.dart';
+
+import '../../base/instrumentation.dart'
+    show
+        InstrumentationValueForMember,
+        InstrumentationValueForType,
+        InstrumentationValueForTypeArgs;
+
+import '../builder/library_builder.dart';
+
+import '../fasta_codes.dart'
+    show
+        messageCantDisambiguateAmbiguousInformation,
+        messageCantDisambiguateNotEnoughInformation,
+        messageNonNullAwareSpreadIsNull,
+        messageSwitchExpressionNotAssignableCause,
+        noLength,
+        templateCantInferTypeDueToCircularity,
+        templateForInLoopElementTypeNotAssignable,
+        templateForInLoopTypeNotIterable,
+        templateIntegerLiteralIsOutOfRange,
+        templateSpreadElementTypeMismatch,
+        templateSpreadMapEntryElementKeyTypeMismatch,
+        templateSpreadMapEntryElementValueTypeMismatch,
+        templateSpreadMapEntryTypeMismatch,
+        templateSpreadTypeMismatch,
+        templateSwitchExpressionNotAssignable,
+        templateUndefinedSetter;
+
+import '../names.dart';
+
+import '../problems.dart' show unhandled;
+
+import '../source/source_library_builder.dart' show SourceLibraryBuilder;
+
+import '../type_inference/type_inference_engine.dart';
+import '../type_inference/type_inferrer.dart';
+
+import '../type_inference/type_schema.dart' show UnknownType;
+
+import '../type_inference/type_schema_elimination.dart' show greatestClosure;
+
+import 'body_builder.dart' show combineStatements;
+
+import 'collections.dart'
+    show
+        ForElement,
+        ForInElement,
+        ForInMapEntry,
+        ForMapEntry,
+        IfElement,
+        IfMapEntry,
+        SpreadElement,
+        SpreadMapEntry,
+        convertToElement;
+
+import 'implicit_type_argument.dart' show ImplicitTypeArgument;
+
+import 'internal_ast.dart';
+
+import 'late_lowering.dart' as late_lowering;
 
 class InferenceVisitor
     implements
         ExpressionVisitor1<ExpressionInferenceResult, DartType>,
-        StatementVisitor<void>,
+        StatementVisitor<StatementInferenceResult>,
         InitializerVisitor<void> {
   final TypeInferrerImpl inferrer;
 
@@ -27,6 +93,20 @@
 
   InferenceVisitor(this.inferrer);
 
+  Expression _clone(Expression node) {
+    if (node is ThisExpression) {
+      return new ThisExpression()..fileOffset = node.fileOffset;
+    } else if (node is VariableGet) {
+      assert(
+          node.variable.isFinal,
+          "Trying to clone VariableGet of non-final variable"
+          " ${node.variable}.");
+      return new VariableGet(node.variable, node.promotedType)
+        ..fileOffset = node.fileOffset;
+    }
+    throw new UnsupportedError("Clone not supported for ${node.runtimeType}.");
+  }
+
   ExpressionInferenceResult _unhandledExpression(
       Expression node, DartType typeContext) {
     unhandled("${node.runtimeType}", "InferenceVisitor", node.fileOffset,
@@ -112,19 +192,19 @@
     return _unhandledExpression(node, typeContext);
   }
 
-  void _unhandledStatement(Statement node) {
-    unhandled("${node.runtimeType}", "InferenceVisitor", node.fileOffset,
+  StatementInferenceResult _unhandledStatement(Statement node) {
+    return unhandled("${node.runtimeType}", "InferenceVisitor", node.fileOffset,
         inferrer.helper.uri);
   }
 
   @override
-  void defaultStatement(Statement node) {
-    _unhandledStatement(node);
+  StatementInferenceResult defaultStatement(Statement node) {
+    return _unhandledStatement(node);
   }
 
   @override
-  void visitAssertBlock(AssertBlock node) {
-    _unhandledStatement(node);
+  StatementInferenceResult visitAssertBlock(AssertBlock node) {
+    return _unhandledStatement(node);
   }
 
   void _unhandledInitializer(Initializer node) {
@@ -175,11 +255,14 @@
 
   @override
   void visitAssertInitializer(AssertInitializer node) {
-    inferrer.inferStatement(node.statement);
+    StatementInferenceResult result = inferrer.inferStatement(node.statement);
+    if (result.hasChanged) {
+      node.statement = result.statement..parent = node;
+    }
   }
 
   @override
-  void visitAssertStatement(AssertStatement node) {
+  StatementInferenceResult visitAssertStatement(AssertStatement node) {
     inferrer.flowAnalysis.assert_begin();
     InterfaceType expectedType =
         inferrer.coreTypes.boolRawType(inferrer.library.nonNullable);
@@ -198,6 +281,7 @@
       node.message = messageResult.expression..parent = node;
     }
     inferrer.flowAnalysis.assert_end();
+    return const StatementInferenceResult();
   }
 
   @override
@@ -214,12 +298,37 @@
     return new ExpressionInferenceResult(inferredType, node);
   }
 
-  @override
-  void visitBlock(Block node) {
-    inferrer.registerIfUnreachableForTesting(node);
-    for (Statement statement in node.statements) {
-      inferrer.inferStatement(statement);
+  List<Statement> _visitStatements<T extends Statement>(List<T> statements) {
+    List<Statement> result;
+    for (int index = 0; index < statements.length; index++) {
+      T statement = statements[index];
+      StatementInferenceResult statementResult =
+          inferrer.inferStatement(statement);
+      if (statementResult.hasChanged) {
+        if (result == null) {
+          result = <T>[];
+          result.addAll(statements.sublist(0, index));
+        }
+        if (statementResult.statementCount == 1) {
+          result.add(statementResult.statement);
+        } else {
+          result.addAll(statementResult.statements);
+        }
+      } else if (result != null) {
+        result.add(statement);
+      }
     }
+    return result;
+  }
+
+  @override
+  StatementInferenceResult visitBlock(Block node) {
+    inferrer.registerIfUnreachableForTesting(node);
+    List<Statement> result = _visitStatements<Statement>(node.statements);
+    return result != null
+        ? new StatementInferenceResult.single(
+            new Block(result)..fileOffset = node.fileOffset)
+        : const StatementInferenceResult();
   }
 
   @override
@@ -231,9 +340,10 @@
   }
 
   @override
-  void visitBreakStatement(BreakStatement node) {
+  StatementInferenceResult visitBreakStatement(BreakStatement node) {
     // TODO(johnniwinther): Refactor break/continue encoding.
     inferrer.flowAnalysis.handleBreak(node.target);
+    return const StatementInferenceResult();
   }
 
   ExpressionInferenceResult visitCascade(Cascade node, DartType typeContext) {
@@ -255,8 +365,19 @@
           createVariable(expressionResults[index].expression, const VoidType()),
           replacement);
     }
-    replacement = new Let(node.variable, replacement)
-      ..fileOffset = node.fileOffset;
+
+    if (node.isNullAware) {
+      Member equalsMember = inferrer
+          .findInterfaceMember(result.inferredType, equalsName, node.fileOffset)
+          .member;
+      NullAwareGuard nullAwareGuard = new NullAwareGuard(
+          node.variable, node.variable.fileOffset, equalsMember);
+      replacement =
+          nullAwareGuard.createExpression(result.inferredType, replacement);
+    } else {
+      replacement = new Let(node.variable, replacement)
+        ..fileOffset = node.fileOffset;
+    }
     return new ExpressionInferenceResult(result.inferredType, replacement);
   }
 
@@ -339,7 +460,8 @@
         getExplicitTypeArguments(node.arguments) != null;
     DartType inferredType = inferrer.inferInvocation(typeContext,
         node.fileOffset, node.target.function.thisFunctionType, node.arguments,
-        returnType: computeConstructorReturnType(node.target),
+        returnType:
+            computeConstructorReturnType(node.target, inferrer.coreTypes),
         isConst: node.isConst);
     if (!inferrer.isTopLevel) {
       SourceLibraryBuilder library = inferrer.library;
@@ -353,15 +475,18 @@
   }
 
   @override
-  void visitContinueSwitchStatement(ContinueSwitchStatement node) {
+  StatementInferenceResult visitContinueSwitchStatement(
+      ContinueSwitchStatement node) {
     // No inference needs to be done.
+    return const StatementInferenceResult();
   }
 
   ExpressionInferenceResult visitExtensionTearOff(
       ExtensionTearOff node, DartType typeContext) {
     FunctionType calleeType = node.target != null
         ? node.target.function.functionType
-        : new FunctionType([], const DynamicType(), Nullability.legacy);
+        : new FunctionType(
+            [], const DynamicType(), inferrer.library.nonNullable);
     TypeArgumentsInfo typeArgumentsInfo = getTypeArgumentsInfo(node.arguments);
     DartType inferredType = inferrer.inferInvocation(
         typeContext, node.fileOffset, calleeType, node.arguments);
@@ -465,7 +590,7 @@
     Expression writeReceiver;
     if (node.readOnlyReceiver && identical(receiver, node.receiver)) {
       readReceiver = receiver;
-      writeReceiver = receiver.accept<TreeNode>(new CloneVisitor());
+      writeReceiver = _clone(receiver);
     } else {
       receiverVariable = createVariable(receiver, receiverType);
       readReceiver = createVariableGet(receiverVariable);
@@ -565,9 +690,12 @@
   }
 
   @override
-  void visitDoStatement(DoStatement node) {
+  StatementInferenceResult visitDoStatement(DoStatement node) {
     inferrer.flowAnalysis.doStatement_bodyBegin(node);
-    inferrer.inferStatement(node.body);
+    StatementInferenceResult bodyResult = inferrer.inferStatement(node.body);
+    if (bodyResult.hasChanged) {
+      node.body = bodyResult.statement..parent = node;
+    }
     inferrer.flowAnalysis.doStatement_conditionBegin();
     InterfaceType boolType =
         inferrer.coreTypes.boolRawType(inferrer.library.nonNullable);
@@ -578,6 +706,7 @@
         inferrer.ensureAssignableResult(boolType, conditionResult);
     node.condition = condition..parent = node;
     inferrer.flowAnalysis.doStatement_end(condition);
+    return const StatementInferenceResult();
   }
 
   ExpressionInferenceResult visitDoubleLiteral(
@@ -587,16 +716,18 @@
   }
 
   @override
-  void visitEmptyStatement(EmptyStatement node) {
+  StatementInferenceResult visitEmptyStatement(EmptyStatement node) {
     // No inference needs to be done.
+    return const StatementInferenceResult();
   }
 
   @override
-  void visitExpressionStatement(ExpressionStatement node) {
+  StatementInferenceResult visitExpressionStatement(ExpressionStatement node) {
     ExpressionInferenceResult result = inferrer.inferExpression(
         node.expression, const UnknownType(), !inferrer.isTopLevel,
         isVoidAllowed: true);
     node.expression = result.expression..parent = node;
+    return const StatementInferenceResult();
   }
 
   ExpressionInferenceResult visitFactoryConstructorInvocationJudgment(
@@ -605,7 +736,8 @@
         getExplicitTypeArguments(node.arguments) != null;
     DartType inferredType = inferrer.inferInvocation(typeContext,
         node.fileOffset, node.target.function.thisFunctionType, node.arguments,
-        returnType: computeConstructorReturnType(node.target),
+        returnType:
+            computeConstructorReturnType(node.target, inferrer.coreTypes),
         isConst: node.isConst);
     node.hasBeenInferred = true;
     if (!inferrer.isTopLevel) {
@@ -635,7 +767,7 @@
     DartType elementType;
     bool typeNeeded = false;
     bool typeChecksNeeded = !inferrer.isTopLevel;
-    if (VariableDeclarationImpl.isImplicitlyTyped(variable)) {
+    if (variable is VariableDeclarationImpl && variable.isImplicitlyTyped) {
       typeNeeded = true;
       elementType = const UnknownType();
     } else {
@@ -658,7 +790,10 @@
     if (body != null) {
       inferrer.flowAnalysis
           .forEach_bodyBegin(body?.parent, variable, variable.type);
-      inferrer.inferStatement(body);
+      StatementInferenceResult bodyResult = inferrer.inferStatement(body);
+      if (bodyResult.hasChanged) {
+        body = bodyResult.statement;
+      }
       inferrer.flowAnalysis.forEach_end();
     }
 
@@ -693,7 +828,8 @@
     Class iterableClass = isAsync
         ? inferrer.coreTypes.streamClass
         : inferrer.coreTypes.iterableClass;
-    DartType context = inferrer.wrapType(elementType, iterableClass);
+    DartType context = inferrer.wrapType(
+        elementType, iterableClass, inferrer.library.nonNullable);
     ExpressionInferenceResult iterableResult = inferrer
         .inferExpression(iterable, context, typeNeeded, isVoidAllowed: false);
     DartType iterableType = iterableResult.inferredType;
@@ -701,7 +837,8 @@
     DartType inferredExpressionType =
         inferrer.resolveTypeParameter(iterableType);
     iterable = inferrer.ensureAssignable(
-        inferrer.wrapType(const DynamicType(), iterableClass),
+        inferrer.wrapType(
+            const DynamicType(), iterableClass, inferrer.library.nonNullable),
         inferredExpressionType,
         iterable,
         template: templateForInLoopTypeNotIterable);
@@ -823,14 +960,37 @@
     inferrer.flowAnalysis
         .forEach_bodyBegin(body.parent, variable, variable.type);
     if (body is Block) {
-      for (Statement statement in body.statements) {
+      Block block = body;
+      List<Statement> result;
+      for (int index = 0; index < block.statements.length; index++) {
+        Statement statement = block.statements[index];
         if (!skipStatement || statement != syntheticStatement) {
-          inferrer.inferStatement(statement);
+          StatementInferenceResult statementResult =
+              inferrer.inferStatement(statement);
+          if (statementResult.hasChanged) {
+            if (result == null) {
+              result = <Statement>[];
+              result.addAll(block.statements.sublist(0, index));
+            }
+            if (statementResult.statementCount == 1) {
+              result.add(statementResult.statement);
+            } else {
+              result.addAll(statementResult.statements);
+            }
+          }
+        } else if (result != null) {
+          result.add(statement);
         }
       }
+      if (result != null) {
+        body = new Block(result)..fileOffset = body.fileOffset;
+      }
     } else {
       if (!skipStatement) {
-        inferrer.inferStatement(body);
+        StatementInferenceResult bodyResult = inferrer.inferStatement(body);
+        if (bodyResult.hasChanged) {
+          body = bodyResult.statement;
+        }
       }
     }
     inferrer.flowAnalysis.forEach_end();
@@ -857,7 +1017,7 @@
   }
 
   @override
-  void visitForInStatement(ForInStatement node) {
+  StatementInferenceResult visitForInStatement(ForInStatement node) {
     ForInResult result;
     if (node.variable.name == null) {
       result = handleForInWithoutVariable(
@@ -871,11 +1031,14 @@
     node.variable = result.variable..parent = node;
     node.iterable = result.iterable..parent = node;
     node.body = result.body..parent = node;
+    return const StatementInferenceResult();
   }
 
   @override
-  void visitForStatement(ForStatement node) {
-    for (VariableDeclaration variable in node.variables) {
+  StatementInferenceResult visitForStatement(ForStatement node) {
+    List<VariableDeclaration> variables;
+    for (int index = 0; index < node.variables.length; index++) {
+      VariableDeclaration variable = node.variables[index];
       if (variable.name == null) {
         if (variable.initializer != null) {
           ExpressionInferenceResult result = inferrer.inferExpression(
@@ -885,9 +1048,30 @@
           variable.type = result.inferredType;
         }
       } else {
-        inferrer.inferStatement(variable);
+        StatementInferenceResult variableResult =
+            inferrer.inferStatement(variable);
+        if (variableResult.hasChanged) {
+          if (variables == null) {
+            variables = <VariableDeclaration>[];
+            variables.addAll(node.variables.sublist(0, index));
+          }
+          if (variableResult.statementCount == 1) {
+            variables.add(variableResult.statement);
+          } else {
+            for (VariableDeclaration variable in variableResult.statements) {
+              variables.add(variable);
+            }
+          }
+        } else if (variables != null) {
+          variables.add(variable);
+        }
       }
     }
+    if (variables != null) {
+      node.variables.clear();
+      node.variables.addAll(variables);
+      setParents(variables, node);
+    }
     inferrer.flowAnalysis.for_conditionBegin(node);
     if (node.condition != null) {
       InterfaceType expectedType =
@@ -901,7 +1085,10 @@
     }
 
     inferrer.flowAnalysis.for_bodyBegin(node.body, node.condition);
-    inferrer.inferStatement(node.body);
+    StatementInferenceResult bodyResult = inferrer.inferStatement(node.body);
+    if (bodyResult.hasChanged) {
+      node.body = bodyResult.statement..parent = node;
+    }
     inferrer.flowAnalysis.for_updaterBegin();
     for (int index = 0; index < node.updates.length; index++) {
       ExpressionInferenceResult updateResult = inferrer.inferExpression(
@@ -910,6 +1097,7 @@
       node.updates[index] = updateResult.expression..parent = node;
     }
     inferrer.flowAnalysis.for_end();
+    return const StatementInferenceResult();
   }
 
   DartType visitFunctionNode(FunctionNode node, DartType typeContext,
@@ -919,16 +1107,18 @@
   }
 
   @override
-  void visitFunctionDeclaration(covariant FunctionDeclarationImpl node) {
+  StatementInferenceResult visitFunctionDeclaration(
+      covariant FunctionDeclarationImpl node) {
     inferrer.flowAnalysis.functionExpression_begin(node);
     inferrer.inferMetadataKeepingHelper(
         node.variable, node.variable.annotations);
     DartType returnContext =
-        node._hasImplicitReturnType ? null : node.function.returnType;
+        node.hasImplicitReturnType ? null : node.function.returnType;
     DartType inferredType =
         visitFunctionNode(node.function, null, returnContext, node.fileOffset);
     node.variable.type = inferredType;
     inferrer.flowAnalysis.functionExpression_end();
+    return const StatementInferenceResult();
   }
 
   @override
@@ -1001,7 +1191,7 @@
   }
 
   @override
-  void visitIfStatement(IfStatement node) {
+  StatementInferenceResult visitIfStatement(IfStatement node) {
     InterfaceType expectedType =
         inferrer.coreTypes.boolRawType(inferrer.library.nonNullable);
     ExpressionInferenceResult conditionResult = inferrer.inferExpression(
@@ -1011,12 +1201,20 @@
         inferrer.ensureAssignableResult(expectedType, conditionResult);
     node.condition = condition..parent = node;
     inferrer.flowAnalysis.ifStatement_thenBegin(condition);
-    inferrer.inferStatement(node.then);
+    StatementInferenceResult thenResult = inferrer.inferStatement(node.then);
+    if (thenResult.hasChanged) {
+      node.then = thenResult.statement..parent = node;
+    }
     if (node.otherwise != null) {
       inferrer.flowAnalysis.ifStatement_elseBegin();
-      inferrer.inferStatement(node.otherwise);
+      StatementInferenceResult otherwiseResult =
+          inferrer.inferStatement(node.otherwise);
+      if (otherwiseResult.hasChanged) {
+        node.otherwise = otherwiseResult.statement..parent = node;
+      }
     }
     inferrer.flowAnalysis.ifStatement_end(node.otherwise != null);
+    return const StatementInferenceResult();
   }
 
   ExpressionInferenceResult visitIntJudgment(
@@ -1100,8 +1298,12 @@
   }
 
   @override
-  void visitLabeledStatement(LabeledStatement node) {
-    inferrer.inferStatement(node.body);
+  StatementInferenceResult visitLabeledStatement(LabeledStatement node) {
+    StatementInferenceResult bodyResult = inferrer.inferStatement(node.body);
+    if (bodyResult.hasChanged) {
+      node.body = bodyResult.statement..parent = node;
+    }
+    return const StatementInferenceResult();
   }
 
   DartType getSpreadElementType(DartType spreadType, bool isNullAware) {
@@ -1128,8 +1330,10 @@
     if (element is SpreadElement) {
       ExpressionInferenceResult spreadResult = inferrer.inferExpression(
           element.expression,
-          new InterfaceType(inferrer.coreTypes.iterableClass,
-              Nullability.legacy, <DartType>[inferredTypeArgument]),
+          new InterfaceType(
+              inferrer.coreTypes.iterableClass,
+              inferrer.library.nullableIfTrue(element.isNullAware),
+              <DartType>[inferredTypeArgument]),
           inferenceNeeded || typeChecksNeeded,
           isVoidAllowed: true);
       element.expression = spreadResult.expression..parent = element;
@@ -1203,21 +1407,45 @@
                   thenResult.inferredType, otherwiseResult.inferredType),
           element);
     } else if (element is ForElement) {
-      for (VariableDeclaration declaration in element.variables) {
-        if (declaration.name == null) {
-          if (declaration.initializer != null) {
+      // TODO(johnniwinther): Use _visitStatements instead.
+      List<VariableDeclaration> variables;
+      for (int index = 0; index < element.variables.length; index++) {
+        VariableDeclaration variable = element.variables[index];
+        if (variable.name == null) {
+          if (variable.initializer != null) {
             ExpressionInferenceResult initializerResult =
-                inferrer.inferExpression(declaration.initializer,
-                    declaration.type, inferenceNeeded || typeChecksNeeded,
+                inferrer.inferExpression(variable.initializer, variable.type,
+                    inferenceNeeded || typeChecksNeeded,
                     isVoidAllowed: true);
-            declaration.initializer = initializerResult.expression
-              ..parent = declaration;
-            declaration.type = initializerResult.inferredType;
+            variable.initializer = initializerResult.expression
+              ..parent = variable;
+            variable.type = initializerResult.inferredType;
           }
         } else {
-          inferrer.inferStatement(declaration);
+          StatementInferenceResult variableResult =
+              inferrer.inferStatement(variable);
+          if (variableResult.hasChanged) {
+            if (variables == null) {
+              variables = <VariableDeclaration>[];
+              variables.addAll(element.variables.sublist(0, index));
+            }
+            if (variableResult.statementCount == 1) {
+              variables.add(variableResult.statement);
+            } else {
+              for (VariableDeclaration variable in variableResult.statements) {
+                variables.add(variable);
+              }
+            }
+          } else if (variables != null) {
+            variables.add(variable);
+          }
         }
       }
+      if (variables != null) {
+        element.variables.clear();
+        element.variables.addAll(variables);
+        setParents(variables, element);
+      }
       inferrer.flowAnalysis.for_conditionBegin(element);
       if (element.condition != null) {
         ExpressionInferenceResult conditionResult = inferrer.inferExpression(
@@ -1347,7 +1575,8 @@
   ExpressionInferenceResult visitListLiteral(
       ListLiteral node, DartType typeContext) {
     Class listClass = inferrer.coreTypes.listClass;
-    InterfaceType listType = listClass.thisType;
+    InterfaceType listType = inferrer.coreTypes
+        .thisInterfaceType(listClass, inferrer.library.nonNullable);
     List<DartType> inferredTypes;
     DartType inferredTypeArgument;
     List<DartType> formalTypes;
@@ -1364,8 +1593,14 @@
     }
     if (inferenceNeeded) {
       inferredTypes = [const UnknownType()];
-      inferrer.typeSchemaEnvironment.inferGenericFunctionOrType(listType,
-          listClass.typeParameters, null, null, typeContext, inferredTypes,
+      inferrer.typeSchemaEnvironment.inferGenericFunctionOrType(
+          listType,
+          listClass.typeParameters,
+          null,
+          null,
+          typeContext,
+          inferredTypes,
+          inferrer.library.library,
           isConst: node.isConst);
       inferredTypeArgument = inferredTypes[0];
     } else {
@@ -1394,7 +1629,8 @@
           formalTypes,
           actualTypes,
           typeContext,
-          inferredTypes);
+          inferredTypes,
+          inferrer.library.library);
       inferredTypeArgument = inferredTypes[0];
       inferrer.instrumentation?.record(
           inferrer.uriForInstrumentation,
@@ -1410,7 +1646,7 @@
       }
     }
     DartType inferredType = new InterfaceType(
-        listClass, Nullability.legacy, [inferredTypeArgument]);
+        listClass, inferrer.library.nonNullable, [inferredTypeArgument]);
     if (!inferrer.isTopLevel) {
       SourceLibraryBuilder library = inferrer.library;
       if (inferenceNeeded) {
@@ -1564,7 +1800,9 @@
       mapEntryClass ??=
           inferrer.coreTypes.index.getClass('dart:core', 'MapEntry');
       // TODO(dmitryas):  Handle the case of an ambiguous Set.
-      entry.entryType = new InterfaceType(mapEntryClass, Nullability.legacy,
+      entry.entryType = new InterfaceType(
+          mapEntryClass,
+          inferrer.library.nonNullable,
           <DartType>[actualKeyType, actualValueType]);
 
       bool isMap = inferrer.typeSchemaEnvironment.isSubtypeOf(
@@ -1640,21 +1878,45 @@
       }
       return entry;
     } else if (entry is ForMapEntry) {
-      for (VariableDeclaration declaration in entry.variables) {
-        if (declaration.name == null) {
-          if (declaration.initializer != null) {
+      // TODO(johnniwinther): Use _visitStatements instead.
+      List<VariableDeclaration> variables;
+      for (int index = 0; index < entry.variables.length; index++) {
+        VariableDeclaration variable = entry.variables[index];
+        if (variable.name == null) {
+          if (variable.initializer != null) {
             ExpressionInferenceResult result = inferrer.inferExpression(
-                declaration.initializer,
-                declaration.type,
+                variable.initializer,
+                variable.type,
                 inferenceNeeded || typeChecksNeeded,
                 isVoidAllowed: true);
-            declaration.initializer = result.expression..parent = declaration;
-            declaration.type = result.inferredType;
+            variable.initializer = result.expression..parent = variable;
+            variable.type = result.inferredType;
           }
         } else {
-          inferrer.inferStatement(declaration);
+          StatementInferenceResult variableResult =
+              inferrer.inferStatement(variable);
+          if (variableResult.hasChanged) {
+            if (variables == null) {
+              variables = <VariableDeclaration>[];
+              variables.addAll(entry.variables.sublist(0, index));
+            }
+            if (variableResult.statementCount == 1) {
+              variables.add(variableResult.statement);
+            } else {
+              for (VariableDeclaration variable in variableResult.statements) {
+                variables.add(variable);
+              }
+            }
+          } else if (variables != null) {
+            variables.add(variable);
+          }
         }
       }
+      if (variables != null) {
+        entry.variables.clear();
+        entry.variables.addAll(variables);
+        setParents(variables, entry);
+      }
       inferrer.flowAnalysis.for_conditionBegin(entry);
       if (entry.condition != null) {
         ExpressionInferenceResult conditionResult = inferrer.inferExpression(
@@ -1820,7 +2082,8 @@
   ExpressionInferenceResult visitMapLiteral(
       MapLiteral node, DartType typeContext) {
     Class mapClass = inferrer.coreTypes.mapClass;
-    InterfaceType mapType = mapClass.thisType;
+    InterfaceType mapType = inferrer.coreTypes
+        .thisInterfaceType(mapClass, inferrer.library.nonNullable);
     List<DartType> inferredTypes;
     DartType inferredKeyType;
     DartType inferredValueType;
@@ -1866,8 +2129,14 @@
     }
     if (inferenceNeeded) {
       inferredTypes = [const UnknownType(), const UnknownType()];
-      inferrer.typeSchemaEnvironment.inferGenericFunctionOrType(mapType,
-          mapClass.typeParameters, null, null, typeContext, inferredTypes,
+      inferrer.typeSchemaEnvironment.inferGenericFunctionOrType(
+          mapType,
+          mapClass.typeParameters,
+          null,
+          null,
+          typeContext,
+          inferredTypes,
+          inferrer.library.library,
           isConst: node.isConst);
       inferredKeyType = inferredTypes[0];
       inferredValueType = inferredTypes[1];
@@ -1888,8 +2157,10 @@
         spreadTypeContext = inferrer.typeSchemaEnvironment
             .getTypeAsInstanceOf(typeContext, inferrer.coreTypes.iterableClass);
       } else if (!typeContextIsIterable && typeContextIsMap) {
-        spreadTypeContext = new InterfaceType(inferrer.coreTypes.mapClass,
-            Nullability.legacy, <DartType>[inferredKeyType, inferredValueType]);
+        spreadTypeContext = new InterfaceType(
+            inferrer.coreTypes.mapClass,
+            inferrer.library.nonNullable,
+            <DartType>[inferredKeyType, inferredValueType]);
       }
       for (int index = 0; index < node.entries.length; ++index) {
         MapEntry entry = node.entries[index];
@@ -1921,7 +2192,8 @@
       if (canBeSet && !canBeMap) {
         List<Expression> setElements = <Expression>[];
         List<DartType> formalTypesForSet = <DartType>[];
-        InterfaceType setType = inferrer.coreTypes.setClass.thisType;
+        InterfaceType setType = inferrer.coreTypes.thisInterfaceType(
+            inferrer.coreTypes.setClass, inferrer.library.nonNullable);
         for (int i = 0; i < node.entries.length; ++i) {
           setElements.add(convertToElement(node.entries[i], inferrer.helper,
               inferrer.assignedVariables.reassignInfo));
@@ -1936,14 +2208,17 @@
             null,
             typeContext,
             inferredTypesForSet,
+            inferrer.library.library,
             isConst: node.isConst);
         inferrer.typeSchemaEnvironment.inferGenericFunctionOrType(
-            inferrer.coreTypes.setClass.thisType,
+            inferrer.coreTypes.thisInterfaceType(
+                inferrer.coreTypes.setClass, inferrer.library.nonNullable),
             inferrer.coreTypes.setClass.typeParameters,
             formalTypesForSet,
             actualTypesForSet,
             typeContext,
-            inferredTypesForSet);
+            inferredTypesForSet,
+            inferrer.library.library);
         DartType inferredTypeArgument = inferredTypesForSet[0];
         inferrer.instrumentation?.record(
             inferrer.uriForInstrumentation,
@@ -1966,7 +2241,7 @@
         }
 
         DartType inferredType = new InterfaceType(inferrer.coreTypes.setClass,
-            Nullability.legacy, inferredTypesForSet);
+            inferrer.library.nonNullable, inferredTypesForSet);
         return new ExpressionInferenceResult(inferredType, setLiteral);
       }
       if (canBeSet && canBeMap && node.entries.isNotEmpty) {
@@ -1988,7 +2263,8 @@
           formalTypes,
           actualTypes,
           typeContext,
-          inferredTypes);
+          inferredTypes,
+          inferrer.library.library);
       inferredKeyType = inferredTypes[0];
       inferredValueType = inferredTypes[1];
       inferrer.instrumentation?.record(
@@ -2007,8 +2283,8 @@
         node.entries[index] = entry..parent = node;
       }
     }
-    DartType inferredType = new InterfaceType(
-        mapClass, Nullability.legacy, [inferredKeyType, inferredValueType]);
+    DartType inferredType = new InterfaceType(mapClass,
+        inferrer.library.nonNullable, [inferredKeyType, inferredValueType]);
     if (!inferrer.isTopLevel) {
       SourceLibraryBuilder library = inferrer.library;
       // Either both [_declaredKeyType] and [_declaredValueType] are omitted or
@@ -2134,7 +2410,7 @@
 
   ExpressionInferenceResult visitNullAwareMethodInvocation(
       NullAwareMethodInvocation node, DartType typeContext) {
-    inferrer.inferStatement(node.variable);
+    inferrer.inferSyntheticVariable(node.variable);
     ExpressionInferenceResult invocationResult = inferrer.inferExpression(
         node.invocation, typeContext, true,
         isVoidAllowed: true);
@@ -2149,7 +2425,7 @@
 
   ExpressionInferenceResult visitNullAwarePropertyGet(
       NullAwarePropertyGet node, DartType typeContext) {
-    inferrer.inferStatement(node.variable);
+    inferrer.inferSyntheticVariable(node.variable);
     ExpressionInferenceResult readResult =
         inferrer.inferExpression(node.read, const UnknownType(), true);
     Member equalsMember = inferrer
@@ -2163,7 +2439,7 @@
 
   ExpressionInferenceResult visitNullAwarePropertySet(
       NullAwarePropertySet node, DartType typeContext) {
-    inferrer.inferStatement(node.variable);
+    inferrer.inferSyntheticVariable(node.variable);
     ExpressionInferenceResult writeResult =
         inferrer.inferExpression(node.write, typeContext, true);
     Member equalsMember = inferrer
@@ -2177,7 +2453,7 @@
 
   ExpressionInferenceResult visitNullAwareExtension(
       NullAwareExtension node, DartType typeContext) {
-    inferrer.inferStatement(node.variable);
+    inferrer.inferSyntheticVariable(node.variable);
     ExpressionInferenceResult expressionResult =
         inferrer.inferExpression(node.expression, const UnknownType(), true);
     Member equalsMember = inferrer
@@ -2191,8 +2467,8 @@
 
   ExpressionInferenceResult visitStaticPostIncDec(
       StaticPostIncDec node, DartType typeContext) {
-    inferrer.inferStatement(node.read);
-    inferrer.inferStatement(node.write);
+    inferrer.inferSyntheticVariable(node.read);
+    inferrer.inferSyntheticVariable(node.write);
     DartType inferredType = node.read.type;
 
     Expression replacement =
@@ -2203,8 +2479,8 @@
 
   ExpressionInferenceResult visitSuperPostIncDec(
       SuperPostIncDec node, DartType typeContext) {
-    inferrer.inferStatement(node.read);
-    inferrer.inferStatement(node.write);
+    inferrer.inferSyntheticVariable(node.read);
+    inferrer.inferSyntheticVariable(node.write);
     DartType inferredType = node.read.type;
 
     Expression replacement =
@@ -2215,8 +2491,8 @@
 
   ExpressionInferenceResult visitLocalPostIncDec(
       LocalPostIncDec node, DartType typeContext) {
-    inferrer.inferStatement(node.read);
-    inferrer.inferStatement(node.write);
+    inferrer.inferSyntheticVariable(node.read);
+    inferrer.inferSyntheticVariable(node.write);
     DartType inferredType = node.read.type;
     Expression replacement =
         new Let(node.read, createLet(node.write, createVariableGet(node.read)))
@@ -2226,9 +2502,11 @@
 
   ExpressionInferenceResult visitPropertyPostIncDec(
       PropertyPostIncDec node, DartType typeContext) {
-    inferrer.inferStatement(node.variable);
-    inferrer.inferStatement(node.read);
-    inferrer.inferStatement(node.write);
+    if (node.variable != null) {
+      inferrer.inferSyntheticVariable(node.variable);
+    }
+    inferrer.inferSyntheticVariable(node.read);
+    inferrer.inferSyntheticVariable(node.write);
     DartType inferredType = node.read.type;
 
     Expression replacement;
@@ -2267,7 +2545,7 @@
     Expression writeReceiver;
     if (node.readOnlyReceiver && identical(receiver, node.receiver)) {
       readReceiver = receiver;
-      writeReceiver = receiver.accept<TreeNode>(new CloneVisitor());
+      writeReceiver = _clone(receiver);
     } else {
       receiverVariable = createVariable(receiver, receiverType);
       inferrer.instrumentation?.record(
@@ -2312,7 +2590,7 @@
 
   ExpressionInferenceResult visitIfNullPropertySet(
       IfNullPropertySet node, DartType typeContext) {
-    inferrer.inferStatement(node.variable);
+    inferrer.inferSyntheticVariable(node.variable);
     ExpressionInferenceResult readResult = inferrer.inferExpression(
         node.read, const UnknownType(), true,
         isVoidAllowed: true);
@@ -2409,6 +2687,41 @@
     return new ExpressionInferenceResult(inferredType, replacement);
   }
 
+  ExpressionInferenceResult visitIndexGet(IndexGet node, DartType typeContext) {
+    ExpressionInferenceResult receiverResult = inferrer.inferExpression(
+        node.receiver, const UnknownType(), true,
+        isVoidAllowed: true);
+    Expression receiver;
+    NullAwareGuard nullAwareGuard;
+    if (inferrer.isNonNullableByDefault) {
+      nullAwareGuard = receiverResult.nullAwareGuard;
+      receiver = receiverResult.nullAwareAction;
+    } else {
+      receiver = receiverResult.expression;
+    }
+    DartType receiverType = receiverResult.inferredType;
+
+    ObjectAccessTarget indexGetTarget = inferrer.findInterfaceMember(
+        receiverType, indexGetName, node.fileOffset,
+        includeExtensionMethods: true);
+
+    DartType indexType = inferrer.getIndexKeyType(indexGetTarget, receiverType);
+
+    MethodContravarianceCheckKind readCheckKind =
+        inferrer.preCheckInvocationContravariance(receiverType, indexGetTarget,
+            isThisReceiver: node.receiver is ThisExpression);
+
+    ExpressionInferenceResult indexResult = inferrer
+        .inferExpression(node.index, indexType, true, isVoidAllowed: true);
+
+    Expression index = inferrer.ensureAssignableResult(indexType, indexResult);
+
+    ExpressionInferenceResult replacement = _computeIndexGet(node.fileOffset,
+        receiver, receiverType, indexGetTarget, index, readCheckKind);
+    return new ExpressionInferenceResult.nullAware(
+        replacement.inferredType, replacement.expression, nullAwareGuard);
+  }
+
   ExpressionInferenceResult visitIndexSet(IndexSet node, DartType typeContext) {
     ExpressionInferenceResult receiverResult = inferrer.inferExpression(
         node.receiver, const UnknownType(), true,
@@ -2480,7 +2793,7 @@
         replacement = createLet(receiverVariable, replacement);
       }
     }
-    replacement..fileOffset = node.fileOffset;
+    replacement.fileOffset = node.fileOffset;
     return new ExpressionInferenceResult.nullAware(
         inferredType, replacement, nullAwareGuard);
   }
@@ -2628,8 +2941,8 @@
     VariableDeclaration receiverVariable;
     Expression readReceiver = receiver;
     Expression writeReceiver;
-    if (node.readOnlyReceiver) {
-      writeReceiver = readReceiver.accept<TreeNode>(new CloneVisitor());
+    if (node.readOnlyReceiver && identical(receiver, node.receiver)) {
+      writeReceiver = _clone(readReceiver);
     } else {
       receiverVariable = createVariable(readReceiver, receiverType);
       readReceiver = createVariableGet(receiverVariable);
@@ -2922,8 +3235,17 @@
     Expression receiver =
         inferrer.ensureAssignableResult(receiverType, receiverResult);
 
-    VariableDeclaration receiverVariable =
-        createVariable(receiver, receiverType);
+    VariableDeclaration receiverVariable;
+    Expression readReceiver;
+    Expression writeReceiver;
+    if (node.readOnlyReceiver && identical(receiver, node.receiver)) {
+      readReceiver = receiver;
+      writeReceiver = _clone(receiver);
+    } else {
+      receiverVariable = createVariable(receiver, receiverType);
+      readReceiver = createVariableGet(receiverVariable);
+      writeReceiver = createVariableGet(receiverVariable);
+    }
 
     ObjectAccessTarget readTarget = node.getter != null
         ? new ExtensionAccessTarget(
@@ -2953,7 +3275,7 @@
 
     ExpressionInferenceResult readResult = _computeIndexGet(
         node.readOffset,
-        createVariableGet(receiverVariable),
+        readReceiver,
         receiverType,
         readTarget,
         readIndex,
@@ -2984,15 +3306,10 @@
       value = createVariableGet(valueVariable);
     }
 
-    Expression write = _computeIndexSet(
-        node.writeOffset,
-        createVariableGet(receiverVariable),
-        receiverType,
-        writeTarget,
-        writeIndex,
-        value);
+    Expression write = _computeIndexSet(node.writeOffset, writeReceiver,
+        receiverType, writeTarget, writeIndex, value);
 
-    Expression inner;
+    Expression replacement;
     if (node.forEffect) {
       // Encode `Extension(o)[a] ??= b` as:
       //
@@ -3006,7 +3323,7 @@
       ConditionalExpression conditional = new ConditionalExpression(equalsNull,
           write, new NullLiteral()..fileOffset = node.testOffset, inferredType)
         ..fileOffset = node.testOffset;
-      inner = createLet(indexVariable, conditional);
+      replacement = createLet(indexVariable, conditional);
     } else {
       // Encode `Extension(o)[a] ??= b` as:
       //
@@ -3034,11 +3351,13 @@
           createVariableGet(readVariable),
           inferredType)
         ..fileOffset = node.fileOffset;
-      inner = createLet(indexVariable, createLet(readVariable, conditional));
+      replacement =
+          createLet(indexVariable, createLet(readVariable, conditional));
     }
-
-    Expression replacement = new Let(receiverVariable, inner)
-      ..fileOffset = node.fileOffset;
+    if (receiverVariable != null) {
+      replacement = new Let(receiverVariable, replacement);
+    }
+    replacement.fileOffset = node.fileOffset;
     return new ExpressionInferenceResult(inferredType, replacement);
   }
 
@@ -3318,7 +3637,8 @@
     Expression write;
     if (writeTarget.isMissing) {
       write = inferrer.createMissingIndexSet(
-          fileOffset, receiver, receiverType, index, value);
+          fileOffset, receiver, receiverType, index, value,
+          forEffect: true, readOnlyReceiver: true);
     } else if (writeTarget.isExtensionMember) {
       assert(writeTarget.extensionMethodKind != ProcedureKind.Setter);
       write = new StaticInvocation(
@@ -3513,7 +3833,7 @@
     Expression readReceiver = receiver;
     Expression writeReceiver;
     if (node.readOnlyReceiver) {
-      writeReceiver = readReceiver.accept<TreeNode>(new CloneVisitor());
+      writeReceiver = _clone(readReceiver);
     } else {
       receiverVariable = createVariable(readReceiver, receiverType);
       readReceiver = createVariableGet(receiverVariable);
@@ -3528,8 +3848,7 @@
         inferrer.preCheckInvocationContravariance(receiverType, readTarget,
             isThisReceiver: node.receiver is ThisExpression);
 
-    DartType readIndexType = inferrer.getPositionalParameterTypeForTarget(
-        readTarget, receiverType, 0);
+    DartType readIndexType = inferrer.getIndexKeyType(readTarget, receiverType);
 
     ExpressionInferenceResult indexResult = inferrer
         .inferExpression(node.index, readIndexType, true, isVoidAllowed: true);
@@ -3564,8 +3883,8 @@
         receiverType, indexSetName, node.writeOffset,
         includeExtensionMethods: true);
 
-    DartType writeIndexType = inferrer.getPositionalParameterTypeForTarget(
-        writeTarget, receiverType, 0);
+    DartType writeIndexType =
+        inferrer.getIndexKeyType(writeTarget, receiverType);
     Expression writeIndex = createVariableGet(indexVariable);
     writeIndex = inferrer.ensureAssignable(
         writeIndexType, indexResult.inferredType, writeIndex);
@@ -3769,8 +4088,8 @@
         : const ObjectAccessTarget.missing();
 
     DartType readType = inferrer.getReturnType(readTarget, inferrer.thisType);
-    DartType readIndexType = inferrer.getPositionalParameterTypeForTarget(
-        readTarget, inferrer.thisType, 0);
+    DartType readIndexType =
+        inferrer.getIndexKeyType(readTarget, inferrer.thisType);
 
     ExpressionInferenceResult indexResult = inferrer
         .inferExpression(node.index, readIndexType, true, isVoidAllowed: true);
@@ -3820,8 +4139,8 @@
         ? new ObjectAccessTarget.interfaceMember(node.setter)
         : const ObjectAccessTarget.missing();
 
-    DartType writeIndexType = inferrer.getPositionalParameterTypeForTarget(
-        writeTarget, inferrer.thisType, 0);
+    DartType writeIndexType =
+        inferrer.getIndexKeyType(writeTarget, inferrer.thisType);
     Expression writeIndex = createVariableGet(indexVariable);
     writeIndex = inferrer.ensureAssignable(
         writeIndexType, indexResult.inferredType, writeIndex);
@@ -3927,17 +4246,25 @@
             node.getter, null, ProcedureKind.Operator, extensionTypeArguments)
         : const ObjectAccessTarget.missing();
 
-    DartType receiverType = inferrer.getPositionalParameterTypeForTarget(
-        readTarget, receiverResult.inferredType, 0);
+    DartType receiverType = inferrer.getExtensionReceiverType(
+        node.extension, extensionTypeArguments);
 
     Expression receiver =
         inferrer.ensureAssignableResult(receiverType, receiverResult);
 
-    VariableDeclaration receiverVariable =
-        createVariable(receiver, receiverType);
+    VariableDeclaration receiverVariable;
+    Expression readReceiver;
+    Expression writeReceiver;
+    if (node.readOnlyReceiver && identical(receiver, node.receiver)) {
+      readReceiver = receiver;
+      writeReceiver = _clone(receiver);
+    } else {
+      receiverVariable = createVariable(receiver, receiverType);
+      readReceiver = createVariableGet(receiverVariable);
+      writeReceiver = createVariableGet(receiverVariable);
+    }
 
-    DartType readIndexType = inferrer.getPositionalParameterTypeForTarget(
-        readTarget, receiverType, 0);
+    DartType readIndexType = inferrer.getIndexKeyType(readTarget, receiverType);
 
     ExpressionInferenceResult indexResult = inferrer
         .inferExpression(node.index, readIndexType, true, isVoidAllowed: true);
@@ -3949,7 +4276,7 @@
 
     ExpressionInferenceResult readResult = _computeIndexGet(
         node.readOffset,
-        createVariableGet(receiverVariable),
+        readReceiver,
         receiverType,
         readTarget,
         readIndex,
@@ -3978,8 +4305,8 @@
             node.setter, null, ProcedureKind.Operator, extensionTypeArguments)
         : const ObjectAccessTarget.missing();
 
-    DartType writeIndexType = inferrer.getPositionalParameterTypeForTarget(
-        writeTarget, receiverType, 0);
+    DartType writeIndexType =
+        inferrer.getIndexSetValueType(writeTarget, receiverType);
     Expression writeIndex = createVariableGet(indexVariable);
     writeIndex = inferrer.ensureAssignable(
         writeIndexType, indexResult.inferredType, writeIndex);
@@ -3998,15 +4325,10 @@
       valueExpression = createVariableGet(valueVariable);
     }
 
-    Expression write = _computeIndexSet(
-        node.writeOffset,
-        createVariableGet(receiverVariable),
-        receiverType,
-        writeTarget,
-        writeIndex,
-        valueExpression);
+    Expression write = _computeIndexSet(node.writeOffset, writeReceiver,
+        receiverType, writeTarget, writeIndex, valueExpression);
 
-    Expression inner;
+    Expression replacement;
     if (node.forEffect) {
       assert(leftVariable == null);
       assert(valueVariable == null);
@@ -4016,7 +4338,7 @@
       //     let indexVariable = a in
       //         receiverVariable.[]=(receiverVariable, o.[](indexVariable) + b)
       //
-      inner = createLet(indexVariable, write);
+      replacement = createLet(indexVariable, write);
     } else if (node.forPostIncDec) {
       // Encode `Extension(o)[a]++` as:
       //
@@ -4032,7 +4354,7 @@
 
       VariableDeclaration writeVariable =
           createVariable(write, const VoidType());
-      inner = createLet(
+      replacement = createLet(
           indexVariable,
           createLet(leftVariable,
               createLet(writeVariable, createVariableGet(leftVariable))));
@@ -4051,14 +4373,16 @@
 
       VariableDeclaration writeVariable =
           createVariable(write, const VoidType());
-      inner = createLet(
+      replacement = createLet(
           indexVariable,
           createLet(valueVariable,
               createLet(writeVariable, createVariableGet(valueVariable))));
     }
 
-    Expression replacement = new Let(receiverVariable, inner)
-      ..fileOffset = node.fileOffset;
+    if (receiverVariable != null) {
+      replacement = new Let(receiverVariable, replacement);
+    }
+    replacement.fileOffset = node.fileOffset;
     return new ExpressionInferenceResult(
         node.forPostIncDec ? readType : binaryType, replacement);
   }
@@ -4265,13 +4589,14 @@
     List<DartType> typeArguments =
         new List<DartType>(classTypeParameters.length);
     for (int i = 0; i < typeArguments.length; i++) {
-      typeArguments[i] =
-          new TypeParameterType(classTypeParameters[i], Nullability.legacy);
+      typeArguments[i] = new TypeParameterType.withDefaultNullabilityForLibrary(
+          classTypeParameters[i], inferrer.library.library);
     }
     ArgumentsImpl.setNonInferrableArgumentTypes(node.arguments, typeArguments);
     inferrer.inferInvocation(null, node.fileOffset,
         node.target.function.thisFunctionType, node.arguments,
-        returnType: node.target.enclosingClass.thisType,
+        returnType: inferrer.coreTypes.thisInterfaceType(
+            node.target.enclosingClass, inferrer.library.nonNullable),
         skipTypeArgumentInference: true);
     ArgumentsImpl.removeNonInferrableArgumentTypes(node.arguments);
   }
@@ -4283,7 +4608,8 @@
   }
 
   @override
-  void visitReturnStatement(covariant ReturnStatementImpl node) {
+  StatementInferenceResult visitReturnStatement(
+      covariant ReturnStatementImpl node) {
     ClosureContext closureContext = inferrer.closureContext;
     DartType typeContext = !closureContext.isGenerator
         ? closureContext.returnOrYieldContext
@@ -4300,13 +4626,15 @@
     }
     closureContext.handleReturn(inferrer, node, inferredType, node.isArrow);
     inferrer.flowAnalysis.handleExit();
+    return const StatementInferenceResult();
   }
 
   @override
   ExpressionInferenceResult visitSetLiteral(
       SetLiteral node, DartType typeContext) {
     Class setClass = inferrer.coreTypes.setClass;
-    InterfaceType setType = setClass.thisType;
+    InterfaceType setType = inferrer.coreTypes
+        .thisInterfaceType(setClass, inferrer.library.nonNullable);
     List<DartType> inferredTypes;
     DartType inferredTypeArgument;
     List<DartType> formalTypes;
@@ -4323,8 +4651,14 @@
     }
     if (inferenceNeeded) {
       inferredTypes = [const UnknownType()];
-      inferrer.typeSchemaEnvironment.inferGenericFunctionOrType(setType,
-          setClass.typeParameters, null, null, typeContext, inferredTypes,
+      inferrer.typeSchemaEnvironment.inferGenericFunctionOrType(
+          setType,
+          setClass.typeParameters,
+          null,
+          null,
+          typeContext,
+          inferredTypes,
+          inferrer.library.library,
           isConst: node.isConst);
       inferredTypeArgument = inferredTypes[0];
     } else {
@@ -4353,7 +4687,8 @@
           formalTypes,
           actualTypes,
           typeContext,
-          inferredTypes);
+          inferredTypes,
+          inferrer.library.library);
       inferredTypeArgument = inferredTypes[0];
       inferrer.instrumentation?.record(
           inferrer.uriForInstrumentation,
@@ -4368,8 +4703,8 @@
             inferredSpreadTypes, inferredConditionTypes);
       }
     }
-    DartType inferredType =
-        new InterfaceType(setClass, Nullability.legacy, [inferredTypeArgument]);
+    DartType inferredType = new InterfaceType(
+        setClass, inferrer.library.nonNullable, [inferredTypeArgument]);
     if (!inferrer.isTopLevel) {
       SourceLibraryBuilder library = inferrer.library;
       if (inferenceNeeded) {
@@ -4419,7 +4754,8 @@
       StaticInvocation node, DartType typeContext) {
     FunctionType calleeType = node.target != null
         ? node.target.function.functionType
-        : new FunctionType([], const DynamicType(), Nullability.legacy);
+        : new FunctionType(
+            [], const DynamicType(), inferrer.library.nonNullable);
     TypeArgumentsInfo typeArgumentsInfo = getTypeArgumentsInfo(node.arguments);
     DartType inferredType = inferrer.inferInvocation(
         typeContext, node.fileOffset, calleeType, node.arguments);
@@ -4529,7 +4865,7 @@
   }
 
   @override
-  void visitSwitchStatement(SwitchStatement node) {
+  StatementInferenceResult visitSwitchStatement(SwitchStatement node) {
     ExpressionInferenceResult expressionResult = inferrer.inferExpression(
         node.expression, const UnknownType(), true,
         isVoidAllowed: false);
@@ -4567,9 +4903,14 @@
               ]);
         }
       }
-      inferrer.inferStatement(switchCase.body);
+      StatementInferenceResult bodyResult =
+          inferrer.inferStatement(switchCase.body);
+      if (bodyResult.hasChanged) {
+        switchCase.body = bodyResult.statement..parent = switchCase;
+      }
     }
     inferrer.flowAnalysis.switchStatement_end(hasDefault);
+    return const StatementInferenceResult();
   }
 
   @override
@@ -4602,13 +4943,19 @@
     if (node.stackTrace != null) {
       inferrer.flowAnalysis.initialize(node.stackTrace);
     }
-    inferrer.inferStatement(node.body);
+    StatementInferenceResult bodyResult = inferrer.inferStatement(node.body);
+    if (bodyResult.hasChanged) {
+      node.body = bodyResult.statement..parent = node;
+    }
   }
 
   @override
-  void visitTryCatch(TryCatch node) {
+  StatementInferenceResult visitTryCatch(TryCatch node) {
     inferrer.flowAnalysis.tryCatchStatement_bodyBegin();
-    inferrer.inferStatement(node.body);
+    StatementInferenceResult bodyResult = inferrer.inferStatement(node.body);
+    if (bodyResult.hasChanged) {
+      node.body = bodyResult.statement..parent = node;
+    }
     inferrer.flowAnalysis.tryCatchStatement_bodyEnd(node.body);
     for (Catch catch_ in node.catches) {
       inferrer.flowAnalysis
@@ -4619,15 +4966,24 @@
       inferrer.flowAnalysis.tryCatchStatement_catchEnd();
     }
     inferrer.flowAnalysis.tryCatchStatement_end();
+    return const StatementInferenceResult();
   }
 
   @override
-  void visitTryFinally(TryFinally node) {
+  StatementInferenceResult visitTryFinally(TryFinally node) {
     inferrer.flowAnalysis.tryFinallyStatement_bodyBegin();
-    inferrer.inferStatement(node.body);
+    StatementInferenceResult bodyResult = inferrer.inferStatement(node.body);
+    if (bodyResult.hasChanged) {
+      node.body = bodyResult.statement..parent = node;
+    }
     inferrer.flowAnalysis.tryFinallyStatement_finallyBegin(node.finalizer);
-    inferrer.inferStatement(node.finalizer);
+    StatementInferenceResult finalizerResult =
+        inferrer.inferStatement(node.finalizer);
+    if (finalizerResult.hasChanged) {
+      node.finalizer = finalizerResult.statement..parent = node;
+    }
     inferrer.flowAnalysis.tryFinallyStatement_end(node.finalizer);
+    return const StatementInferenceResult();
   }
 
   @override
@@ -4641,26 +4997,39 @@
   @override
   ExpressionInferenceResult visitVariableSet(
       VariableSet node, DartType typeContext) {
-    DartType writeContext = node.variable.type;
+    VariableDeclarationImpl variable = node.variable;
+    DartType writeContext = variable.type;
     ExpressionInferenceResult rhsResult = inferrer.inferExpression(
         node.value, writeContext ?? const UnknownType(), true,
         isVoidAllowed: true);
     Expression rhs = inferrer.ensureAssignableResult(writeContext, rhsResult,
         fileOffset: node.fileOffset, isVoidAllowed: writeContext is VoidType);
-    node.value = rhs..parent = node;
-    inferrer.flowAnalysis.write(node.variable, rhsResult.inferredType);
-    return new ExpressionInferenceResult(rhsResult.inferredType, node);
+    inferrer.flowAnalysis.write(variable, rhsResult.inferredType);
+    if (variable.lateSetter != null) {
+      return new ExpressionInferenceResult(
+          rhsResult.inferredType,
+          new MethodInvocation(
+              new VariableGet(variable.lateSetter)
+                ..fileOffset = node.fileOffset,
+              callName,
+              new Arguments(<Expression>[rhs])..fileOffset = node.fileOffset)
+            ..fileOffset = node.fileOffset);
+    } else {
+      node.value = rhs..parent = node;
+      return new ExpressionInferenceResult(rhsResult.inferredType, node);
+    }
   }
 
   @override
-  void visitVariableDeclaration(covariant VariableDeclarationImpl node) {
+  StatementInferenceResult visitVariableDeclaration(
+      covariant VariableDeclarationImpl node) {
     DartType declaredType =
-        node._implicitlyTyped ? const UnknownType() : node.type;
+        node.isImplicitlyTyped ? const UnknownType() : node.type;
     DartType inferredType;
     ExpressionInferenceResult initializerResult;
     if (node.initializer != null) {
       initializerResult = inferrer.inferExpression(node.initializer,
-          declaredType, !inferrer.isTopLevel || node._implicitlyTyped,
+          declaredType, !inferrer.isTopLevel || node.isImplicitlyTyped,
           isVoidAllowed: true);
       inferredType =
           inferrer.inferDeclarationType(initializerResult.inferredType);
@@ -4668,7 +5037,7 @@
     } else {
       inferredType = const DynamicType();
     }
-    if (node._implicitlyTyped) {
+    if (node.isImplicitlyTyped) {
       inferrer.instrumentation?.record(
           inferrer.uriForInstrumentation,
           node.fileOffset,
@@ -4684,12 +5053,98 @@
     }
     if (!inferrer.isTopLevel) {
       SourceLibraryBuilder library = inferrer.library;
-      if (node._implicitlyTyped) {
+      if (node.isImplicitlyTyped) {
         library.checkBoundsInVariableDeclaration(
             node, inferrer.typeSchemaEnvironment, inferrer.helper.uri,
             inferred: true);
       }
     }
+    if (node.isLate &&
+        !inferrer.library.loader.target.backendTarget.supportsLateFields) {
+      int fileOffset = node.fileOffset;
+
+      List<Statement> result = <Statement>[];
+      result.add(node);
+
+      VariableDeclaration isSetVariable;
+      if (node.type.isPotentiallyNullable) {
+        isSetVariable = new VariableDeclaration('#${node.name}#isSet',
+            initializer: new BoolLiteral(false)..fileOffset = fileOffset,
+            type: inferrer.coreTypes.boolRawType(inferrer.library.nonNullable))
+          ..fileOffset = fileOffset;
+        result.add(isSetVariable);
+      }
+
+      Expression createVariableRead() => new VariableGet(node);
+      Expression createIsSetRead() => new VariableGet(isSetVariable);
+      Expression createVariableWrite(Expression value) =>
+          new VariableSet(node, value);
+      Expression createIsSetWrite(Expression value) =>
+          new VariableSet(isSetVariable, value);
+
+      VariableDeclaration getVariable =
+          new VariableDeclaration('#${node.name}#get')..fileOffset = fileOffset;
+      FunctionDeclaration getter = new FunctionDeclaration(
+          getVariable,
+          new FunctionNode(
+              node.initializer == null
+                  ? late_lowering.createGetterBodyWithoutInitializer(
+                      fileOffset, node.name, node.type, 'Local',
+                      createVariableRead: createVariableRead,
+                      createIsSetRead: createIsSetRead)
+                  : late_lowering.createGetterWithInitializer(
+                      fileOffset, node.name, node.type, node.initializer,
+                      createVariableRead: createVariableRead,
+                      createVariableWrite: createVariableWrite,
+                      createIsSetRead: createIsSetRead,
+                      createIsSetWrite: createIsSetWrite),
+              returnType: node.type))
+        ..fileOffset = fileOffset;
+      getVariable.type = getter.function.functionType;
+      node.lateGetter = getVariable;
+      result.add(getter);
+
+      if (!node.isFinal || node.initializer == null) {
+        VariableDeclaration setVariable =
+            new VariableDeclaration('#${node.name}#set')
+              ..fileOffset = fileOffset;
+        VariableDeclaration setterParameter =
+            new VariableDeclaration(null, type: node.type)
+              ..fileOffset = fileOffset;
+        FunctionDeclaration setter = new FunctionDeclaration(
+                setVariable,
+                new FunctionNode(
+                    node.isFinal
+                        ? late_lowering.createSetterBodyFinal(fileOffset,
+                            node.name, setterParameter, node.type, 'Local',
+                            shouldReturnValue: true,
+                            createVariableRead: createVariableRead,
+                            createVariableWrite: createVariableWrite,
+                            createIsSetRead: createIsSetRead,
+                            createIsSetWrite: createIsSetWrite)
+                        : late_lowering.createSetterBody(
+                            fileOffset, node.name, setterParameter, node.type,
+                            shouldReturnValue: true,
+                            createVariableWrite: createVariableWrite,
+                            createIsSetWrite: createIsSetWrite)
+                      ..fileOffset = fileOffset,
+                    positionalParameters: <VariableDeclaration>[
+                      setterParameter
+                    ]))
+            // TODO(johnniwinther): Reinsert the file offset when the vm doesn't
+            //  use it for function declaration identity.
+            /*..fileOffset = fileOffset*/;
+        setVariable.type = setter.function.functionType;
+        node.lateSetter = setVariable;
+        result.add(setter);
+      }
+      node.isLate = false;
+      node.type = node.type.withNullability(Nullability.nullable);
+      node.initializer = null;
+
+      return new StatementInferenceResult.multiple(node.fileOffset, result);
+    }
+    return const StatementInferenceResult();
   }
 
   @override
@@ -4706,9 +5161,9 @@
     if (inferrer.isNonNullableByDefault) {
       promotedType = inferrer.flowAnalysis.variableRead(node, variable);
     } else {
-      bool mutatedInClosure = variable._mutatedInClosure;
+      bool mutatedInClosure = variable.mutatedInClosure;
       promotedType = inferrer.typePromoter
-          .computePromotedType(node._fact, node._scope, mutatedInClosure);
+          .computePromotedType(node.fact, node.scope, mutatedInClosure);
     }
     if (promotedType != null) {
       inferrer.instrumentation?.record(
@@ -4719,15 +5174,24 @@
     }
     node.promotedType = promotedType;
     DartType type = promotedType ?? declaredOrInferredType;
-    if (variable._isLocalFunction) {
+    if (variable.isLocalFunction) {
       return inferrer.instantiateTearOff(type, typeContext, node);
+    } else if (variable.lateGetter != null) {
+      return new ExpressionInferenceResult(
+          type,
+          new MethodInvocation(
+              new VariableGet(variable.lateGetter)
+                ..fileOffset = node.fileOffset,
+              callName,
+              new Arguments(<Expression>[])..fileOffset = node.fileOffset)
+            ..fileOffset = node.fileOffset);
     } else {
       return new ExpressionInferenceResult(type, node);
     }
   }
 
   @override
-  void visitWhileStatement(WhileStatement node) {
+  StatementInferenceResult visitWhileStatement(WhileStatement node) {
     InterfaceType expectedType =
         inferrer.coreTypes.boolRawType(inferrer.library.nonNullable);
     ExpressionInferenceResult conditionResult = inferrer.inferExpression(
@@ -4736,11 +5200,15 @@
     Expression condition =
         inferrer.ensureAssignableResult(expectedType, conditionResult);
     node.condition = condition..parent = node;
-    inferrer.inferStatement(node.body);
+    StatementInferenceResult bodyResult = inferrer.inferStatement(node.body);
+    if (bodyResult.hasChanged) {
+      node.body = bodyResult.statement..parent = node;
+    }
+    return const StatementInferenceResult();
   }
 
   @override
-  void visitYieldStatement(YieldStatement node) {
+  StatementInferenceResult visitYieldStatement(YieldStatement node) {
     ClosureContext closureContext = inferrer.closureContext;
     ExpressionInferenceResult expressionResult;
     if (closureContext.isGenerator) {
@@ -4750,7 +5218,8 @@
             typeContext,
             closureContext.isAsync
                 ? inferrer.coreTypes.streamClass
-                : inferrer.coreTypes.iterableClass);
+                : inferrer.coreTypes.iterableClass,
+            inferrer.library.nonNullable);
       }
       expressionResult = inferrer.inferExpression(
           node.expression, typeContext, true,
@@ -4761,16 +5230,17 @@
           isVoidAllowed: true);
     }
     closureContext.handleYield(inferrer, node, expressionResult);
+    return const StatementInferenceResult();
   }
 
   @override
   ExpressionInferenceResult visitLoadLibrary(
       covariant LoadLibraryImpl node, DartType typeContext) {
     DartType inferredType = inferrer.typeSchemaEnvironment
-        .futureType(const DynamicType(), Nullability.legacy);
+        .futureType(const DynamicType(), inferrer.library.nullable);
     if (node.arguments != null) {
       FunctionType calleeType =
-          new FunctionType([], inferredType, Nullability.legacy);
+          new FunctionType([], inferredType, inferrer.library.nonNullable);
       inferrer.inferInvocation(
           typeContext, node.fileOffset, calleeType, node.arguments);
     }
@@ -4782,8 +5252,8 @@
     DartType inferredType = new FunctionType(
         [],
         inferrer.typeSchemaEnvironment
-            .futureType(const DynamicType(), Nullability.legacy),
-        Nullability.legacy);
+            .futureType(const DynamicType(), inferrer.library.nullable),
+        inferrer.library.nonNullable);
     Expression replacement = new StaticGet(node.target)
       ..fileOffset = node.fileOffset;
     return new ExpressionInferenceResult(inferredType, replacement);
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart b/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart
similarity index 95%
rename from pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
rename to pkg/front_end/lib/src/fasta/kernel/internal_ast.dart
index ae75f53..b97a372 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart
@@ -22,48 +22,17 @@
 
 import 'package:kernel/ast.dart';
 
-import 'package:kernel/type_algebra.dart' show Substitution;
-
-import 'package:kernel/type_environment.dart';
-
-import 'package:kernel/clone.dart';
-
-import '../../base/instrumentation.dart'
-    show
-        InstrumentationValueForMember,
-        InstrumentationValueForType,
-        InstrumentationValueForTypeArgs;
-
-import '../builder/library_builder.dart';
+import 'package:kernel/core_types.dart';
 
 import '../fasta_codes.dart'
-    show
-        messageCantDisambiguateAmbiguousInformation,
-        messageCantDisambiguateNotEnoughInformation,
-        messageNonNullAwareSpreadIsNull,
-        messageSwitchExpressionNotAssignableCause,
-        noLength,
-        templateCantInferTypeDueToCircularity,
-        templateForInLoopElementTypeNotAssignable,
-        templateForInLoopTypeNotIterable,
-        templateIntegerLiteralIsOutOfRange,
-        templateSpreadElementTypeMismatch,
-        templateSpreadMapEntryElementKeyTypeMismatch,
-        templateSpreadMapEntryElementValueTypeMismatch,
-        templateSpreadMapEntryTypeMismatch,
-        templateSpreadTypeMismatch,
-        templateSwitchExpressionNotAssignable,
-        templateUndefinedSetter,
-        templateWebLiteralCannotBeRepresentedExactly;
+    show noLength, templateWebLiteralCannotBeRepresentedExactly;
 
 import '../names.dart';
 
-import '../problems.dart' show unhandled, unsupported;
+import '../problems.dart' show unsupported;
 
 import '../source/source_class_builder.dart' show SourceClassBuilder;
 
-import '../source/source_library_builder.dart' show SourceLibraryBuilder;
-
 import '../type_inference/type_inference_engine.dart';
 import '../type_inference/type_inferrer.dart';
 
@@ -72,33 +41,17 @@
 
 import '../type_inference/type_schema.dart' show UnknownType;
 
-import '../type_inference/type_schema_elimination.dart' show greatestClosure;
-
 import '../type_inference/type_schema_environment.dart'
     show TypeSchemaEnvironment;
 
-import 'body_builder.dart' show combineStatements;
-
-import 'collections.dart'
-    show
-        ForElement,
-        ForInElement,
-        ForInMapEntry,
-        ForMapEntry,
-        IfElement,
-        IfMapEntry,
-        SpreadElement,
-        SpreadMapEntry,
-        convertToElement;
-
-import 'implicit_type_argument.dart' show ImplicitTypeArgument;
-
-part "inference_visitor.dart";
+import 'inference_visitor.dart';
 
 /// Computes the return type of a (possibly factory) constructor.
-InterfaceType computeConstructorReturnType(Member constructor) {
+InterfaceType computeConstructorReturnType(
+    Member constructor, CoreTypes coreTypes) {
   if (constructor is Constructor) {
-    return constructor.enclosingClass.thisType;
+    return coreTypes.thisInterfaceType(
+        constructor.enclosingClass, constructor.enclosingLibrary.nonNullable);
   } else {
     return constructor.function.returnType;
   }
@@ -261,6 +214,7 @@
   IfNullPropertySet,
   IfNullSet,
   IfNullSuperIndexSet,
+  IndexGet,
   IndexSet,
   LoadLibraryTearOff,
   LocalPostIncDec,
@@ -380,6 +334,8 @@
   /// initializer;
   VariableDeclaration variable;
 
+  final bool isNullAware;
+
   /// The expressions performed on [variable].
   final List<Expression> expressions = <Expression>[];
 
@@ -387,7 +343,7 @@
   /// variable.  Caller is responsible for ensuring that [variable]'s
   /// initializer is the expression preceding the first `..` of the cascade
   /// expression.
-  Cascade(this.variable) {
+  Cascade(this.variable, {this.isNullAware}) : assert(isNullAware != null) {
     variable?.parent = this;
   }
 
@@ -490,7 +446,7 @@
 
 /// Front end specific implementation of [FunctionDeclaration].
 class FunctionDeclarationImpl extends FunctionDeclaration {
-  bool _hasImplicitReturnType = false;
+  bool hasImplicitReturnType = false;
 
   FunctionDeclarationImpl(
       VariableDeclarationImpl variable, FunctionNode function)
@@ -498,7 +454,7 @@
 
   static void setHasImplicitReturnType(
       FunctionDeclarationImpl declaration, bool hasImplicitReturnType) {
-    declaration._hasImplicitReturnType = hasImplicitReturnType;
+    declaration.hasImplicitReturnType = hasImplicitReturnType;
   }
 }
 
@@ -857,7 +813,7 @@
   @override
   int getVariableFunctionNestingLevel(VariableDeclaration variable) {
     if (variable is VariableDeclarationImpl) {
-      return variable._functionNestingLevel;
+      return variable.functionNestingLevel;
     } else {
       // Hack to deal with the fact that BodyBuilder still creates raw
       // VariableDeclaration objects sometimes.
@@ -871,7 +827,7 @@
   bool isPromotionCandidate(VariableDeclaration variable) {
     assert(variable is VariableDeclarationImpl);
     VariableDeclarationImpl kernelVariableDeclaration = variable;
-    return !kernelVariableDeclaration._isLocalFunction;
+    return !kernelVariableDeclaration.isLocalFunction;
   }
 
   @override
@@ -882,7 +838,7 @@
   @override
   void setVariableMutatedAnywhere(VariableDeclaration variable) {
     if (variable is VariableDeclarationImpl) {
-      variable._mutatedAnywhere = true;
+      variable.mutatedAnywhere = true;
     } else {
       // Hack to deal with the fact that BodyBuilder still creates raw
       // VariableDeclaration objects sometimes.
@@ -894,7 +850,7 @@
   @override
   void setVariableMutatedInClosure(VariableDeclaration variable) {
     if (variable is VariableDeclarationImpl) {
-      variable._mutatedInClosure = true;
+      variable.mutatedInClosure = true;
     } else {
       // Hack to deal with the fact that BodyBuilder still creates raw
       // VariableDeclaration objects sometimes.
@@ -906,7 +862,7 @@
   @override
   bool wasVariableMutatedAnywhere(VariableDeclaration variable) {
     if (variable is VariableDeclarationImpl) {
-      return variable._mutatedAnywhere;
+      return variable.mutatedAnywhere;
     } else {
       // Hack to deal with the fact that BodyBuilder still creates raw
       // VariableDeclaration objects sometimes.
@@ -921,25 +877,35 @@
 class VariableDeclarationImpl extends VariableDeclaration {
   final bool forSyntheticToken;
 
-  final bool _implicitlyTyped;
+  /// Determine whether the given [VariableDeclarationImpl] had an implicit
+  /// type.
+  ///
+  /// This is static to avoid introducing a method that would be visible to
+  /// the kernel.
+  final bool isImplicitlyTyped;
 
   // TODO(ahe): Remove this field. We can get rid of it by recording closure
   // mutation in [BodyBuilder].
-  final int _functionNestingLevel;
+  final int functionNestingLevel;
 
   // TODO(ahe): Remove this field. It's only used locally when compiling a
   // method, and this can thus be tracked in a [Set] (actually, tracking this
   // information in a [List] is probably even faster as the average size will
   // be close to zero).
-  bool _mutatedInClosure = false;
+  bool mutatedInClosure = false;
 
   // TODO(ahe): Investigate if this can be removed.
-  bool _mutatedAnywhere = false;
+  bool mutatedAnywhere = false;
 
+  /// Determines whether the given [VariableDeclarationImpl] represents a
+  /// local function.
+  ///
+  /// This is static to avoid introducing a method that would be visible to the
+  /// kernel.
   // TODO(ahe): Investigate if this can be removed.
-  final bool _isLocalFunction;
+  final bool isLocalFunction;
 
-  VariableDeclarationImpl(String name, this._functionNestingLevel,
+  VariableDeclarationImpl(String name, this.functionNestingLevel,
       {this.forSyntheticToken: false,
       Expression initializer,
       DartType type,
@@ -950,8 +916,8 @@
       bool isLocalFunction: false,
       bool isLate: false,
       bool isRequired: false})
-      : _implicitlyTyped = type == null,
-        _isLocalFunction = isLocalFunction,
+      : isImplicitlyTyped = type == null,
+        isLocalFunction = isLocalFunction,
         super(name,
             initializer: initializer,
             type: type ?? const DynamicType(),
@@ -964,42 +930,29 @@
 
   VariableDeclarationImpl.forEffect(Expression initializer)
       : forSyntheticToken = false,
-        _functionNestingLevel = 0,
-        _implicitlyTyped = false,
-        _isLocalFunction = false,
+        functionNestingLevel = 0,
+        isImplicitlyTyped = false,
+        isLocalFunction = false,
         super.forValue(initializer);
 
   VariableDeclarationImpl.forValue(Expression initializer)
       : forSyntheticToken = false,
-        _functionNestingLevel = 0,
-        _implicitlyTyped = true,
-        _isLocalFunction = false,
+        functionNestingLevel = 0,
+        isImplicitlyTyped = true,
+        isLocalFunction = false,
         super.forValue(initializer);
 
-  /// Determine whether the given [VariableDeclarationImpl] had an implicit
-  /// type.
-  ///
-  /// This is static to avoid introducing a method that would be visible to
-  /// the kernel.
-  static bool isImplicitlyTyped(VariableDeclarationImpl variable) =>
-      variable._implicitlyTyped;
-
-  /// Determines whether the given [VariableDeclarationImpl] represents a
-  /// local function.
-  ///
-  /// This is static to avoid introducing a method that would be visible to the
-  /// kernel.
-  static bool isLocalFunction(VariableDeclarationImpl variable) =>
-      variable._isLocalFunction;
+  VariableDeclaration lateGetter;
+  VariableDeclaration lateSetter;
 }
 
 /// Front end specific implementation of [VariableGet].
 class VariableGetImpl extends VariableGet {
-  final TypePromotionFact _fact;
+  final TypePromotionFact fact;
 
-  final TypePromotionScope _scope;
+  final TypePromotionScope scope;
 
-  VariableGetImpl(VariableDeclaration variable, this._fact, this._scope)
+  VariableGetImpl(VariableDeclaration variable, this.fact, this.scope)
       : super(variable);
 }
 
@@ -1567,6 +1520,47 @@
   }
 }
 
+/// Internal expression representing an index get expression.
+class IndexGet extends InternalExpression {
+  /// The receiver on which the index set operation is performed.
+  Expression receiver;
+
+  /// The index expression of the operation.
+  Expression index;
+
+  IndexGet(this.receiver, this.index) {
+    receiver?.parent = this;
+    index?.parent = this;
+  }
+
+  @override
+  ExpressionInferenceResult acceptInference(
+      InferenceVisitor visitor, DartType typeContext) {
+    return visitor.visitIndexGet(this, typeContext);
+  }
+
+  @override
+  InternalExpressionKind get kind => InternalExpressionKind.IndexGet;
+
+  @override
+  void visitChildren(Visitor<dynamic> v) {
+    receiver?.accept(v);
+    index?.accept(v);
+  }
+
+  @override
+  void transformChildren(Transformer v) {
+    if (receiver != null) {
+      receiver = receiver.accept<TreeNode>(v);
+      receiver?.parent = this;
+    }
+    if (index != null) {
+      index = index.accept<TreeNode>(v);
+      index?.parent = this;
+    }
+  }
+}
+
 /// Internal expression representing an index set expression.
 ///
 /// An index set expression of the form `o[a] = b` used for value is encoded as
@@ -2002,15 +1996,24 @@
   /// If `true`, the expression is only need for effect and not for its value.
   final bool forEffect;
 
+  /// If `true`, the receiver is read-only and therefore doesn't need a
+  /// temporary variable for its value.
+  final bool readOnlyReceiver;
+
   IfNullExtensionIndexSet(this.extension, this.explicitTypeArguments,
       this.receiver, this.getter, this.setter, this.index, this.value,
-      {this.readOffset, this.testOffset, this.writeOffset, this.forEffect})
+      {this.readOffset,
+      this.testOffset,
+      this.writeOffset,
+      this.forEffect,
+      this.readOnlyReceiver})
       : assert(explicitTypeArguments == null ||
             explicitTypeArguments.length == extension.typeParameters.length),
         assert(readOffset != null),
         assert(testOffset != null),
         assert(writeOffset != null),
-        assert(forEffect != null) {
+        assert(forEffect != null),
+        assert(readOnlyReceiver != null) {
     receiver?.parent = this;
     index?.parent = this;
     value?.parent = this;
@@ -2474,6 +2477,10 @@
   /// If `true`, the expression is a post-fix inc/dec expression.
   final bool forPostIncDec;
 
+  /// If `true` the receiver can be cloned instead of creating a temporary
+  /// variable.
+  final bool readOnlyReceiver;
+
   CompoundExtensionIndexSet(
       this.extension,
       this.explicitTypeArguments,
@@ -2487,14 +2494,16 @@
       this.binaryOffset,
       this.writeOffset,
       this.forEffect,
-      this.forPostIncDec})
+      this.forPostIncDec,
+      this.readOnlyReceiver})
       : assert(explicitTypeArguments == null ||
             explicitTypeArguments.length == extension.typeParameters.length),
         assert(readOffset != null),
         assert(binaryOffset != null),
         assert(writeOffset != null),
         assert(forEffect != null),
-        assert(forPostIncDec != null) {
+        assert(forPostIncDec != null),
+        assert(readOnlyReceiver != null) {
     receiver?.parent = this;
     index?.parent = this;
     rhs?.parent = this;
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_ast_api.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_ast_api.dart
index 975c09a..29365bc 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_ast_api.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_ast_api.dart
@@ -82,7 +82,7 @@
         VoidType,
         setParents;
 
-export 'kernel_shadow_ast.dart'
+export 'internal_ast.dart'
     show
         ArgumentsImpl,
         Cascade,
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 0a6001d..dbd9dfb 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
@@ -31,11 +31,14 @@
         RedirectingInitializer,
         Source,
         SuperInitializer,
+        Supertype,
         TypeParameter,
         TypeParameterType,
         VariableDeclaration,
         VariableGet;
 
+import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
+
 import 'package:kernel/clone.dart' show CloneVisitor;
 
 import 'package:kernel/type_algebra.dart' show substitute;
@@ -44,6 +47,8 @@
 
 import 'package:kernel/type_environment.dart' show TypeEnvironment;
 
+import 'package:kernel/verifier.dart' show verifyGetStaticType;
+
 import '../../api_prototype/file_system.dart' show FileSystem;
 
 import '../builder/builder.dart';
@@ -559,8 +564,9 @@
     List<DartType> typeParameterTypes = new List<DartType>();
     for (int i = 0; i < enclosingClass.typeParameters.length; i++) {
       TypeParameter typeParameter = enclosingClass.typeParameters[i];
-      typeParameterTypes
-          .add(new TypeParameterType(typeParameter, Nullability.legacy));
+      typeParameterTypes.add(
+          new TypeParameterType.withDefaultNullabilityForLibrary(
+              typeParameter, enclosingClass.enclosingLibrary));
     }
     return new InterfaceType(
         enclosingClass, Nullability.legacy, typeParameterTypes);
@@ -835,6 +841,12 @@
   void verify() {
     // TODO(ahe): How to handle errors.
     verifyComponent(component);
+    ClassHierarchy hierarchy = new ClassHierarchy(component,
+        onAmbiguousSupertypes: (Class cls, Supertype a, Supertype b) {
+      // An error has already been reported.
+    });
+    verifyGetStaticType(
+        new TypeEnvironment(loader.coreTypes, hierarchy), component);
     ticker.logMs("Verified component");
   }
 
@@ -866,6 +878,10 @@
       }
     }
   }
+
+  void releaseAncillaryResources() {
+    component = null;
+  }
 }
 
 /// Looks for a constructor call that matches `super()` from a constructor in
diff --git a/pkg/front_end/lib/src/fasta/kernel/late_lowering.dart b/pkg/front_end/lib/src/fasta/kernel/late_lowering.dart
new file mode 100644
index 0000000..02f87f8
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/kernel/late_lowering.dart
@@ -0,0 +1,222 @@
+// 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.
+
+import 'package:kernel/ast.dart' hide MapEntry;
+
+import '../names.dart';
+
+Statement createGetterWithInitializer(
+    int fileOffset, String name, DartType type, Expression initializer,
+    {Expression createVariableRead(),
+    Expression createVariableWrite(Expression value),
+    Expression createIsSetRead(),
+    Expression createIsSetWrite(Expression value)}) {
+  if (type.isPotentiallyNullable) {
+    // Generate:
+    //
+    //    if (!_#isSet#field) {
+    //      _#isSet#field = true
+    //      _#field = <init>;
+    //    }
+    //    return _#field;
+    return new Block(<Statement>[
+      new IfStatement(
+          new Not(createIsSetRead()..fileOffset = fileOffset)
+            ..fileOffset = fileOffset,
+          new Block(<Statement>[
+            new ExpressionStatement(
+                createIsSetWrite(new BoolLiteral(true)..fileOffset = fileOffset)
+                  ..fileOffset = fileOffset)
+              ..fileOffset = fileOffset,
+            new ExpressionStatement(
+                createVariableWrite(initializer)..fileOffset = fileOffset)
+              ..fileOffset = fileOffset,
+          ]),
+          null)
+        ..fileOffset = fileOffset,
+      new ReturnStatement(createVariableRead()..fileOffset = fileOffset)
+        ..fileOffset = fileOffset
+    ])
+      ..fileOffset = fileOffset;
+  } else {
+    // Generate:
+    //
+    //    return let # = _#field in # == null ? _#field = <init> : #;
+    VariableDeclaration variable = new VariableDeclaration.forValue(
+        createVariableRead()..fileOffset = fileOffset,
+        type: type.withNullability(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;
+  }
+}
+
+Statement createGetterBodyWithoutInitializer(
+    int fileOffset, String name, DartType type, String variableKindName,
+    {Expression createVariableRead(), Expression createIsSetRead()}) {
+  Expression exception = new Throw(
+      new StringLiteral("$variableKindName '${name}' has not been initialized.")
+        ..fileOffset = fileOffset)
+    ..fileOffset = fileOffset;
+  if (type.isPotentiallyNullable) {
+    // Generate:
+    //
+    //    return _#isSet#field ? _#field : throw '...';
+    return new ReturnStatement(
+        new ConditionalExpression(createIsSetRead()..fileOffset = fileOffset,
+            createVariableRead()..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.withNullability(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;
+  }
+}
+
+Statement createSetterBody(
+    int fileOffset, String name, VariableDeclaration parameter, DartType type,
+    {bool shouldReturnValue,
+    Expression createVariableWrite(Expression value),
+    Expression createIsSetWrite(Expression value)}) {
+  Statement createReturn(Expression value) {
+    if (shouldReturnValue) {
+      return new ReturnStatement(value)..fileOffset = fileOffset;
+    } else {
+      return new ExpressionStatement(value)..fileOffset = fileOffset;
+    }
+  }
+
+  Statement assignment = createReturn(
+      createVariableWrite(new VariableGet(parameter)..fileOffset = fileOffset)
+        ..fileOffset = fileOffset);
+
+  if (type.isPotentiallyNullable) {
+    // 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;
+  }
+}
+
+Statement createSetterBodyFinal(int fileOffset, String name,
+    VariableDeclaration parameter, DartType type, String variableKindName,
+    {bool shouldReturnValue,
+    Expression createVariableRead(),
+    Expression createVariableWrite(Expression value),
+    Expression createIsSetRead(),
+    Expression createIsSetWrite(Expression value)}) {
+  Expression exception = new Throw(
+      new StringLiteral(
+          "${variableKindName} '${name}' has already been initialized.")
+        ..fileOffset = fileOffset)
+    ..fileOffset = fileOffset;
+
+  Statement createReturn(Expression value) {
+    if (shouldReturnValue) {
+      return new ReturnStatement(value)..fileOffset = fileOffset;
+    } else {
+      return new ExpressionStatement(value)..fileOffset = fileOffset;
+    }
+  }
+
+  if (type.isPotentiallyNullable) {
+    // 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;
+  } 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;
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/kernel/redirecting_factory_body.dart b/pkg/front_end/lib/src/fasta/kernel/redirecting_factory_body.dart
index e56558a..5added1 100644
--- a/pkg/front_end/lib/src/fasta/kernel/redirecting_factory_body.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/redirecting_factory_body.dart
@@ -14,7 +14,6 @@
         Let,
         Member,
         NullLiteral,
-        Nullability,
         Procedure,
         StaticGet,
         StringLiteral,
@@ -136,8 +135,8 @@
   List<DartType> typeArguments = <DartType>[]..length =
       member.function.typeParameters.length;
   for (int i = 0; i < typeArguments.length; i++) {
-    typeArguments[i] = new TypeParameterType(
-        member.function.typeParameters[i], Nullability.legacy);
+    typeArguments[i] = new TypeParameterType.withDefaultNullabilityForLibrary(
+        member.function.typeParameters[i], member.enclosingLibrary);
   }
 
   // We use the [tortoise and hare algorithm]
diff --git a/pkg/front_end/lib/src/fasta/kernel/transform_collections.dart b/pkg/front_end/lib/src/fasta/kernel/transform_collections.dart
index 369a2d3..e8ce83d 100644
--- a/pkg/front_end/lib/src/fasta/kernel/transform_collections.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/transform_collections.dart
@@ -24,6 +24,7 @@
         IfStatement,
         InterfaceType,
         Let,
+        Library,
         ListConcatenation,
         ListLiteral,
         MapConcatenation,
@@ -32,7 +33,6 @@
         MethodInvocation,
         Name,
         Not,
-        Nullability,
         NullLiteral,
         Procedure,
         PropertyGet,
@@ -85,6 +85,12 @@
   final Field mapEntryValue;
   final SourceLoaderDataForTesting dataForTesting;
 
+  /// Library that contains the transformed nodes.
+  ///
+  /// The transformation of the nodes is affected by the NNBD opt-in status of
+  /// the library.
+  Library _currentLibrary;
+
   static Procedure _findSetFactory(CoreTypes coreTypes) {
     Procedure factory = coreTypes.index.getMember('dart:core', 'Set', '');
     RedirectingFactoryBody body = factory?.function?.body;
@@ -132,13 +138,13 @@
           new StaticInvocation(
               setFactory, new Arguments([], types: [elementType])),
           type: new InterfaceType(
-              coreTypes.setClass, Nullability.legacy, [elementType]),
+              coreTypes.setClass, _currentLibrary.nonNullable, [elementType]),
           isFinal: true);
     } else {
       result = new VariableDeclaration.forValue(
           new ListLiteral([], typeArgument: elementType),
           type: new InterfaceType(
-              coreTypes.listClass, Nullability.legacy, [elementType]),
+              coreTypes.listClass, _currentLibrary.nonNullable, [elementType]),
           isFinal: true);
     }
     List<Statement> body = [result];
@@ -335,7 +341,7 @@
     // Build a block expression and create an empty map.
     VariableDeclaration result = new VariableDeclaration.forValue(
         new MapLiteral([], keyType: node.keyType, valueType: node.valueType),
-        type: new InterfaceType(coreTypes.mapClass, Nullability.legacy,
+        type: new InterfaceType(coreTypes.mapClass, _currentLibrary.nonNullable,
             [node.keyType, node.valueType]),
         isFinal: true);
     List<Statement> body = [result];
@@ -448,14 +454,16 @@
     }
 
     DartType entryType = new InterfaceType(
-        mapEntryClass, Nullability.legacy, <DartType>[keyType, valueType]);
+        mapEntryClass,
+        _currentLibrary.nullableIfTrue(entry.isNullAware),
+        <DartType>[keyType, valueType]);
     VariableDeclaration elt;
     Statement loopBody;
     if (entry.entryType == null ||
         !typeEnvironment.isSubtypeOf(entry.entryType, entryType,
             SubtypeCheckMode.ignoringNullabilities)) {
       elt = new VariableDeclaration(null,
-          type: new InterfaceType(mapEntryClass, Nullability.legacy,
+          type: new InterfaceType(mapEntryClass, _currentLibrary.nonNullable,
               <DartType>[const DynamicType(), const DynamicType()]),
           isFinal: true);
       VariableDeclaration keyVar = new VariableDeclaration.forValue(
@@ -653,4 +661,18 @@
     return new MapConcatenation(parts,
         keyType: node.keyType, valueType: node.valueType);
   }
+
+  void enterLibrary(Library library) {
+    assert(
+        _currentLibrary == null,
+        "Attempting to enter library '${library.fileUri}' "
+        "without having exited library '${_currentLibrary.fileUri}'.");
+    _currentLibrary = library;
+  }
+
+  void exitLibrary() {
+    assert(_currentLibrary != null,
+        "Attempting to exit a library without having entered one.");
+    _currentLibrary = null;
+  }
 }
diff --git a/pkg/front_end/lib/src/fasta/kernel/transform_set_literals.dart b/pkg/front_end/lib/src/fasta/kernel/transform_set_literals.dart
index 0a61069..7b3a8de 100644
--- a/pkg/front_end/lib/src/fasta/kernel/transform_set_literals.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/transform_set_literals.dart
@@ -12,9 +12,9 @@
         Expression,
         InterfaceType,
         Let,
+        Library,
         MethodInvocation,
         Name,
-        Nullability,
         Procedure,
         SetLiteral,
         StaticInvocation,
@@ -36,6 +36,12 @@
   final Procedure setFactory;
   final Procedure addMethod;
 
+  /// Library that contains the transformed nodes.
+  ///
+  /// The transformation of the nodes is affected by the NNBD opt-in status of
+  /// the library.
+  Library _currentLibrary;
+
   static Procedure _findSetFactory(CoreTypes coreTypes) {
     Procedure factory = coreTypes.index.getMember('dart:core', 'Set', '');
     RedirectingFactoryBody body = factory?.function?.body;
@@ -58,8 +64,8 @@
     VariableDeclaration setVar = new VariableDeclaration.forValue(
         new StaticInvocation(
             setFactory, new Arguments([], types: [node.typeArgument])),
-        type: new InterfaceType(
-            coreTypes.setClass, Nullability.legacy, [node.typeArgument]));
+        type: new InterfaceType(coreTypes.setClass, _currentLibrary.nonNullable,
+            [node.typeArgument]));
     // Innermost body of let chain: setVar
     Expression setExp = new VariableGet(setVar);
     for (int i = node.expressions.length - 1; i >= 0; i--) {
@@ -75,4 +81,18 @@
     }
     return new Let(setVar, setExp);
   }
+
+  void enterLibrary(Library library) {
+    assert(
+        _currentLibrary == null,
+        "Attempting to enter library '${library.fileUri}' "
+        "without having exited library '${_currentLibrary.fileUri}'.");
+    _currentLibrary = library;
+  }
+
+  void exitLibrary() {
+    assert(_currentLibrary != null,
+        "Attempting to exit a library without having entered one.");
+    _currentLibrary = null;
+  }
 }
diff --git a/pkg/front_end/lib/src/fasta/kernel/types.dart b/pkg/front_end/lib/src/fasta/kernel/types.dart
index 37a3272..5f75c6d 100644
--- a/pkg/front_end/lib/src/fasta/kernel/types.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/types.dart
@@ -38,15 +38,6 @@
 
   /// Returns true if [s] is a subtype of [t].
   bool isSubtypeOfKernel(DartType s, DartType t, SubtypeCheckMode mode) {
-    // TODO(dmitryas): Remove InvalidType from subtype relation.
-    if (s is InvalidType) {
-      // InvalidType is a bottom type.
-      return true;
-    }
-    if (t is InvalidType) {
-      return false;
-    }
-
     IsSubtypeOf result = performNullabilityAwareSubtypeCheck(s, t);
     switch (mode) {
       case SubtypeCheckMode.withNullabilities:
@@ -75,6 +66,16 @@
     if (s is NeverType) {
       return new IsSubtypeOf.basedSolelyOnNullabilities(s, t);
     }
+
+    // TODO(dmitryas): Remove InvalidType from subtype relation.
+    if (s is InvalidType) {
+      // InvalidType is a bottom type.
+      return const IsSubtypeOf.always();
+    }
+    if (t is InvalidType) {
+      return const IsSubtypeOf.never();
+    }
+
     if (t is InterfaceType) {
       Class cls = t.classNode;
       if (cls == hierarchy.objectClass &&
@@ -275,8 +276,7 @@
       hierarchy.coreTypes.functionLegacyRawType;
 
   @override
-  InterfaceType futureType(DartType type,
-      [Nullability nullability = Nullability.legacy]) {
+  InterfaceType futureType(DartType type, Nullability nullability) {
     return new InterfaceType(
         hierarchy.coreTypes.futureClass, nullability, <DartType>[type]);
   }
@@ -440,8 +440,8 @@
         TypeParameter tTypeVariable = tTypeVariables[i];
         result = result.and(
             types.isSameTypeKernel(sTypeVariable.bound, tTypeVariable.bound));
-        typeVariableSubstitution.add(new TypeParameterType(tTypeVariable,
-            TypeParameterType.computeNullabilityFromBound(tTypeVariable)));
+        typeVariableSubstitution.add(new TypeParameterType.forAlphaRenaming(
+            sTypeVariable, tTypeVariable));
       }
       Substitution substitution =
           Substitution.fromPairs(sTypeVariables, typeVariableSubstitution);
diff --git a/pkg/front_end/lib/src/fasta/kernel/utils.dart b/pkg/front_end/lib/src/fasta/kernel/utils.dart
index c24a87a..86b1ee5 100644
--- a/pkg/front_end/lib/src/fasta/kernel/utils.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/utils.dart
@@ -16,7 +16,6 @@
         Component,
         DartType,
         Library,
-        Nullability,
         Procedure,
         Supertype,
         TreeNode,
@@ -98,7 +97,7 @@
         ..parent = fakeClass;
       typeParams[typeParam] = newNode;
       typeSubstitution[typeParam] =
-          new TypeParameterType(newNode, Nullability.legacy);
+          new TypeParameterType.forAlphaRenaming(typeParam, newNode);
     }
     CloneVisitor cloner = new CloneVisitor(
         typeSubstitution: typeSubstitution, typeParams: typeParams);
diff --git a/pkg/front_end/lib/src/fasta/scope.dart b/pkg/front_end/lib/src/fasta/scope.dart
index 1fb9f37..c564753 100644
--- a/pkg/front_end/lib/src/fasta/scope.dart
+++ b/pkg/front_end/lib/src/fasta/scope.dart
@@ -14,6 +14,7 @@
 import 'builder/name_iterator.dart';
 import 'builder/type_variable_builder.dart';
 import 'kernel/body_builder.dart' show JumpTarget;
+import 'kernel/class_hierarchy_builder.dart' show ClassMember;
 
 import 'fasta_codes.dart'
     show
@@ -644,14 +645,10 @@
   }
 
   @override
-  void inferType() {
-    throw new UnsupportedError('AmbiguousMemberBuilder.inferType');
-  }
+  List<ClassMember> get localMembers => const <ClassMember>[];
 
   @override
-  void inferCopiedType(covariant Object other) {
-    throw new UnsupportedError('AmbiguousMemberBuilder.inferCopiedType');
-  }
+  List<ClassMember> get localSetters => const <ClassMember>[];
 }
 
 class ScopeLocalDeclarationIterator implements Iterator<Builder> {
diff --git a/pkg/front_end/lib/src/fasta/source/diet_listener.dart b/pkg/front_end/lib/src/fasta/source/diet_listener.dart
index ade334e..12309a5 100644
--- a/pkg/front_end/lib/src/fasta/source/diet_listener.dart
+++ b/pkg/front_end/lib/src/fasta/source/diet_listener.dart
@@ -765,7 +765,7 @@
     checkEmpty(token.charOffset);
     if (names == null || currentClassIsParserRecovery) return;
 
-    FieldBuilderImpl declaration = lookupBuilder(token, null, names.first);
+    SourceFieldBuilder declaration = lookupBuilder(token, null, names.first);
     // TODO(paulberry): don't re-parse the field if we've already parsed it
     // for type inference.
     parseFields(
diff --git a/pkg/front_end/lib/src/fasta/source/outline_builder.dart b/pkg/front_end/lib/src/fasta/source/outline_builder.dart
index b27bedc..38b82ea 100644
--- a/pkg/front_end/lib/src/fasta/source/outline_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/outline_builder.dart
@@ -56,6 +56,7 @@
         messageInterpolationInUri,
         messageOperatorWithOptionalFormals,
         messageTypedefNotFunction,
+        messageTypedefNotType,
         Template,
         templateCycleInTypeVariables,
         templateDirectCycleInTypeVariables,
@@ -1440,7 +1441,7 @@
     List<TypeVariableBuilder> typeVariables;
     Object name;
     int charOffset;
-    FunctionTypeBuilder functionType;
+    TypeBuilder aliasedType;
     if (equals == null) {
       List<FormalParameterBuilder> formals = pop();
       pop(); // formals offset
@@ -1460,7 +1461,7 @@
           TypeParameterScopeKind.functionType, "#function_type",
           hasMembers: false);
       // TODO(dmitryas): Make sure that RHS of typedefs can't have '?'.
-      functionType = library.addFunctionType(returnType, null, formals,
+      aliasedType = library.addFunctionType(returnType, null, formals,
           const NullabilityBuilder.omitted(), charOffset);
     } else {
       Object type = pop();
@@ -1479,7 +1480,13 @@
         // `type.typeVariables`. A typedef can have type variables, and a new
         // function type can also have type variables (representing the type of
         // a generic function).
-        functionType = type;
+        aliasedType = type;
+      } else if (library.loader.target.enableNonfunctionTypeAliases) {
+        if (type is TypeBuilder) {
+          aliasedType = type;
+        } else {
+          addProblem(messageTypedefNotType, equals.charOffset, equals.length);
+        }
       } else {
         // TODO(ahe): Improve this error message.
         addProblem(messageTypedefNotFunction, equals.charOffset, equals.length);
@@ -1488,7 +1495,7 @@
     List<MetadataBuilder> metadata = pop();
     checkEmpty(typedefKeyword.charOffset);
     library.addFunctionTypeAlias(documentationComment, metadata, name,
-        typeVariables, functionType, charOffset);
+        typeVariables, aliasedType, charOffset);
   }
 
   @override
diff --git a/pkg/front_end/lib/src/fasta/source/source_extension_builder.dart b/pkg/front_end/lib/src/fasta/source/source_extension_builder.dart
index b5b5959..3bd7bae 100644
--- a/pkg/front_end/lib/src/fasta/source/source_extension_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_extension_builder.dart
@@ -116,15 +116,18 @@
                       declaration.fileUri);
                   break;
                 case BuiltMemberKind.ExtensionField:
+                case BuiltMemberKind.LateIsSetField:
                   kind = ExtensionMemberKind.Field;
                   break;
                 case BuiltMemberKind.ExtensionMethod:
                   kind = ExtensionMemberKind.Method;
                   break;
                 case BuiltMemberKind.ExtensionGetter:
+                case BuiltMemberKind.LateGetter:
                   kind = ExtensionMemberKind.Getter;
                   break;
                 case BuiltMemberKind.ExtensionSetter:
+                case BuiltMemberKind.LateSetter:
                   kind = ExtensionMemberKind.Setter;
                   break;
                 case BuiltMemberKind.ExtensionOperator:
diff --git a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
index 739d4fb..20b52a4 100644
--- a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
@@ -145,7 +145,6 @@
         templateIncorrectTypeArgumentInferred,
         templateIncorrectTypeArgumentQualified,
         templateIncorrectTypeArgumentQualifiedInferred,
-        templateIntersectionTypeAsTypeArgument,
         templateLanguageVersionTooHigh,
         templateLoadLibraryHidesMember,
         templateLocalDefinitionHidesExport,
@@ -171,7 +170,7 @@
         compareProcedures,
         toKernelCombinators;
 
-import '../kernel/kernel_shadow_ast.dart';
+import '../kernel/internal_ast.dart';
 
 import '../kernel/metadata_collector.dart';
 
@@ -214,12 +213,14 @@
 
 // TODO(johnniwinther,jensj): Replace this with the correct scheme.
 const int enableNonNullableDefaultMajorVersion = 2;
-const int enableNonNullableDefaultMinorVersion = 6;
+const int enableNonNullableDefaultMinorVersion = 7;
 
 class SourceLibraryBuilder extends LibraryBuilderImpl {
   static const String MALFORMED_URI_SCHEME = "org-dartlang-malformed-uri";
 
-  final SourceLoader loader;
+  SourceLoader loader;
+
+  bool issueLexicalErrorsOnBodyBuild = false;
 
   final TypeParameterScopeBuilder libraryDeclaration;
 
@@ -346,7 +347,9 @@
       this._nameOrigin)
       : currentTypeParameterScopeBuilder = libraryDeclaration,
         super(
-            fileUri, libraryDeclaration.toScope(importScope), new Scope.top());
+            fileUri, libraryDeclaration.toScope(importScope), new Scope.top()) {
+    library.isNonNullableByDefault = isNonNullableByDefault;
+  }
 
   SourceLibraryBuilder(
       Uri uri, Uri fileUri, Loader loader, SourceLibraryBuilder actualOrigin,
@@ -1783,14 +1786,14 @@
     if (hasInitializer) {
       modifiers |= hasInitializerMask;
     }
-    FieldBuilderImpl fieldBuilder = new FieldBuilderImpl(
+    SourceFieldBuilder fieldBuilder = new SourceFieldBuilder(
         metadata, type, name, modifiers, this, charOffset, charEndOffset);
     fieldBuilder.constInitializerToken = constInitializerToken;
     addBuilder(name, fieldBuilder, charOffset);
     if (type == null && initializerToken != null && fieldBuilder.next == null) {
       // Only the first one (the last one in the linked list of next pointers)
       // are added to the tree, had parent pointers and can infer correctly.
-      fieldBuilder.field.type =
+      fieldBuilder.fieldType =
           new ImplicitFieldType(fieldBuilder, initializerToken);
       (implicitlyTypedFields ??= <FieldBuilder>[]).add(fieldBuilder);
     }
@@ -2006,7 +2009,7 @@
       List<MetadataBuilder> metadata,
       String name,
       List<TypeVariableBuilder> typeVariables,
-      FunctionTypeBuilder type,
+      TypeBuilder type,
       int charOffset) {
     if (typeVariables != null) {
       for (TypeVariableBuilder typeVariable in typeVariables) {
@@ -2618,15 +2621,6 @@
           message = messageGenericFunctionTypeUsedAsActualTypeArgument;
         }
         typeParameter = null;
-      } else if (argument is TypeParameterType &&
-          argument.promotedBound != null) {
-        addProblem(
-            templateIntersectionTypeAsTypeArgument.withArguments(
-                typeParameter.name, argument, argument.promotedBound),
-            offset,
-            noLength,
-            fileUri);
-        continue;
       } else {
         if (issue.enclosingType == null && targetReceiver != null) {
           if (issueInferred) {
@@ -2805,8 +2799,8 @@
     if (node.arguments.types.isEmpty) return;
     Constructor constructor = node.target;
     Class klass = constructor.enclosingClass;
-    DartType constructedType =
-        new InterfaceType(klass, Nullability.legacy, node.arguments.types);
+    DartType constructedType = new InterfaceType(
+        klass, klass.enclosingLibrary.nonNullable, node.arguments.types);
     checkBoundsInType(
         constructedType, typeEnvironment, fileUri, node.fileOffset,
         inferred: inferred, allowSuperBounded: false);
@@ -2819,8 +2813,8 @@
     Procedure factory = node.target;
     assert(factory.isFactory);
     Class klass = factory.enclosingClass;
-    DartType constructedType =
-        new InterfaceType(klass, Nullability.legacy, node.arguments.types);
+    DartType constructedType = new InterfaceType(
+        klass, klass.enclosingLibrary.nonNullable, node.arguments.types);
     checkBoundsInType(
         constructedType, typeEnvironment, fileUri, node.fileOffset,
         inferred: inferred, allowSuperBounded: false);
@@ -2845,7 +2839,8 @@
     if (issues != null) {
       DartType targetReceiver;
       if (klass != null) {
-        targetReceiver = new InterfaceType(klass, Nullability.legacy);
+        targetReceiver =
+            new InterfaceType(klass, klass.enclosingLibrary.nonNullable);
       }
       String targetName = node.target.name.name;
       reportTypeArgumentIssues(issues, fileUri, node.fileOffset,
@@ -2897,8 +2892,9 @@
     for (int i = 0; i < instantiatedMethodParameters.length; ++i) {
       instantiatedMethodParameters[i] =
           new TypeParameter(methodParameters[i].name);
-      substitutionMap[methodParameters[i]] = new TypeParameterType(
-          instantiatedMethodParameters[i], Nullability.legacy);
+      substitutionMap[methodParameters[i]] =
+          new TypeParameterType.forAlphaRenaming(
+              methodParameters[i], instantiatedMethodParameters[i]);
     }
     for (int i = 0; i < instantiatedMethodParameters.length; ++i) {
       instantiatedMethodParameters[i].bound =
diff --git a/pkg/front_end/lib/src/fasta/source/source_loader.dart b/pkg/front_end/lib/src/fasta/source/source_loader.dart
index 085b89a..874292a 100644
--- a/pkg/front_end/lib/src/fasta/source/source_loader.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_loader.dart
@@ -302,7 +302,10 @@
       // We tokenize source files twice to keep memory usage low. This is the
       // second time, and the first time was in [buildOutline] above. So this
       // time we suppress lexical errors.
-      Token tokens = await tokenize(library, suppressLexicalErrors: true);
+      bool suppressLexicalErrors = true;
+      if (library.issueLexicalErrorsOnBodyBuild) suppressLexicalErrors = false;
+      Token tokens =
+          await tokenize(library, suppressLexicalErrors: suppressLexicalErrors);
       if (tokens == null) return;
       DietListener listener = createDietListener(library);
       DietParser parser = new DietParser(listener);
@@ -1043,31 +1046,44 @@
     ticker.logMs("Performed top level inference");
   }
 
-  void transformPostInference(
-      TreeNode node, bool transformSetLiterals, bool transformCollections) {
+  void transformPostInference(TreeNode node, bool transformSetLiterals,
+      bool transformCollections, Library clientLibrary) {
     if (transformCollections) {
-      node.accept(collectionTransformer ??= new CollectionTransformer(this));
+      collectionTransformer ??= new CollectionTransformer(this);
+      collectionTransformer.enterLibrary(clientLibrary);
+      node.accept(collectionTransformer);
+      collectionTransformer.exitLibrary();
     }
     if (transformSetLiterals) {
-      node.accept(setLiteralTransformer ??= new SetLiteralTransformer(this));
+      setLiteralTransformer ??= new SetLiteralTransformer(this);
+      setLiteralTransformer.enterLibrary(clientLibrary);
+      node.accept(setLiteralTransformer);
+      setLiteralTransformer.exitLibrary();
     }
   }
 
-  void transformListPostInference(List<TreeNode> list,
-      bool transformSetLiterals, bool transformCollections) {
+  void transformListPostInference(
+      List<TreeNode> list,
+      bool transformSetLiterals,
+      bool transformCollections,
+      Library clientLibrary) {
     if (transformCollections) {
       CollectionTransformer transformer =
           collectionTransformer ??= new CollectionTransformer(this);
+      transformer.enterLibrary(clientLibrary);
       for (int i = 0; i < list.length; ++i) {
         list[i] = list[i].accept(transformer);
       }
+      transformer.exitLibrary();
     }
     if (transformSetLiterals) {
       SetLiteralTransformer transformer =
           setLiteralTransformer ??= new SetLiteralTransformer(this);
+      transformer.enterLibrary(clientLibrary);
       for (int i = 0; i < list.length; ++i) {
         list[i] = list[i].accept(transformer);
       }
+      transformer.exitLibrary();
     }
   }
 
@@ -1105,7 +1121,17 @@
 
   void releaseAncillaryResources() {
     hierarchy = null;
+    builderHierarchy = null;
     typeInferenceEngine = null;
+    builders?.clear();
+    libraries?.clear();
+    first = null;
+    sourceBytes?.clear();
+    target?.releaseAncillaryResources();
+    coreTypes = null;
+    instrumentation = null;
+    collectionTransformer = null;
+    setLiteralTransformer = null;
   }
 
   @override
diff --git a/pkg/front_end/lib/src/fasta/target_implementation.dart b/pkg/front_end/lib/src/fasta/target_implementation.dart
index 7ff4363..160d2bb 100644
--- a/pkg/front_end/lib/src/fasta/target_implementation.dart
+++ b/pkg/front_end/lib/src/fasta/target_implementation.dart
@@ -52,6 +52,7 @@
   bool enableNonNullable;
   bool enableTripleShift;
   bool enableVariance;
+  bool enableNonfunctionTypeAliases;
 
   TargetImplementation(Ticker ticker, this.uriTranslator, this.backendTarget)
       : enableExtensionMethods = CompilerContext.current.options
@@ -62,6 +63,8 @@
             .isExperimentEnabled(ExperimentalFlag.tripleShift),
         enableVariance = CompilerContext.current.options
             .isExperimentEnabled(ExperimentalFlag.variance),
+        enableNonfunctionTypeAliases = CompilerContext.current.options
+            .isExperimentEnabled(ExperimentalFlag.nonfunctionTypeAliases),
         super(ticker);
 
   /// Creates a [LibraryBuilder] corresponding to [uri], if one doesn't exist
@@ -191,4 +194,6 @@
       throw new StateError("Unparsable sdk version given: $currentSdkVersion");
     }
   }
+
+  void releaseAncillaryResources();
 }
diff --git a/pkg/front_end/lib/src/fasta/type_inference/replacement_visitor.dart b/pkg/front_end/lib/src/fasta/type_inference/replacement_visitor.dart
new file mode 100644
index 0000000..ddcfb58
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/type_inference/replacement_visitor.dart
@@ -0,0 +1,124 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE.md file.
+
+import 'package:kernel/ast.dart' hide MapEntry;
+
+/// Helper visitor that clones a type if a nested type is replaced, and
+/// otherwise returns `null`.
+class ReplacementVisitor implements DartTypeVisitor<DartType> {
+  const ReplacementVisitor();
+
+  void changeVariance() {}
+
+  @override
+  DartType visitFunctionType(FunctionType node) {
+    DartType newReturnType = node.returnType.accept(this);
+    changeVariance();
+    List<DartType> newPositionalParameters = null;
+    for (int i = 0; i < node.positionalParameters.length; i++) {
+      DartType substitution = node.positionalParameters[i].accept(this);
+      if (substitution != null) {
+        newPositionalParameters ??=
+            node.positionalParameters.toList(growable: false);
+        newPositionalParameters[i] = substitution;
+      }
+    }
+    List<NamedType> newNamedParameters = null;
+    for (int i = 0; i < node.namedParameters.length; i++) {
+      DartType substitution = node.namedParameters[i].type.accept(this);
+      if (substitution != null) {
+        newNamedParameters ??= node.namedParameters.toList(growable: false);
+        newNamedParameters[i] = new NamedType(
+            node.namedParameters[i].name, substitution,
+            isRequired: node.namedParameters[i].isRequired);
+      }
+    }
+    changeVariance();
+    DartType typedefType = node.typedefType?.accept(this);
+    if (newReturnType == null &&
+        newPositionalParameters == null &&
+        newNamedParameters == null &&
+        typedefType == null) {
+      // No types had to be substituted.
+      return null;
+    } else {
+      return new FunctionType(
+          newPositionalParameters ?? node.positionalParameters,
+          newReturnType ?? node.returnType,
+          node.nullability,
+          namedParameters: newNamedParameters ?? node.namedParameters,
+          typeParameters: node.typeParameters,
+          requiredParameterCount: node.requiredParameterCount,
+          typedefType: typedefType);
+    }
+  }
+
+  @override
+  DartType visitInterfaceType(InterfaceType node) {
+    List<DartType> newTypeArguments = null;
+    for (int i = 0; i < node.typeArguments.length; i++) {
+      DartType substitution = node.typeArguments[i].accept(this);
+      if (substitution != null) {
+        newTypeArguments ??= node.typeArguments.toList(growable: false);
+        newTypeArguments[i] = substitution;
+      }
+    }
+    if (newTypeArguments == null) {
+      // No type arguments needed to be substituted.
+      return null;
+    } else {
+      return new InterfaceType(
+          node.classNode, node.nullability, newTypeArguments);
+    }
+  }
+
+  @override
+  DartType visitDynamicType(DynamicType node) => null;
+
+  @override
+  DartType visitNeverType(NeverType node) => null;
+
+  @override
+  DartType visitInvalidType(InvalidType node) => null;
+
+  @override
+  DartType visitBottomType(BottomType node) => null;
+
+  @override
+  DartType visitVoidType(VoidType node) => null;
+
+  @override
+  DartType visitTypeParameterType(TypeParameterType node) {
+    if (node.promotedBound != null) {
+      DartType newPromotedBound = node.promotedBound.accept(this);
+      if (newPromotedBound != null) {
+        return new TypeParameterType(node.parameter,
+            node.typeParameterTypeNullability, newPromotedBound);
+      }
+    }
+    return null;
+  }
+
+  @override
+  DartType visitTypedefType(TypedefType node) {
+    List<DartType> newTypeArguments = null;
+    for (int i = 0; i < node.typeArguments.length; i++) {
+      DartType substitution = node.typeArguments[i].accept(this);
+      if (substitution != null) {
+        newTypeArguments ??= node.typeArguments.toList(growable: false);
+        newTypeArguments[i] = substitution;
+      }
+    }
+    if (newTypeArguments == null) {
+      // No type arguments needed to be substituted.
+      return null;
+    } else {
+      return new TypedefType(
+          node.typedefNode, node.nullability, newTypeArguments);
+    }
+  }
+
+  @override
+  DartType defaultDartType(DartType node) => null;
+}
diff --git a/pkg/front_end/lib/src/fasta/type_inference/standard_bounds.dart b/pkg/front_end/lib/src/fasta/type_inference/standard_bounds.dart
index 6b1f45a..67147c8 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/standard_bounds.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/standard_bounds.dart
@@ -14,7 +14,6 @@
         InterfaceType,
         InvalidType,
         NamedType,
-        Nullability,
         TypeParameter,
         TypeParameterType,
         Variance,
@@ -24,6 +23,8 @@
 
 import 'package:kernel/type_environment.dart' show SubtypeCheckMode;
 
+import 'package:kernel/src/future_or.dart';
+
 import 'type_schema.dart' show UnknownType;
 
 abstract class StandardBounds {
@@ -111,18 +112,22 @@
       if (type2 is InterfaceType) {
         if (type2.classNode == futureOrClass) {
           // GLB(FutureOr<A>, FutureOr<B>) == FutureOr<GLB(A, B)>
+          DartType argument = getStandardLowerBound(
+              type1.typeArguments[0], type2.typeArguments[0]);
           return new InterfaceType(
-              futureOrClass, Nullability.legacy, <DartType>[
-            getStandardLowerBound(
-                type1.typeArguments[0], type2.typeArguments[0])
-          ]);
+              futureOrClass, argument.nullability, <DartType>[argument]);
         }
         if (type2.classNode == futureClass) {
           // GLB(FutureOr<A>, Future<B>) == Future<GLB(A, B)>
-          return new InterfaceType(futureClass, Nullability.legacy, <DartType>[
-            getStandardLowerBound(
-                type1.typeArguments[0], type2.typeArguments[0])
-          ]);
+          return new InterfaceType(
+              futureClass,
+              intersectNullabilities(
+                  computeNullabilityOfFutureOr(type1, futureOrClass),
+                  type2.nullability),
+              <DartType>[
+                getStandardLowerBound(
+                    type1.typeArguments[0], type2.typeArguments[0])
+              ]);
         }
       }
       // GLB(FutureOr<A>, B) == GLB(A, B)
@@ -136,9 +141,14 @@
     if (type2 is InterfaceType && type2.classNode == futureOrClass) {
       if (type1 is InterfaceType && type1.classNode == futureClass) {
         // GLB(Future<A>, FutureOr<B>) == Future<GLB(B, A)>
-        return new InterfaceType(futureClass, Nullability.legacy, <DartType>[
-          getStandardLowerBound(type2.typeArguments[0], type1.typeArguments[0])
-        ]);
+        return new InterfaceType(
+            futureClass,
+            intersectNullabilities(type1.nullability,
+                computeNullabilityOfFutureOr(type2, futureOrClass)),
+            <DartType>[
+              getStandardLowerBound(
+                  type2.typeArguments[0], type1.typeArguments[0])
+            ]);
       }
       // GLB(A, FutureOr<B>) == GLB(B, A)
       return getStandardLowerBound(type2.typeArguments[0], type1);
@@ -317,8 +327,8 @@
 
     // Calculate the SLB of the return type.
     DartType returnType = getStandardLowerBound(f.returnType, g.returnType);
-    return new FunctionType(
-        positionalParameters, returnType, Nullability.legacy,
+    return new FunctionType(positionalParameters, returnType,
+        intersectNullabilities(f.nullability, g.nullability),
         namedParameters: namedParameters,
         requiredParameterCount: requiredParameterCount);
   }
@@ -345,7 +355,9 @@
     //   SUB(([int]) -> void, (int) -> void) = (int) -> void
     if (f.requiredParameterCount != g.requiredParameterCount) {
       return new InterfaceType(
-          functionClass, Nullability.legacy, const <DynamicType>[]);
+          functionClass,
+          uniteNullabilities(f.nullability, g.nullability),
+          const <DynamicType>[]);
     }
     int requiredParameterCount = f.requiredParameterCount;
 
@@ -392,8 +404,8 @@
 
     // Calculate the SUB of the return type.
     DartType returnType = getStandardUpperBound(f.returnType, g.returnType);
-    return new FunctionType(
-        positionalParameters, returnType, Nullability.legacy,
+    return new FunctionType(positionalParameters, returnType,
+        uniteNullabilities(f.nullability, g.nullability),
         namedParameters: namedParameters,
         requiredParameterCount: requiredParameterCount);
   }
@@ -453,7 +465,8 @@
           tArgs[i] = getStandardUpperBound(tArgs1[i], tArgs2[i]);
         }
       }
-      return new InterfaceType(type1.classNode, Nullability.legacy, tArgs);
+      return new InterfaceType(type1.classNode,
+          uniteNullabilities(type1.nullability, type2.nullability), tArgs);
     }
     return getLegacyLeastUpperBound(type1, type2);
   }
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_constraint_gatherer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_constraint_gatherer.dart
index 691ecdb..c71249a 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_constraint_gatherer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_constraint_gatherer.dart
@@ -9,6 +9,7 @@
         DynamicType,
         FunctionType,
         InterfaceType,
+        Library,
         Member,
         Name,
         NamedType,
@@ -21,10 +22,11 @@
 
 import 'package:kernel/type_algebra.dart' show substitute, Substitution;
 
-import 'type_schema.dart' show UnknownType;
+import 'package:kernel/type_environment.dart';
 
-import 'type_schema_environment.dart'
-    show TypeConstraint, TypeSchemaEnvironment, substituteTypeParams;
+import 'package:kernel/src/future_or.dart';
+
+import 'type_schema.dart' show UnknownType;
 
 import '../names.dart' show callName;
 
@@ -39,14 +41,18 @@
 
   final List<TypeParameter> _parametersToConstrain;
 
+  final Library _currentLibrary;
+
   /// Creates a [TypeConstraintGatherer] which is prepared to gather type
   /// constraints for the given [typeParameters].
-  TypeConstraintGatherer.subclassing(Iterable<TypeParameter> typeParameters)
+  TypeConstraintGatherer.subclassing(
+      Iterable<TypeParameter> typeParameters, this._currentLibrary)
       : _parametersToConstrain = typeParameters.toList();
 
   factory TypeConstraintGatherer(TypeSchemaEnvironment environment,
-      Iterable<TypeParameter> typeParameters) {
-    return new TypeSchemaConstraintGatherer(environment, typeParameters);
+      Iterable<TypeParameter> typeParameters, Library currentLibrary) {
+    return new TypeSchemaConstraintGatherer(
+        environment, typeParameters, currentLibrary);
   }
 
   Class get objectClass;
@@ -298,9 +304,12 @@
       //   constraints `C0`.
       // - And `P` is a subtype match for `Q` with respect to `L` under
       //   constraints `C1`.
-      InterfaceType subtypeFuture = futureType(subtypeArg, Nullability.legacy);
+      InterfaceType subtypeFuture =
+          futureType(subtypeArg, _currentLibrary.nonNullable);
       return _isSubtypeMatch(subtypeFuture, supertype) &&
-          _isSubtypeMatch(subtypeArg, supertype);
+          _isSubtypeMatch(subtypeArg, supertype) &&
+          new IsSubtypeOf.basedSolelyOnNullabilities(subtype, supertype)
+              .isSubtypeWhenUsingNullabilities();
     }
 
     if (supertype is InterfaceType &&
@@ -313,8 +322,24 @@
       //   under constraints `C`
       //   - And `P` is a subtype match for `Q` with respect to `L` under
       //     constraints `C`
-      DartType supertypeArg = supertype.typeArguments[0];
-      DartType supertypeFuture = futureType(supertypeArg, Nullability.legacy);
+
+      // Since FutureOr<S> is a union type Future<S> U S where U denotes the
+      // union operation on types, T? is T U Null, T U T = T, S U T = T U S, and
+      // S U (T U V) = (S U T) U V, the following is true:
+      //
+      //   - FutureOr<S?> = S? U Future<S?>?
+      //   - FutureOr<S>? = S? U Future<S>?
+      //
+      // To compute the nullabilities for the two types in the union, the
+      // nullability of the argument and the declared nullability of FutureOr
+      // should be united.  Also, computeNullability is used to fetch the
+      // nullability of the argument because it can be a FutureOr itself.
+      Nullability unitedNullability = uniteNullabilities(
+          computeNullability(supertype.typeArguments[0], futureOrClass),
+          supertype.nullability);
+      DartType supertypeArg =
+          supertype.typeArguments[0].withNullability(unitedNullability);
+      DartType supertypeFuture = futureType(supertypeArg, unitedNullability);
 
       // The match against FutureOr<X> succeeds if the match against either
       // Future<X> or X succeeds.  If they both succeed, the one adding new
@@ -419,7 +444,7 @@
       TypeParameter pFresh = new TypeParameter(params2[i].name);
       freshTypeVariables.add(pFresh);
       DartType variableFresh =
-          new TypeParameterType(pFresh, Nullability.legacy);
+          new TypeParameterType.forAlphaRenaming(params2[i], pFresh);
       substitution1[params1[i]] = variableFresh;
       substitution2[params2[i]] = variableFresh;
       DartType bound1 = substitute(params1[i].bound, substitution1);
@@ -434,9 +459,9 @@
 class TypeSchemaConstraintGatherer extends TypeConstraintGatherer {
   final TypeSchemaEnvironment environment;
 
-  TypeSchemaConstraintGatherer(
-      this.environment, Iterable<TypeParameter> typeParameters)
-      : super.subclassing(typeParameters);
+  TypeSchemaConstraintGatherer(this.environment,
+      Iterable<TypeParameter> typeParameters, Library currentLibrary)
+      : super.subclassing(typeParameters, currentLibrary);
 
   @override
   Class get objectClass => environment.coreTypes.objectClass;
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_demotion.dart b/pkg/front_end/lib/src/fasta/type_inference/type_demotion.dart
new file mode 100644
index 0000000..1e67390
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_demotion.dart
@@ -0,0 +1,78 @@
+// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE.md file.
+
+import 'package:kernel/ast.dart' hide MapEntry;
+
+import 'replacement_visitor.dart';
+
+/// Returns `true` if type contains a promoted type variable.
+bool hasPromotedTypeVariable(DartType type) {
+  return type.accept(const _HasPromotedTypeVariableVisitor());
+}
+
+/// Visitor that returns `true` if a type contains a promoted type variable.
+class _HasPromotedTypeVariableVisitor extends DartTypeVisitor<bool> {
+  const _HasPromotedTypeVariableVisitor();
+
+  @override
+  bool defaultDartType(DartType node) => false;
+
+  @override
+  bool visitFunctionType(FunctionType node) {
+    if (node.returnType.accept(this)) return true;
+    for (DartType parameterType in node.positionalParameters) {
+      if (parameterType.accept(this)) return true;
+    }
+    for (NamedType namedParameterType in node.namedParameters) {
+      if (namedParameterType.type.accept(this)) return true;
+    }
+    if (node.typedefType != null && node.typedefType.accept(this)) {
+      return true;
+    }
+    return false;
+  }
+
+  @override
+  bool visitInterfaceType(InterfaceType node) {
+    for (DartType typeArgument in node.typeArguments) {
+      if (typeArgument.accept(this)) return true;
+    }
+    return false;
+  }
+
+  @override
+  bool visitTypedefType(TypedefType node) {
+    for (DartType typeArgument in node.typeArguments) {
+      if (typeArgument.accept(this)) return true;
+    }
+    return false;
+  }
+
+  @override
+  bool visitTypeParameterType(TypeParameterType node) {
+    return node.promotedBound != null;
+  }
+}
+
+/// Returns [type] in which all promoted type variables have been replace with
+/// their unpromoted equivalents.
+DartType demoteType(DartType type) {
+  return type.accept(const _TypeVariableDemotion()) ?? type;
+}
+
+/// Visitor that replaces all promoted type variables the type variable itself.
+///
+/// The visitor returns `null` if the type wasn't changed.
+class _TypeVariableDemotion extends ReplacementVisitor {
+  const _TypeVariableDemotion();
+
+  @override
+  DartType visitTypeParameterType(TypeParameterType node) {
+    if (node.promotedBound != null) {
+      return new TypeParameterType(
+          node.parameter, node.typeParameterTypeNullability);
+    }
+    return node;
+  }
+}
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 696f7a4..609f21b 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
@@ -199,11 +199,7 @@
     if (member is Field) {
       DartType type = member.type;
       if (type is ImplicitFieldType) {
-        if (type.memberBuilder.member != member) {
-          type.memberBuilder.inferCopiedType(member);
-        } else {
-          type.memberBuilder.inferType();
-        }
+        type.inferType();
       }
     }
     return member;
@@ -301,7 +297,8 @@
     }
     if (from is TypeParameterType) {
       if (isSubtypeOf(to, from.promotedBound ?? from.bound)) {
-        return new TypeParameterType(from.parameter, from.nullability, to);
+        return new TypeParameterType.intersection(
+            from.parameter, from.nullability, to);
       }
     }
     return from;
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
index ec83820..8db173a 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
@@ -6,7 +6,8 @@
 
 import 'package:_fe_analyzer_shared/src/flow_analysis/flow_analysis.dart';
 
-import 'package:front_end/src/fasta/kernel/kernel_shadow_ast.dart';
+import 'package:front_end/src/fasta/kernel/internal_ast.dart';
+import 'package:front_end/src/fasta/type_inference/type_demotion.dart';
 
 import 'package:kernel/ast.dart';
 
@@ -32,14 +33,14 @@
 
 import '../fasta_codes.dart';
 
-import '../kernel/expression_generator.dart' show buildIsNull;
-
-import '../kernel/kernel_shadow_ast.dart'
+import '../kernel/internal_ast.dart'
     show
         VariableDeclarationImpl,
         getExplicitTypeArguments,
         getExtensionTypeParameterCount;
 
+import '../kernel/inference_visitor.dart';
+
 import '../kernel/type_algorithms.dart' show hasAnyTypeVariables;
 
 import '../names.dart';
@@ -303,7 +304,8 @@
       return;
     }
     DartType expectedType = node.isYieldStar
-        ? _wrapAsyncOrGenerator(inferrer, returnOrYieldContext)
+        ? _wrapAsyncOrGenerator(
+            inferrer, returnOrYieldContext, inferrer.library.nonNullable)
         : returnOrYieldContext;
     Expression expression = inferrer.ensureAssignableResult(
         expectedType, expressionResult,
@@ -344,7 +346,8 @@
       inferredType = greatestClosure(inferrer.coreTypes, returnOrYieldContext);
     }
 
-    inferredType = _wrapAsyncOrGenerator(inferrer, inferredType);
+    inferredType = _wrapAsyncOrGenerator(
+        inferrer, inferredType, inferrer.library.nonNullable);
     for (int i = 0; i < returnStatements.length; ++i) {
       checkValidReturn(inferrer, inferredType, returnStatements[i],
           returnExpressionTypes[i]);
@@ -353,15 +356,18 @@
     return inferredType;
   }
 
-  DartType _wrapAsyncOrGenerator(TypeInferrerImpl inferrer, DartType type) {
+  DartType _wrapAsyncOrGenerator(
+      TypeInferrerImpl inferrer, DartType type, Nullability nullability) {
     if (isGenerator) {
       if (isAsync) {
-        return inferrer.wrapType(type, inferrer.coreTypes.streamClass);
+        return inferrer.wrapType(
+            type, inferrer.coreTypes.streamClass, nullability);
       } else {
-        return inferrer.wrapType(type, inferrer.coreTypes.iterableClass);
+        return inferrer.wrapType(
+            type, inferrer.coreTypes.iterableClass, nullability);
       }
     } else if (isAsync) {
-      return inferrer.wrapFutureType(type);
+      return inferrer.wrapFutureType(type, nullability);
     } else {
       return type;
     }
@@ -408,7 +414,7 @@
       InferenceHelper helper, DartType declaredType, Expression initializer);
 
   /// Performs type inference on the given function body.
-  void inferFunctionBody(InferenceHelper helper, DartType returnType,
+  Statement inferFunctionBody(InferenceHelper helper, DartType returnType,
       AsyncMarker asyncMarker, FunctionNode function, Statement body);
 
   /// Performs type inference on the given constructor initializer.
@@ -578,7 +584,8 @@
       // and Future<T>.
       DartType unfuturedExpectedType =
           typeSchemaEnvironment.unfutureType(expectedType);
-      DartType futuredExpectedType = wrapFutureType(unfuturedExpectedType);
+      DartType futuredExpectedType =
+          wrapFutureType(unfuturedExpectedType, library.nonNullable);
       if (isAssignable(unfuturedExpectedType, actualType)) {
         expectedType = unfuturedExpectedType;
       } else if (isAssignable(futuredExpectedType, actualType)) {
@@ -607,8 +614,12 @@
           VariableDeclaration t =
               new VariableDeclaration.forValue(expression, type: actualType)
                 ..fileOffset = fileOffset;
-          Expression nullCheck =
-              buildIsNull(new VariableGet(t), fileOffset, helper);
+          Expression nullCheck = new MethodInvocation(
+              new VariableGet(t),
+              equalsName,
+              new Arguments(
+                  <Expression>[new NullLiteral()..fileOffset = fileOffset]))
+            ..fileOffset = fileOffset;
           PropertyGet tearOff =
               new PropertyGet(new VariableGet(t), callName, callMember)
                 ..fileOffset = fileOffset;
@@ -702,8 +713,8 @@
     DartType onType = extension.onType;
     List<DartType> inferredTypes =
         new List<DartType>.filled(typeParameters.length, const UnknownType());
-    typeSchemaEnvironment.inferGenericFunctionOrType(
-        null, typeParameters, [onType], [receiverType], null, inferredTypes);
+    typeSchemaEnvironment.inferGenericFunctionOrType(null, typeParameters,
+        [onType], [receiverType], null, inferredTypes, library.library);
     return inferredTypes;
   }
 
@@ -727,7 +738,7 @@
 
     receiverType = resolveTypeParameter(receiverType);
 
-    if (receiverType is FunctionType && name.name == 'call') {
+    if (receiverType is FunctionType && name == callName) {
       return const ObjectAccessTarget.callFunction();
     }
 
@@ -745,7 +756,7 @@
       target = const ObjectAccessTarget.invalid();
     } else if (receiverType is InterfaceType &&
         receiverType.classNode == coreTypes.functionClass &&
-        name.name == 'call') {
+        name == callName) {
       target = const ObjectAccessTarget.callFunction();
     } else {
       target = const ObjectAccessTarget.missing();
@@ -949,7 +960,7 @@
             return substitution.substituteType(new FunctionType(
                 functionType.positionalParameters.skip(1).toList(),
                 functionType.returnType,
-                Nullability.legacy,
+                library.nonNullable,
                 namedParameters: functionType.namedParameters,
                 typeParameters: functionType.typeParameters
                     .skip(target.inferredExtensionTypeArguments.length)
@@ -1415,6 +1426,19 @@
     return initializerType;
   }
 
+  void inferSyntheticVariable(VariableDeclarationImpl variable) {
+    assert(variable.isImplicitlyTyped);
+    assert(variable.initializer != null);
+    ExpressionInferenceResult result = inferExpression(
+        variable.initializer, const UnknownType(), true,
+        isVoidAllowed: true);
+    variable.initializer = result.expression..parent = variable;
+    DartType inferredType = inferDeclarationType(result.inferredType);
+    instrumentation?.record(uriForInstrumentation, variable.fileOffset, 'type',
+        new InstrumentationValueForType(inferredType));
+    variable.type = inferredType;
+  }
+
   /// Performs type inference on the given [expression].
   ///
   /// [typeContext] is the expected type of the expression, based on surrounding
@@ -1484,8 +1508,9 @@
   }
 
   @override
-  void inferFunctionBody(InferenceHelper helper, DartType returnType,
+  Statement inferFunctionBody(InferenceHelper helper, DartType returnType,
       AsyncMarker asyncMarker, FunctionNode function, Statement body) {
+    assert(body != null);
     assert(closureContext == null);
     this.helper = helper;
     closureContext = new ClosureContext(this, asyncMarker, returnType, false);
@@ -1497,7 +1522,7 @@
         flowAnalysis.initialize(parameter);
       }
     }
-    inferStatement(body);
+    StatementInferenceResult result = inferStatement(body);
     closureContext = null;
     this.helper = null;
     if (dataForTesting != null) {
@@ -1507,6 +1532,7 @@
       }
     }
     flowAnalysis.finish();
+    return result.hasChanged ? result.statement : body;
   }
 
   DartType inferInvocation(DartType typeContext, int offset,
@@ -1556,7 +1582,7 @@
     FunctionType extensionFunctionType = new FunctionType(
         [calleeType.positionalParameters.first],
         const DynamicType(),
-        Nullability.legacy,
+        library.nonNullable,
         requiredParameterCount: 1,
         typeParameters: calleeType.typeParameters
             .take(extensionTypeParameterCount)
@@ -1580,7 +1606,7 @@
     FunctionType targetFunctionType = new FunctionType(
         calleeType.positionalParameters.skip(1).toList(),
         calleeType.returnType,
-        Nullability.legacy,
+        library.nonNullable,
         requiredParameterCount: calleeType.requiredParameterCount - 1,
         namedParameters: calleeType.namedParameters,
         typeParameters: targetTypeParameters);
@@ -1668,7 +1694,8 @@
           null,
           null,
           typeContext,
-          inferredTypes);
+          inferredTypes,
+          library.library);
       substitution =
           Substitution.fromPairs(calleeTypeParameters, inferredTypes);
     } else if (explicitTypeArguments != null &&
@@ -1782,9 +1809,12 @@
           formalTypes,
           actualTypes,
           typeContext,
-          inferredTypes);
+          inferredTypes,
+          library.library);
       assert(inferredTypes.every((type) => isKnown(type)),
           "Unknown type(s) in inferred types: $inferredTypes.");
+      assert(inferredTypes.every((type) => !hasPromotedTypeVariable(type)),
+          "Promoted type variable(s) in inferred types: $inferredTypes.");
       substitution =
           Substitution.fromPairs(calleeTypeParameters, inferredTypes);
       instrumentation?.record(uriForInstrumentation, offset, 'typeArgs',
@@ -1921,7 +1951,8 @@
       for (int i = 0; i < typeContext.typeParameters.length; i++) {
         substitutionMap[typeContext.typeParameters[i]] =
             i < typeParameters.length
-                ? new TypeParameterType(typeParameters[i], Nullability.legacy)
+                ? new TypeParameterType.forAlphaRenaming(
+                    typeContext.typeParameters[i], typeParameters[i])
                 : const DynamicType();
       }
       substitution = Substitution.fromMap(substitutionMap);
@@ -1940,7 +1971,7 @@
     // `Qi[T/S]` with respect to `?`.  Otherwise, let `Ri` be `dynamic`.
     for (int i = 0; i < formals.length; i++) {
       VariableDeclarationImpl formal = formals[i];
-      if (VariableDeclarationImpl.isImplicitlyTyped(formal)) {
+      if (formal.isImplicitlyTyped) {
         DartType inferredType;
         if (formalTypesFromContext[i] == coreTypes.nullType) {
           inferredType = coreTypes.objectRawType(library.nullable);
@@ -2035,6 +2066,368 @@
             typeArguments: arguments.types));
   }
 
+  ExpressionInferenceResult _inferDynamicInvocation(
+      int fileOffset,
+      NullAwareGuard nullAwareGuard,
+      Expression receiver,
+      Name name,
+      Arguments arguments,
+      DartType typeContext) {
+    DartType inferredType = inferInvocation(
+        typeContext, fileOffset, unknownFunction, arguments,
+        receiverType: const DynamicType());
+    assert(name != equalsName);
+    return new ExpressionInferenceResult.nullAware(
+        inferredType,
+        new MethodInvocationImpl(receiver, name, arguments)
+          ..fileOffset = fileOffset,
+        nullAwareGuard);
+  }
+
+  ExpressionInferenceResult _inferMissingInvocation(
+      int fileOffset,
+      NullAwareGuard nullAwareGuard,
+      Expression receiver,
+      DartType receiverType,
+      ObjectAccessTarget target,
+      Name name,
+      Arguments arguments,
+      DartType typeContext,
+      {bool isImplicitCall}) {
+    assert(isImplicitCall != null);
+    Expression error = createMissingMethodInvocation(
+        fileOffset, receiver, receiverType, name, arguments,
+        isImplicitCall: isImplicitCall);
+    inferInvocation(typeContext, fileOffset, unknownFunction, arguments,
+        receiverType: receiverType);
+    assert(name != equalsName);
+    // TODO(johnniwinther): Use InvalidType instead.
+    return new ExpressionInferenceResult(const DynamicType(), error);
+  }
+
+  ExpressionInferenceResult _inferExtensionInvocation(
+      int fileOffset,
+      NullAwareGuard nullAwareGuard,
+      Expression receiver,
+      DartType receiverType,
+      ObjectAccessTarget target,
+      Name name,
+      Arguments arguments,
+      DartType typeContext) {
+    assert(target.isExtensionMember);
+    DartType calleeType = getGetterType(target, receiverType);
+    FunctionType functionType = getFunctionType(target, receiverType, false);
+
+    // TODO(johnniwinther): Disallow all implicit non-function calls?
+    if (calleeType is! DynamicType &&
+        !(calleeType is InterfaceType &&
+            calleeType.classNode == coreTypes.functionClass) &&
+        identical(functionType, unknownFunction)) {
+      Expression error = helper.buildProblem(
+          // TODO(johnniwinther): Use a different message for implicit .call.
+          templateInvokeNonFunction.withArguments(name.name),
+          fileOffset,
+          noLength);
+      return new ExpressionInferenceResult(const DynamicType(), error);
+    }
+    StaticInvocation staticInvocation = transformExtensionMethodInvocation(
+        fileOffset, target, receiver, arguments);
+    DartType inferredType = inferInvocation(
+        typeContext, fileOffset, functionType, staticInvocation.arguments,
+        receiverType: receiverType, isImplicitExtensionMember: true);
+    if (!isTopLevel) {
+      library.checkBoundsInStaticInvocation(staticInvocation,
+          typeSchemaEnvironment, helper.uri, getTypeArgumentsInfo(arguments));
+    }
+    return new ExpressionInferenceResult.nullAware(
+        inferredType, staticInvocation, nullAwareGuard);
+  }
+
+  ExpressionInferenceResult _inferFunctionInvocation(
+      int fileOffset,
+      NullAwareGuard nullAwareGuard,
+      Expression receiver,
+      DartType receiverType,
+      ObjectAccessTarget target,
+      Arguments arguments,
+      DartType typeContext) {
+    assert(target.isCallFunction);
+    FunctionType functionType = getFunctionType(target, receiverType, false);
+    DartType inferredType = inferInvocation(
+        typeContext, fileOffset, functionType, arguments,
+        receiverType: receiverType);
+    // TODO(johnniwinther): Check that type arguments against the bounds.
+    return new ExpressionInferenceResult.nullAware(
+        inferredType,
+        new MethodInvocation(receiver, callName, arguments)
+          ..fileOffset = fileOffset,
+        nullAwareGuard);
+  }
+
+  ExpressionInferenceResult _inferInstanceMethodInvocation(
+      int fileOffset,
+      NullAwareGuard nullAwareGuard,
+      Expression receiver,
+      DartType receiverType,
+      ObjectAccessTarget target,
+      Arguments arguments,
+      DartType typeContext,
+      {bool isImplicitCall}) {
+    assert(isImplicitCall != null);
+    assert(target.isInstanceMember);
+    Procedure method = target.member;
+    assert(method.kind == ProcedureKind.Method,
+        "Unexpected instance method $method");
+    Name methodName = method.name;
+
+    if (receiverType == const DynamicType()) {
+      FunctionNode signature = method.function;
+      if (arguments.positional.length < signature.requiredParameterCount ||
+          arguments.positional.length > signature.positionalParameters.length) {
+        target = const ObjectAccessTarget.unresolved();
+        method = null;
+      }
+      for (NamedExpression argument in arguments.named) {
+        if (!signature.namedParameters
+            .any((declaration) => declaration.name == argument.name)) {
+          target = const ObjectAccessTarget.unresolved();
+          method = null;
+        }
+      }
+      if (instrumentation != null && method != null) {
+        instrumentation.record(uriForInstrumentation, fileOffset, 'target',
+            new InstrumentationValueForMember(method));
+      }
+    }
+
+    DartType calleeType = getGetterType(target, receiverType);
+    FunctionType functionType =
+        getFunctionType(target, receiverType, !isImplicitCall);
+
+    // TODO(johnniwinther): Refactor to avoid this test in multiple places,
+    // either by providing a shared helper method or avoiding the calleeType/
+    // functionType distinction altogether.
+    if (!target.isUnresolved &&
+        calleeType is! DynamicType &&
+        !(calleeType is InterfaceType &&
+            calleeType.classNode == coreTypes.functionClass) &&
+        identical(functionType, unknownFunction)) {
+      Expression error = helper.buildProblem(
+          templateInvokeNonFunction.withArguments(methodName.name),
+          fileOffset,
+          noLength);
+      return new ExpressionInferenceResult(const DynamicType(), error);
+    }
+    bool contravariantCheck = false;
+    if (receiver is! ThisExpression &&
+        method != null &&
+        returnedTypeParametersOccurNonCovariantly(
+            method.enclosingClass, method.function.returnType)) {
+      contravariantCheck = true;
+    }
+    DartType inferredType = inferInvocation(
+        typeContext, fileOffset, functionType, arguments,
+        receiverType: receiverType);
+
+    Expression replacement;
+    if (contravariantCheck) {
+      // TODO(johnniwinther): Merge with the replacement computation below.
+      replacement = new AsExpression(
+          new MethodInvocation(receiver, methodName, arguments, method)
+            ..fileOffset = fileOffset,
+          inferredType)
+        ..isTypeError = true
+        ..fileOffset = fileOffset;
+      if (instrumentation != null) {
+        int offset =
+            arguments.fileOffset == -1 ? fileOffset : arguments.fileOffset;
+        instrumentation.record(uriForInstrumentation, offset, 'checkReturn',
+            new InstrumentationValueForType(inferredType));
+      }
+    }
+
+    _checkBoundsInMethodInvocation(
+        target, receiverType, calleeType, methodName, arguments, fileOffset);
+
+    replacement ??=
+        new MethodInvocation(receiver, methodName, arguments, method)
+          ..fileOffset = fileOffset;
+
+    return new ExpressionInferenceResult.nullAware(
+        inferredType, replacement, nullAwareGuard);
+  }
+
+  ExpressionInferenceResult _inferInstanceGetterInvocation(
+      int fileOffset,
+      NullAwareGuard nullAwareGuard,
+      Expression receiver,
+      DartType receiverType,
+      ObjectAccessTarget target,
+      Arguments arguments,
+      DartType typeContext,
+      {bool isImplicitCall}) {
+    assert(isImplicitCall != null);
+    assert(target.isInstanceMember);
+    Procedure getter = target.member;
+    assert(getter.kind == ProcedureKind.Getter);
+
+    if (receiverType == const DynamicType() && getter is Procedure) {
+      FunctionNode signature = getter.function;
+      if (arguments.positional.length < signature.requiredParameterCount ||
+          arguments.positional.length > signature.positionalParameters.length) {
+        target = const ObjectAccessTarget.unresolved();
+        getter = null;
+      }
+      for (NamedExpression argument in arguments.named) {
+        if (!signature.namedParameters
+            .any((declaration) => declaration.name == argument.name)) {
+          target = const ObjectAccessTarget.unresolved();
+          getter = null;
+        }
+      }
+      if (instrumentation != null && getter != null) {
+        instrumentation.record(uriForInstrumentation, fileOffset, 'target',
+            new InstrumentationValueForMember(getter));
+      }
+    }
+
+    DartType calleeType = getGetterType(target, receiverType);
+    FunctionType functionType =
+        getFunctionType(target, receiverType, !isImplicitCall);
+
+    if (!target.isUnresolved &&
+        calleeType is! DynamicType &&
+        !(calleeType is InterfaceType &&
+            calleeType.classNode == coreTypes.functionClass) &&
+        identical(functionType, unknownFunction)) {
+      Expression error = helper.buildProblem(
+          templateInvokeNonFunction.withArguments(getter.name.name),
+          fileOffset,
+          noLength);
+      return new ExpressionInferenceResult(const DynamicType(), error);
+    }
+    bool contravariantCheck = false;
+    if (calleeType is! DynamicType &&
+        receiver is! ThisExpression &&
+        returnedTypeParametersOccurNonCovariantly(
+            getter.enclosingClass, getter.function.returnType)) {
+      contravariantCheck = true;
+    }
+
+    DartType inferredType = inferInvocation(
+        typeContext, fileOffset, functionType, arguments,
+        receiverType: receiverType);
+
+    if (isImplicitCall) {
+      Expression error = helper.buildProblem(
+          templateImplicitCallOfNonMethod.withArguments(receiverType),
+          fileOffset,
+          noLength);
+      return new ExpressionInferenceResult(const DynamicType(), error);
+    }
+
+    Expression replacement;
+    if (contravariantCheck) {
+      PropertyGet propertyGet = new PropertyGet(receiver, getter.name, getter);
+      AsExpression asExpression = new AsExpression(propertyGet, functionType)
+        ..isTypeError = true
+        ..fileOffset = fileOffset;
+      replacement = new MethodInvocation(asExpression, callName, arguments);
+      if (instrumentation != null) {
+        int offset =
+            arguments.fileOffset == -1 ? fileOffset : arguments.fileOffset;
+        instrumentation.record(uriForInstrumentation, offset,
+            'checkGetterReturn', new InstrumentationValueForType(functionType));
+      }
+    }
+
+    _checkBoundsInMethodInvocation(
+        target, receiverType, calleeType, getter.name, arguments, fileOffset);
+
+    // TODO(johnniwinther): Always encode the call as an explicit .call and
+    // set the correct member on the invocation.
+    replacement ??=
+        new MethodInvocation(receiver, getter.name, arguments, getter)
+          ..fileOffset = fileOffset;
+
+    return new ExpressionInferenceResult.nullAware(
+        inferredType, replacement, nullAwareGuard);
+  }
+
+  ExpressionInferenceResult _inferInstanceFieldInvocation(
+      int fileOffset,
+      NullAwareGuard nullAwareGuard,
+      Expression receiver,
+      DartType receiverType,
+      ObjectAccessTarget target,
+      Arguments arguments,
+      DartType typeContext,
+      {bool isImplicitCall}) {
+    assert(isImplicitCall != null);
+    assert(target.isInstanceMember);
+    Field field = target.member;
+
+    DartType calleeType = getGetterType(target, receiverType);
+    FunctionType functionType =
+        getFunctionType(target, receiverType, !isImplicitCall);
+
+    if (calleeType is! DynamicType &&
+        !(calleeType is InterfaceType &&
+            calleeType.classNode == coreTypes.functionClass) &&
+        identical(functionType, unknownFunction)) {
+      Expression error = helper.buildProblem(
+          templateInvokeNonFunction.withArguments(target.member.name.name),
+          fileOffset,
+          noLength);
+      return new ExpressionInferenceResult(const DynamicType(), error);
+    }
+    bool contravariantCheck = false;
+    if (receiver is! ThisExpression &&
+        calleeType is! DynamicType &&
+        returnedTypeParametersOccurNonCovariantly(
+            field.enclosingClass, field.type)) {
+      contravariantCheck = true;
+    }
+
+    DartType inferredType = inferInvocation(
+        typeContext, fileOffset, functionType, arguments,
+        receiverType: receiverType);
+
+    if (isImplicitCall) {
+      Expression error = helper.buildProblem(
+          templateImplicitCallOfNonMethod.withArguments(receiverType),
+          fileOffset,
+          noLength);
+      return new ExpressionInferenceResult(const DynamicType(), error);
+    }
+
+    Expression replacement;
+    if (contravariantCheck) {
+      PropertyGet propertyGet = new PropertyGet(receiver, field.name, field);
+      AsExpression asExpression = new AsExpression(propertyGet, functionType)
+        ..isTypeError = true
+        ..fileOffset = fileOffset;
+      replacement = new MethodInvocation(asExpression, callName, arguments);
+      if (instrumentation != null) {
+        int offset =
+            arguments.fileOffset == -1 ? fileOffset : arguments.fileOffset;
+        instrumentation.record(uriForInstrumentation, offset,
+            'checkGetterReturn', new InstrumentationValueForType(functionType));
+      }
+    }
+
+    _checkBoundsInMethodInvocation(
+        target, receiverType, calleeType, field.name, arguments, fileOffset);
+
+    // TODO(johnniwinther): Always encode the call as an explicit .call and
+    // set the correct member on the invocation.
+    replacement ??= new MethodInvocation(receiver, field.name, arguments, field)
+      ..fileOffset = fileOffset;
+
+    return new ExpressionInferenceResult.nullAware(
+        inferredType, replacement, nullAwareGuard);
+  }
+
   /// Performs the core type inference algorithm for method invocations (this
   /// handles both null-aware and non-null-aware method invocations).
   ExpressionInferenceResult inferMethodInvocation(
@@ -2054,101 +2447,69 @@
     ObjectAccessTarget target = findInterfaceMember(
         receiverType, node.name, node.fileOffset,
         instrumented: true, includeExtensionMethods: true);
-    Expression error = reportMissingInterfaceMember(target, receiverType,
-        node.name, node.fileOffset, templateUndefinedMethod);
-    if (target.isInstanceMember) {
-      Member interfaceMember = target.member;
-      if (receiverType == const DynamicType() && interfaceMember is Procedure) {
-        Arguments arguments = node.arguments;
-        FunctionNode signature = interfaceMember.function;
-        if (arguments.positional.length < signature.requiredParameterCount ||
-            arguments.positional.length >
-                signature.positionalParameters.length) {
-          target = const ObjectAccessTarget.unresolved();
-          interfaceMember = null;
-        }
-        for (NamedExpression argument in arguments.named) {
-          if (!signature.namedParameters
-              .any((declaration) => declaration.name == argument.name)) {
-            target = const ObjectAccessTarget.unresolved();
-            interfaceMember = null;
+    switch (target.kind) {
+      case ObjectAccessTargetKind.instanceMember:
+        Member member = target.member;
+        if (member is Procedure) {
+          if (member.kind == ProcedureKind.Getter) {
+            return _inferInstanceGetterInvocation(
+                node.fileOffset,
+                nullAwareGuard,
+                receiver,
+                receiverType,
+                target,
+                node.arguments,
+                typeContext,
+                isImplicitCall: node.isImplicitCall);
+          } else {
+            return _inferInstanceMethodInvocation(
+                node.fileOffset,
+                nullAwareGuard,
+                receiver,
+                receiverType,
+                target,
+                node.arguments,
+                typeContext,
+                isImplicitCall: node.isImplicitCall);
           }
+        } else {
+          return _inferInstanceFieldInvocation(node.fileOffset, nullAwareGuard,
+              receiver, receiverType, target, node.arguments, typeContext,
+              isImplicitCall: node.isImplicitCall);
         }
-        if (instrumentation != null && interfaceMember != null) {
-          instrumentation.record(uriForInstrumentation, node.fileOffset,
-              'target', new InstrumentationValueForMember(interfaceMember));
-        }
-      }
-      node.interfaceTarget = interfaceMember;
+        break;
+      case ObjectAccessTargetKind.callFunction:
+        return _inferFunctionInvocation(node.fileOffset, nullAwareGuard,
+            receiver, receiverType, target, node.arguments, typeContext);
+      case ObjectAccessTargetKind.extensionMember:
+        return _inferExtensionInvocation(
+            node.fileOffset,
+            nullAwareGuard,
+            receiver,
+            receiverType,
+            target,
+            node.name,
+            node.arguments,
+            typeContext);
+      case ObjectAccessTargetKind.missing:
+        return _inferMissingInvocation(
+            node.fileOffset,
+            nullAwareGuard,
+            receiver,
+            receiverType,
+            target,
+            node.name,
+            node.arguments,
+            typeContext,
+            isImplicitCall: node.isImplicitCall);
+      case ObjectAccessTargetKind.dynamic:
+      case ObjectAccessTargetKind.invalid:
+      case ObjectAccessTargetKind.unresolved:
+        return _inferDynamicInvocation(node.fileOffset, nullAwareGuard,
+            receiver, node.name, node.arguments, typeContext);
     }
-
-    Name methodName = node.name;
-    assert(target != null, "No target for ${node}.");
-    bool isOverloadedArithmeticOperator =
-        isOverloadedArithmeticOperatorAndType(target, receiverType);
-    DartType calleeType = getGetterType(target, receiverType);
-    FunctionType functionType =
-        getFunctionType(target, receiverType, !node.isImplicitCall);
-
-    if (!target.isUnresolved &&
-        calleeType is! DynamicType &&
-        !(calleeType is InterfaceType &&
-            calleeType.classNode == coreTypes.functionClass) &&
-        identical(functionType, unknownFunction)) {
-      Expression error = helper.wrapInProblem(node,
-          templateInvokeNonFunction.withArguments(methodName.name), noLength);
-      return new ExpressionInferenceResult(const DynamicType(), error);
-    }
-    MethodContravarianceCheckKind checkKind = preCheckInvocationContravariance(
-        receiverType, target,
-        isThisReceiver: receiver is ThisExpression);
-    Expression replacement;
-    Arguments arguments = node.arguments;
-    if (target.isExtensionMember) {
-      StaticInvocation staticInvocation = transformExtensionMethodInvocation(
-          node.fileOffset, target, receiver, node.arguments);
-      arguments = staticInvocation.arguments;
-      replacement = staticInvocation;
-    } else {
-      node.receiver = receiver..parent = node;
-      arguments = node.arguments;
-      replacement = node;
-    }
-    DartType inferredType = inferInvocation(
-        typeContext, node.fileOffset, functionType, arguments,
-        isOverloadedArithmeticOperator: isOverloadedArithmeticOperator,
-        receiverType: receiverType,
-        isImplicitExtensionMember: target.isExtensionMember);
-    if (methodName.name == '==') {
-      inferredType = coreTypes.boolRawType(library.nonNullable);
-    }
-    replacement = handleInvocationContravariance(checkKind, node, arguments,
-        replacement, inferredType, functionType, node.fileOffset);
-
-    if (node.isImplicitCall && target.isInstanceMember) {
-      Member member = target.member;
-      if (!(member is Procedure && member.kind == ProcedureKind.Method)) {
-        Expression error = helper.wrapInProblem(
-            node,
-            templateImplicitCallOfNonMethod.withArguments(receiverType),
-            noLength);
-        return new ExpressionInferenceResult(const DynamicType(), error);
-      }
-    }
-    if (!isTopLevel && target.isExtensionMember) {
-      library.checkBoundsInStaticInvocation(replacement, typeSchemaEnvironment,
-          helper.uri, getTypeArgumentsInfo(arguments));
-    } else {
-      _checkBoundsInMethodInvocation(target, receiverType, calleeType,
-          methodName, arguments, node.fileOffset);
-    }
-    if (error != null) {
-      // TODO(johnniwinther): Use InvalidType instead.
-      return new ExpressionInferenceResult(const DynamicType(), error);
-    }
-
-    return new ExpressionInferenceResult.nullAware(
-        inferredType, replacement, nullAwareGuard);
+    return unhandled('$target', 'inferMethodInvocation', node.fileOffset,
+        uriForInstrumentation);
   }
 
   void _checkBoundsInMethodInvocation(
@@ -2276,15 +2637,13 @@
   ///
   /// Derived classes should override this method with logic that dispatches on
   /// the statement type and calls the appropriate specialized "infer" method.
-  void inferStatement(Statement statement) {
+  StatementInferenceResult inferStatement(Statement statement) {
     registerIfUnreachableForTesting(statement);
 
     // For full (non-top level) inference, we need access to the
     // ExpressionGeneratorHelper so that we can perform error recovery.
     if (!isTopLevel) assert(helper != null);
-    if (statement != null) {
-      statement.accept(new InferenceVisitor(this));
-    }
+    return statement.accept(new InferenceVisitor(this));
   }
 
   /// Performs the type inference steps necessary to instantiate a tear-off
@@ -2300,8 +2659,8 @@
         List<DartType> inferredTypes = new List<DartType>.filled(
             typeParameters.length, const UnknownType());
         FunctionType instantiatedType = functionType.withoutTypeParameters;
-        typeSchemaEnvironment.inferGenericFunctionOrType(
-            instantiatedType, typeParameters, [], [], context, inferredTypes);
+        typeSchemaEnvironment.inferGenericFunctionOrType(instantiatedType,
+            typeParameters, [], [], context, inferredTypes, library.library);
         if (!isTopLevel) {
           expression = new Instantiation(expression, inferredTypes)
             ..fileOffset = expression.fileOffset;
@@ -2418,19 +2777,22 @@
     }
     // TODO(paulberry): If [type] is a subtype of `Future`, should we just
     // return it unmodified?
-    return new InterfaceType(coreTypes.futureOrClass, Nullability.legacy,
-        <DartType>[type ?? const DynamicType()]);
-  }
-
-  DartType wrapFutureType(DartType type) {
-    DartType typeWithoutFutureOr = type ?? const DynamicType();
-    return new InterfaceType(coreTypes.futureClass, Nullability.legacy,
-        <DartType>[typeWithoutFutureOr]);
-  }
-
-  DartType wrapType(DartType type, Class class_) {
+    if (type == null) {
+      return coreTypes.futureRawType(library.nullable);
+    }
     return new InterfaceType(
-        class_, Nullability.legacy, <DartType>[type ?? const DynamicType()]);
+        coreTypes.futureOrClass, library.nonNullable, <DartType>[type]);
+  }
+
+  DartType wrapFutureType(DartType type, Nullability nullability) {
+    DartType typeWithoutFutureOr = type ?? const DynamicType();
+    return new InterfaceType(
+        coreTypes.futureClass, nullability, <DartType>[typeWithoutFutureOr]);
+  }
+
+  DartType wrapType(DartType type, Class class_, Nullability nullability) {
+    return new InterfaceType(
+        class_, nullability, <DartType>[type ?? const DynamicType()]);
   }
 
   Member _getInterfaceMember(
@@ -2480,8 +2842,7 @@
     }
     if (expression is VariableGet) {
       VariableDeclaration variable = expression.variable;
-      if (variable is VariableDeclarationImpl &&
-          VariableDeclarationImpl.isLocalFunction(variable)) {
+      if (variable is VariableDeclarationImpl && variable.isLocalFunction) {
         return templateInvalidCastLocalFunction;
       }
     }
@@ -2532,6 +2893,22 @@
     }
   }
 
+  Expression createMissingMethodInvocation(int fileOffset, Expression receiver,
+      DartType receiverType, Name name, Arguments arguments,
+      {bool isImplicitCall}) {
+    assert(isImplicitCall != null);
+    if (isTopLevel) {
+      return engine.forest
+          .createMethodInvocation(fileOffset, receiver, name, arguments);
+    } else {
+      return helper.buildProblem(
+          templateUndefinedMethod.withArguments(
+              name.name, resolveTypeParameter(receiverType)),
+          fileOffset,
+          isImplicitCall ? noLength : name.name.length);
+    }
+  }
+
   Expression createMissingPropertyGet(int fileOffset, Expression receiver,
       DartType receiverType, Name propertyName) {
     if (isTopLevel) {
@@ -2566,11 +2943,7 @@
   Expression createMissingIndexGet(int fileOffset, Expression receiver,
       DartType receiverType, Expression index) {
     if (isTopLevel) {
-      return engine.forest.createMethodInvocation(
-          fileOffset,
-          receiver,
-          indexGetName,
-          engine.forest.createArguments(fileOffset, <Expression>[index]));
+      return engine.forest.createIndexGet(fileOffset, receiver, index);
     } else {
       return helper.buildProblem(
           templateUndefinedMethod.withArguments(
@@ -2581,14 +2954,13 @@
   }
 
   Expression createMissingIndexSet(int fileOffset, Expression receiver,
-      DartType receiverType, Expression index, Expression value) {
+      DartType receiverType, Expression index, Expression value,
+      {bool forEffect, bool readOnlyReceiver}) {
+    assert(forEffect != null);
+    assert(readOnlyReceiver != null);
     if (isTopLevel) {
-      return engine.forest.createMethodInvocation(
-          fileOffset,
-          receiver,
-          indexSetName,
-          engine.forest
-              .createArguments(fileOffset, <Expression>[index, value]));
+      return engine.forest.createIndexSet(fileOffset, receiver, index, value,
+          forEffect: forEffect, readOnlyReceiver: readOnlyReceiver);
     } else {
       return helper.buildProblem(
           templateUndefinedMethod.withArguments(
@@ -2759,9 +3131,10 @@
     // substitute them before calling instantiate to bounds.
     Substitution substitution = Substitution.fromPairs(
         mixinClass.typeParameters,
-        parameters
-            .map((p) => new TypeParameterType(p, Nullability.legacy))
-            .toList());
+        new List<DartType>.generate(
+            parameters.length,
+            (i) => new TypeParameterType.forAlphaRenaming(
+                mixinClass.typeParameters[i], parameters[i])));
     for (TypeParameter p in parameters) {
       p.bound = substitution.substituteType(p.bound);
     }
@@ -2773,6 +3146,55 @@
   }
 }
 
+/// The result of a statement inference.
+class StatementInferenceResult {
+  const StatementInferenceResult();
+
+  factory StatementInferenceResult.single(Statement statement) =
+      SingleStatementInferenceResult;
+
+  factory StatementInferenceResult.multiple(
+          int fileOffset, List<Statement> statements) =
+      MultipleStatementInferenceResult;
+
+  bool get hasChanged => false;
+
+  Statement get statement =>
+      throw new UnsupportedError('StatementInferenceResult.statement');
+
+  int get statementCount =>
+      throw new UnsupportedError('StatementInferenceResult.statementCount');
+
+  List<Statement> get statements =>
+      throw new UnsupportedError('StatementInferenceResult.statements');
+}
+
+class SingleStatementInferenceResult implements StatementInferenceResult {
+  final Statement statement;
+
+  SingleStatementInferenceResult(this.statement);
+
+  bool get hasChanged => true;
+
+  int get statementCount => 1;
+
+  List<Statement> get statements =>
+      throw new UnsupportedError('SingleStatementInferenceResult.statements');
+}
+
+class MultipleStatementInferenceResult implements StatementInferenceResult {
+  final int fileOffset;
+  final List<Statement> statements;
+
+  MultipleStatementInferenceResult(this.fileOffset, this.statements);
+
+  bool get hasChanged => true;
+
+  Statement get statement => new Block(statements)..fileOffset = fileOffset;
+
+  int get statementCount => statements.length;
+}
+
 /// The result of an expression inference.
 class ExpressionInferenceResult {
   /// The inferred type of the expression.
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_promotion.dart b/pkg/front_end/lib/src/fasta/type_inference/type_promotion.dart
index ef4c2a6..56800aa 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_promotion.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_promotion.dart
@@ -11,7 +11,7 @@
 
 import '../problems.dart' show internalProblem;
 
-import '../kernel/kernel_shadow_ast.dart' show ShadowTypePromoter;
+import '../kernel/internal_ast.dart' show ShadowTypePromoter;
 
 import 'type_schema_environment.dart' show TypeSchemaEnvironment;
 
@@ -694,7 +694,7 @@
             previousType.bound, SubtypeCheckMode.ignoringNullabilities)) {
       // The type we are checking against is a subtype of the bound of the
       // previous type of the variable; we can promote the bound.
-      return new TypeParameterType(
+      return new TypeParameterType.intersection(
           previousType.parameter, previousType.nullability, checkedType);
     } else {
       // The types aren't sufficiently related; we can't promote.
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_schema.dart b/pkg/front_end/lib/src/fasta/type_inference/type_schema.dart
index 9399c64..3ded48c 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_schema.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_schema.dart
@@ -20,7 +20,7 @@
     show Annotator, NameSystem, Printer, globalDebuggingNames;
 
 /// Determines whether a type schema contains `?` somewhere inside it.
-bool isKnown(DartType schema) => schema.accept(new _IsKnownVisitor());
+bool isKnown(DartType schema) => schema.accept(const _IsKnownVisitor());
 
 /// Converts a [DartType] to a string, representing the unknown type as `?`.
 String typeSchemaToString(DartType schema) {
@@ -87,6 +87,8 @@
 
 /// Visitor that computes [isKnown].
 class _IsKnownVisitor extends DartTypeVisitor<bool> {
+  const _IsKnownVisitor();
+
   @override
   bool defaultDartType(DartType node) => node is! UnknownType;
 
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_schema_elimination.dart b/pkg/front_end/lib/src/fasta/type_inference/type_schema_elimination.dart
index dc1b1be..95b32d1 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_schema_elimination.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_schema_elimination.dart
@@ -6,6 +6,7 @@
 
 import 'package:kernel/core_types.dart' show CoreTypes;
 
+import 'replacement_visitor.dart';
 import 'type_schema.dart' show UnknownType;
 
 /// Returns the greatest closure of the given type [schema] with respect to `?`.
@@ -45,7 +46,7 @@
 /// Each visitor method returns `null` if there are no `?`s contained in the
 /// type, otherwise it returns the result of substituting `?` with `Null` or
 /// `Object`, as appropriate.
-class _TypeSchemaEliminationVisitor implements DartTypeVisitor<DartType> {
+class _TypeSchemaEliminationVisitor extends ReplacementVisitor {
   final DartType nullType;
 
   bool isLeastClosure;
@@ -53,112 +54,8 @@
   _TypeSchemaEliminationVisitor(CoreTypes coreTypes, this.isLeastClosure)
       : nullType = coreTypes.nullType;
 
-  @override
-  DartType visitFunctionType(FunctionType node) {
-    DartType newReturnType = node.returnType.accept(this);
+  void changeVariance() {
     isLeastClosure = !isLeastClosure;
-    List<DartType> newPositionalParameters = null;
-    for (int i = 0; i < node.positionalParameters.length; i++) {
-      DartType substitution = node.positionalParameters[i].accept(this);
-      if (substitution != null) {
-        newPositionalParameters ??=
-            node.positionalParameters.toList(growable: false);
-        newPositionalParameters[i] = substitution;
-      }
-    }
-    List<NamedType> newNamedParameters = null;
-    for (int i = 0; i < node.namedParameters.length; i++) {
-      DartType substitution = node.namedParameters[i].type.accept(this);
-      if (substitution != null) {
-        newNamedParameters ??= node.namedParameters.toList(growable: false);
-        newNamedParameters[i] = new NamedType(
-            node.namedParameters[i].name, substitution,
-            isRequired: node.namedParameters[i].isRequired);
-      }
-    }
-    isLeastClosure = !isLeastClosure;
-    DartType typedefType = node.typedefType?.accept(this);
-    if (newReturnType == null &&
-        newPositionalParameters == null &&
-        newNamedParameters == null &&
-        typedefType == null) {
-      // No types had to be substituted.
-      return null;
-    } else {
-      return new FunctionType(
-          newPositionalParameters ?? node.positionalParameters,
-          newReturnType ?? node.returnType,
-          node.nullability,
-          namedParameters: newNamedParameters ?? node.namedParameters,
-          typeParameters: node.typeParameters,
-          requiredParameterCount: node.requiredParameterCount,
-          typedefType: typedefType);
-    }
-  }
-
-  @override
-  DartType visitInterfaceType(InterfaceType node) {
-    List<DartType> newTypeArguments = null;
-    for (int i = 0; i < node.typeArguments.length; i++) {
-      DartType substitution = node.typeArguments[i].accept(this);
-      if (substitution != null) {
-        newTypeArguments ??= node.typeArguments.toList(growable: false);
-        newTypeArguments[i] = substitution;
-      }
-    }
-    if (newTypeArguments == null) {
-      // No type arguments needed to be substituted.
-      return null;
-    } else {
-      return new InterfaceType(
-          node.classNode, node.nullability, newTypeArguments);
-    }
-  }
-
-  @override
-  DartType visitDynamicType(DynamicType node) => null;
-
-  @override
-  DartType visitNeverType(NeverType node) => null;
-
-  @override
-  DartType visitInvalidType(InvalidType node) => null;
-
-  @override
-  DartType visitBottomType(BottomType node) => null;
-
-  @override
-  DartType visitVoidType(VoidType node) => null;
-
-  @override
-  DartType visitTypeParameterType(TypeParameterType node) {
-    if (node.promotedBound != null) {
-      DartType newPromotedBound = node.promotedBound.accept(this);
-      if (newPromotedBound != null) {
-        return new TypeParameterType(node.parameter,
-            node.typeParameterTypeNullability, newPromotedBound);
-      }
-    }
-    return null;
-  }
-
-  @override
-  DartType visitTypedefType(TypedefType node) {
-    List<DartType> newTypeArguments = null;
-    for (int i = 0; i < node.typeArguments.length; i++) {
-      DartType substitution = node.typeArguments[i].accept(this);
-      if (substitution != null) {
-        newTypeArguments ??= node.typeArguments.toList(growable: false);
-        newTypeArguments[i] = substitution;
-      }
-    }
-    if (newTypeArguments == null) {
-      // No type arguments needed to be substituted.
-      return null;
-    } else {
-      return new TypedefType(
-          node.typedefNode, node.nullability, newTypeArguments);
-    }
   }
 
   @override
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_schema_environment.dart b/pkg/front_end/lib/src/fasta/type_inference/type_schema_environment.dart
index 16cd881..16f0ff7 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_schema_environment.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_schema_environment.dart
@@ -9,10 +9,11 @@
         DynamicType,
         FunctionType,
         InterfaceType,
+        Library,
         NamedType,
-        Nullability,
         Procedure,
-        TypeParameter;
+        TypeParameter,
+        Variance;
 
 import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
 
@@ -29,6 +30,8 @@
 
 import 'type_constraint_gatherer.dart' show TypeConstraintGatherer;
 
+import 'type_demotion.dart';
+
 import 'type_schema.dart' show UnknownType, typeSchemaToString, isKnown;
 
 import 'type_schema_elimination.dart' show greatestClosure, leastClosure;
@@ -42,7 +45,7 @@
   return new FunctionType(
       type.positionalParameters.map(substitution.substituteType).toList(),
       substitution.substituteType(type.returnType),
-      Nullability.legacy,
+      type.nullability,
       namedParameters: type.namedParameters
           .map((named) => new NamedType(
               named.name, substitution.substituteType(named.type),
@@ -167,6 +170,7 @@
       List<DartType> actualTypes,
       DartType returnContextType,
       List<DartType> inferredTypes,
+      Library currentLibrary,
       {bool isConst: false}) {
     if (typeParametersToInfer.isEmpty) {
       return;
@@ -177,7 +181,7 @@
     // be subtypes (or supertypes) as necessary, and track the constraints that
     // are implied by this.
     TypeConstraintGatherer gatherer =
-        new TypeConstraintGatherer(this, typeParametersToInfer);
+        new TypeConstraintGatherer(this, typeParametersToInfer, currentLibrary);
 
     if (!isEmptyContext(returnContextType)) {
       if (isConst) {
@@ -198,6 +202,10 @@
     inferTypeFromConstraints(
         gatherer.computeConstraints(), typeParametersToInfer, inferredTypes,
         downwardsInferPhase: formalTypes == null);
+
+    for (int i = 0; i < inferredTypes.length; i++) {
+      inferredTypes[i] = demoteType(inferredTypes[i]);
+    }
   }
 
   bool hasOmittedBound(TypeParameter parameter) {
@@ -249,8 +257,9 @@
 
       TypeConstraint constraint = constraints[typeParam];
       if (downwardsInferPhase || !typeParam.isLegacyCovariant) {
-        inferredTypes[i] =
-            _inferTypeParameterFromContext(constraint, extendsConstraint);
+        inferredTypes[i] = _inferTypeParameterFromContext(
+            constraint, extendsConstraint,
+            isContravariant: typeParam.variance == Variance.contravariant);
       } else {
         inferredTypes[i] = _inferTypeParameterFromAll(
             typesFromDownwardsInference[i], constraint, extendsConstraint);
@@ -351,21 +360,44 @@
   ///
   /// If [grounded] is `true`, then the returned type is guaranteed to be a
   /// known type (i.e. it will not contain any instances of `?`).
+  ///
+  /// If [isContravariant] is `true`, then we are solving for a contravariant
+  /// type parameter which means we choose the upper bound rather than the
+  /// lower bound for normally covariant type parameters.
   DartType solveTypeConstraint(TypeConstraint constraint,
-      {bool grounded: false}) {
-    // Prefer the known bound, if any.
-    if (isKnown(constraint.lower)) return constraint.lower;
-    if (isKnown(constraint.upper)) return constraint.upper;
+      {bool grounded: false, bool isContravariant: false}) {
+    if (!isContravariant) {
+      // Prefer the known bound, if any.
+      if (isKnown(constraint.lower)) return constraint.lower;
+      if (isKnown(constraint.upper)) return constraint.upper;
 
-    // Otherwise take whatever bound has partial information, e.g. `Iterable<?>`
-    if (constraint.lower is! UnknownType) {
-      return grounded
-          ? leastClosure(coreTypes, constraint.lower)
-          : constraint.lower;
+      // Otherwise take whatever bound has partial information,
+      // e.g. `Iterable<?>`
+      if (constraint.lower is! UnknownType) {
+        return grounded
+            ? leastClosure(coreTypes, constraint.lower)
+            : constraint.lower;
+      } else {
+        return grounded
+            ? greatestClosure(coreTypes, constraint.upper)
+            : constraint.upper;
+      }
     } else {
-      return grounded
-          ? greatestClosure(coreTypes, constraint.upper)
-          : constraint.upper;
+      // Prefer the known bound, if any.
+      if (isKnown(constraint.upper)) return constraint.upper;
+      if (isKnown(constraint.lower)) return constraint.lower;
+
+      // Otherwise take whatever bound has partial information,
+      // e.g. `Iterable<?>`
+      if (constraint.upper is! UnknownType) {
+        return grounded
+            ? greatestClosure(coreTypes, constraint.upper)
+            : constraint.upper;
+      } else {
+        return grounded
+            ? leastClosure(coreTypes, constraint.lower)
+            : constraint.lower;
+      }
     }
   }
 
@@ -394,8 +426,10 @@
   }
 
   DartType _inferTypeParameterFromContext(
-      TypeConstraint constraint, DartType extendsConstraint) {
-    DartType t = solveTypeConstraint(constraint);
+      TypeConstraint constraint, DartType extendsConstraint,
+      {bool isContravariant: false}) {
+    DartType t =
+        solveTypeConstraint(constraint, isContravariant: isContravariant);
     if (!isKnown(t)) {
       return t;
     }
diff --git a/pkg/front_end/lib/src/fasta/util/textual_outline.dart b/pkg/front_end/lib/src/fasta/util/textual_outline.dart
new file mode 100644
index 0000000..ac59c1e
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/util/textual_outline.dart
@@ -0,0 +1,110 @@
+// Copyright (c) 2019, 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:typed_data' show Uint8List;
+
+import 'dart:io' show File;
+
+import 'package:_fe_analyzer_shared/src/parser/class_member_parser.dart'
+    show ClassMemberParser;
+
+import 'package:_fe_analyzer_shared/src/scanner/scanner.dart'
+    show ErrorToken, LanguageVersionToken, Scanner;
+
+import 'package:_fe_analyzer_shared/src/scanner/utf8_bytes_scanner.dart'
+    show Utf8BytesScanner;
+
+import '../../fasta/source/directive_listener.dart' show DirectiveListener;
+
+import 'package:_fe_analyzer_shared/src/scanner/token.dart' show Token;
+
+String textualOutline(List<int> rawBytes) {
+  // TODO(jensj): We need to specify the scanner settings to match that of the
+  // compiler!
+  Uint8List bytes = new Uint8List(rawBytes.length + 1);
+  bytes.setRange(0, rawBytes.length, rawBytes);
+
+  StringBuffer sb = new StringBuffer();
+
+  Utf8BytesScanner scanner = new Utf8BytesScanner(bytes, includeComments: false,
+      languageVersionChanged:
+          (Scanner scanner, LanguageVersionToken languageVersion) {
+    sb.writeln("// @dart = ${languageVersion.major}.${languageVersion.minor}");
+  });
+  Token firstToken = scanner.tokenize();
+  if (firstToken == null) return null;
+  List<int> lineStarts = scanner.lineStarts;
+  int lineStartsIteratorLine = 1;
+  Iterator<int> lineStartsIterator = lineStarts.iterator;
+  lineStartsIterator.moveNext();
+  lineStartsIterator.moveNext();
+  lineStartsIteratorLine++;
+  Token token = firstToken;
+
+  EndOffsetListener listener = new EndOffsetListener();
+  ClassMemberParser classMemberParser = new ClassMemberParser(listener);
+  classMemberParser.parseUnit(firstToken);
+
+  bool printed = false;
+  int endOfLast = -1;
+  while (token != null) {
+    if (token is ErrorToken) {
+      return null;
+    }
+    int prevLine = lineStartsIteratorLine;
+    while (token.offset >= lineStartsIterator.current &&
+        lineStartsIterator.moveNext()) {
+      lineStartsIteratorLine++;
+    }
+    if (prevLine < lineStartsIteratorLine) {
+      sb.write("\n");
+      prevLine++;
+      if (prevLine < lineStartsIteratorLine) {
+        sb.write("\n");
+      }
+    } else if (printed && token.offset > endOfLast) {
+      sb.write(" ");
+    }
+
+    sb.write(token.lexeme);
+    printed = true;
+    endOfLast = token.end;
+
+    if (token.isEof) break;
+
+    if (token.endGroup != null &&
+        listener.endOffsets.contains(token.endGroup.offset)) {
+      token = token.endGroup;
+    } else {
+      token = token.next;
+    }
+  }
+
+  return sb.toString();
+}
+
+main(List<String> args) {
+  File f = new File(args[0]);
+  print(textualOutline(f.readAsBytesSync()));
+}
+
+class EndOffsetListener extends DirectiveListener {
+  Set<int> endOffsets = new Set<int>();
+
+  @override
+  void endClassMethod(Token getOrSet, Token beginToken, Token beginParam,
+      Token beginInitializers, Token endToken) {
+    endOffsets.add(endToken.offset);
+  }
+
+  @override
+  void endTopLevelMethod(Token beginToken, Token getOrSet, Token endToken) {
+    endOffsets.add(endToken.offset);
+  }
+
+  @override
+  void handleNativeFunctionBodySkipped(Token nativeToken, Token semicolon) {
+    // Allow native functions.
+  }
+}
diff --git a/pkg/front_end/lib/src/kernel_generator_impl.dart b/pkg/front_end/lib/src/kernel_generator_impl.dart
index d69c809..4f0fbf1 100644
--- a/pkg/front_end/lib/src/kernel_generator_impl.dart
+++ b/pkg/front_end/lib/src/kernel_generator_impl.dart
@@ -9,7 +9,7 @@
 
 import 'package:_fe_analyzer_shared/src/messages/severity.dart' show Severity;
 
-import 'package:kernel/kernel.dart' show Component, CanonicalName;
+import 'package:kernel/kernel.dart' show CanonicalName, Component;
 
 import 'base/processed_options.dart' show ProcessedOptions;
 
@@ -81,6 +81,8 @@
           .toSet();
     }
 
+    List<Component> loadedComponents = new List<Component>();
+
     Component sdkSummary = await options.loadSdkSummary(null);
     // By using the nameRoot of the the summary, we enable sharing the
     // sdkSummary between multiple invocations.
@@ -95,6 +97,7 @@
     // linked dependencies were listed out of order (or provide mechanism to
     // sort them).
     for (Component inputSummary in await options.loadInputSummaries(nameRoot)) {
+      loadedComponents.add(inputSummary);
       Set<Uri> excluded = externalLibs(inputSummary);
       dillTarget.loader.appendLibraries(inputSummary,
           filter: (uri) => !excluded.contains(uri));
@@ -110,6 +113,7 @@
     // Linked dependencies are meant to be part of the component so they are not
     // marked external.
     for (Component dependency in await options.loadLinkDependencies(nameRoot)) {
+      loadedComponents.add(dependency);
       Set<Uri> excluded = externalLibs(dependency);
       dillTarget.loader.appendLibraries(dependency,
           filter: (uri) => !excluded.contains(uri));
@@ -174,6 +178,8 @@
     return new InternalCompilerResult(
         summary: summary,
         component: component,
+        sdkComponent: sdkSummary,
+        loadedComponents: loadedComponents,
         classHierarchy:
             includeHierarchyAndCoreTypes ? kernelTarget.loader.hierarchy : null,
         coreTypes:
@@ -191,6 +197,10 @@
   /// The generated component, if it was requested.
   final Component component;
 
+  final Component sdkComponent;
+
+  final List<Component> loadedComponents;
+
   /// Dependencies traversed by the compiler. Used only for generating
   /// dependency .GN files in the dart-sdk build system.
   /// Note this might be removed when we switch to compute dependencies without
@@ -209,6 +219,8 @@
   InternalCompilerResult(
       {this.summary,
       this.component,
+      this.sdkComponent,
+      this.loadedComponents,
       this.deps,
       this.classHierarchy,
       this.coreTypes,
diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status
index 9901425..e420f29 100644
--- a/pkg/front_end/messages.status
+++ b/pkg/front_end/messages.status
@@ -327,7 +327,6 @@
 InterfaceCheck/analyzerCode: Fail
 InterfaceCheck/example: Fail
 InterpolationInUri/example: Fail
-IntersectionTypeAsTypeArgument/analyzerCode: Fail # Analyzer doesn't catch this error.
 InvalidBreakTarget/analyzerCode: Fail
 InvalidBreakTarget/example: Fail
 InvalidCastFunctionExpr/example: Fail
@@ -537,6 +536,7 @@
 TypeVariableInStaticContext/part_wrapped_declaration4: Fail
 TypeVariableSameNameAsEnclosing/example: Fail
 TypedefNotFunction/example: Fail
+TypedefNotType/example: Fail # Feature not yet enabled by default.
 UnexpectedToken/part_wrapped_script1: Fail
 UnexpectedToken/script1: Fail
 UnmatchedToken/part_wrapped_script1: Fail
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index 670a401..e8794be 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -1298,8 +1298,10 @@
     - "class C { int C() {} }"
 
 ConstructorWithTypeParameters:
+  index: 99
   template: "Constructors can't have type parameters."
-  analyzerCode: TYPE_PARAMETER_ON_CONSTRUCTOR
+  analyzerCode: ParserErrorCode.TYPE_PARAMETER_ON_CONSTRUCTOR
+  tip: "Try removing the type parameters."
   script:
     - "class C { C<T>() {} }"
     - "class C { C.foo<T>() {} }"
@@ -2117,6 +2119,10 @@
   template: "Can't create typedef from non-function type."
   analyzerCode: INVALID_GENERIC_FUNCTION_TYPE
 
+TypedefNotType:
+  template: "Can't create typedef from non-type."
+  analyzerCode: INVALID_TYPE_IN_TYPEDEF
+
 LibraryDirectiveNotFirst:
   index: 37
   template: "The library directive must appear before all other directives."
@@ -3371,15 +3377,6 @@
   template: "This is the type variable whose bound isn't conformed to."
   severity: CONTEXT
 
-IntersectionTypeAsTypeArgument:
-  template: "Can't infer a type for '#name', it can be either '#type' or '#type2'."
-  tip: "Try adding a type argument selecting one of the options."
-  script: |
-    class A {}
-    class B extends A {}
-    f<T>(T t) => null;
-    g<S>(S t) => t is B ? f(t) : null;
-
 InferredPackageUri:
   template: "Interpreting this as package URI, '#uri'."
   severity: WARNING
diff --git a/pkg/front_end/parser_testcases/error_recovery/empty_await_for.dart.expect b/pkg/front_end/parser_testcases/error_recovery/empty_await_for.dart.expect
index 2199837..3c0cebd 100644
--- a/pkg/front_end/parser_testcases/error_recovery/empty_await_for.dart.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/empty_await_for.dart.expect
@@ -1,18 +1,18 @@
 Problems reported:
 
-parser_test/error_recovery/empty_await_for:2:14: Expected an identifier, but got ')'.
+parser/error_recovery/empty_await_for:2:14: Expected an identifier, but got ')'.
   await for () {}
              ^
 
-parser_test/error_recovery/empty_await_for:2:14: Expected 'in' before this.
+parser/error_recovery/empty_await_for:2:14: Expected 'in' before this.
   await for () {}
              ^
 
-parser_test/error_recovery/empty_await_for:2:14: Expected an identifier, but got ')'.
+parser/error_recovery/empty_await_for:2:14: Expected an identifier, but got ')'.
   await for () {}
              ^
 
-parser_test/error_recovery/empty_await_for:2:14: Expected an identifier, but got ')'.
+parser/error_recovery/empty_await_for:2:14: Expected an identifier, but got ')'.
   await for () {}
              ^
 
diff --git a/pkg/front_end/parser_testcases/error_recovery/empty_for.dart.expect b/pkg/front_end/parser_testcases/error_recovery/empty_for.dart.expect
index 63dc838..83797a0 100644
--- a/pkg/front_end/parser_testcases/error_recovery/empty_for.dart.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/empty_for.dart.expect
@@ -1,18 +1,18 @@
 Problems reported:
 
-parser_test/error_recovery/empty_for:2:8: Expected an identifier, but got ')'.
+parser/error_recovery/empty_for:2:8: Expected an identifier, but got ')'.
   for () {}
        ^
 
-parser_test/error_recovery/empty_for:2:8: Expected ';' after this.
+parser/error_recovery/empty_for:2:8: Expected ';' after this.
   for () {}
        ^
 
-parser_test/error_recovery/empty_for:2:8: Expected an identifier, but got ')'.
+parser/error_recovery/empty_for:2:8: Expected an identifier, but got ')'.
   for () {}
        ^
 
-parser_test/error_recovery/empty_for:2:8: Expected ';' after this.
+parser/error_recovery/empty_for:2:8: Expected ';' after this.
   for () {}
        ^
 
diff --git a/pkg/front_end/parser_testcases/error_recovery/issue_38415.crash_dart.expect b/pkg/front_end/parser_testcases/error_recovery/issue_38415.crash_dart.expect
index 3f943f9..4263813 100644
--- a/pkg/front_end/parser_testcases/error_recovery/issue_38415.crash_dart.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/issue_38415.crash_dart.expect
@@ -1,10 +1,10 @@
 Problems reported:
 
-parser_test/error_recovery/issue_38415.crash:1:15: Expected '[' before this.
+parser/error_recovery/issue_38415.crash:1:15: Expected '[' before this.
 f() { m(T<R(<Z
               ^...
 
-parser_test/error_recovery/issue_38415.crash:1:15: Expected ';' after this.
+parser/error_recovery/issue_38415.crash:1:15: Expected ';' after this.
 f() { m(T<R(<Z
               ^...
 
diff --git a/pkg/front_end/parser_testcases/error_recovery/issue_39024.crash_dart.expect b/pkg/front_end/parser_testcases/error_recovery/issue_39024.crash_dart.expect
index 8edc8ca..b06508d 100644
--- a/pkg/front_end/parser_testcases/error_recovery/issue_39024.crash_dart.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/issue_39024.crash_dart.expect
@@ -1,18 +1,18 @@
 Problems reported:
 
-parser_test/error_recovery/issue_39024.crash:1:3: Expected '>' after this.
+parser/error_recovery/issue_39024.crash:1:3: Expected '>' after this.
 n<S e(
   ^
 
-parser_test/error_recovery/issue_39024.crash:1:7: Expected an identifier, but got ''.
+parser/error_recovery/issue_39024.crash:1:7: Expected an identifier, but got ''.
 n<S e(
       ^...
 
-parser_test/error_recovery/issue_39024.crash:1:7: A function declaration needs an explicit list of parameters.
+parser/error_recovery/issue_39024.crash:1:7: A function declaration needs an explicit list of parameters.
 n<S e(
       ^...
 
-parser_test/error_recovery/issue_39024.crash:1:7: Expected a function body, but got ''.
+parser/error_recovery/issue_39024.crash:1:7: Expected a function body, but got ''.
 n<S e(
       ^...
 
diff --git a/pkg/front_end/parser_testcases/error_recovery/issue_39026.crash_dart.expect b/pkg/front_end/parser_testcases/error_recovery/issue_39026.crash_dart.expect
index 01f26fa..0f4b8c9 100644
--- a/pkg/front_end/parser_testcases/error_recovery/issue_39026.crash_dart.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/issue_39026.crash_dart.expect
@@ -1,10 +1,10 @@
 Problems reported:
 
-parser_test/error_recovery/issue_39026.crash:2:8: Operator declarations must be preceded by the keyword 'operator'.
+parser/error_recovery/issue_39026.crash:2:8: Operator declarations must be preceded by the keyword 'operator'.
     co <{
        ^
 
-parser_test/error_recovery/issue_39026.crash:2:8: A method declaration needs an explicit list of parameters.
+parser/error_recovery/issue_39026.crash:2:8: A method declaration needs an explicit list of parameters.
     co <{
        ^
 
diff --git a/pkg/front_end/parser_testcases/error_recovery/issue_39026_prime.crash_dart.expect b/pkg/front_end/parser_testcases/error_recovery/issue_39026_prime.crash_dart.expect
index 93a5c86..ada43dbc 100644
--- a/pkg/front_end/parser_testcases/error_recovery/issue_39026_prime.crash_dart.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/issue_39026_prime.crash_dart.expect
@@ -1,6 +1,6 @@
 Problems reported:
 
-parser_test/error_recovery/issue_39026_prime.crash:2:17: A method declaration needs an explicit list of parameters.
+parser/error_recovery/issue_39026_prime.crash:2:17: A method declaration needs an explicit list of parameters.
     co operator <{
                 ^
 
diff --git a/pkg/front_end/parser_testcases/error_recovery/issue_39033.crash_dart.expect b/pkg/front_end/parser_testcases/error_recovery/issue_39033.crash_dart.expect
index 456c08a..852c662 100644
--- a/pkg/front_end/parser_testcases/error_recovery/issue_39033.crash_dart.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/issue_39033.crash_dart.expect
@@ -1,14 +1,14 @@
 Problems reported:
 
-parser_test/error_recovery/issue_39033.crash:1:11: Expected '>' after this.
+parser/error_recovery/issue_39033.crash:1:11: Expected '>' after this.
 typedef F<Glib.=
           ^^^^
 
-parser_test/error_recovery/issue_39033.crash:1:17: Expected a type, but got ''.
+parser/error_recovery/issue_39033.crash:1:17: Expected a type, but got ''.
 typedef F<Glib.=
                 ^...
 
-parser_test/error_recovery/issue_39033.crash:1:17: Expected ';' after this.
+parser/error_recovery/issue_39033.crash:1:17: Expected ';' after this.
 typedef F<Glib.=
                 ^...
 
diff --git a/pkg/front_end/parser_testcases/error_recovery/issue_39058.crash_dart.expect b/pkg/front_end/parser_testcases/error_recovery/issue_39058.crash_dart.expect
index c326fd9..c60bbb7 100644
--- a/pkg/front_end/parser_testcases/error_recovery/issue_39058.crash_dart.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/issue_39058.crash_dart.expect
@@ -1,6 +1,6 @@
 Problems reported:
 
-parser_test/error_recovery/issue_39058.crash:1:1: Expected a declaration, but got '{'.
+parser/error_recovery/issue_39058.crash:1:1: Expected a declaration, but got '{'.
 {<[](
 ^
 
diff --git a/pkg/front_end/parser_testcases/error_recovery/issue_39058_prime.crash_dart.expect b/pkg/front_end/parser_testcases/error_recovery/issue_39058_prime.crash_dart.expect
index fdabfa1..b249f5c 100644
--- a/pkg/front_end/parser_testcases/error_recovery/issue_39058_prime.crash_dart.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/issue_39058_prime.crash_dart.expect
@@ -1,6 +1,6 @@
 Problems reported:
 
-parser_test/error_recovery/issue_39058_prime.crash:1:1: Expected a declaration, but got '{'.
+parser/error_recovery/issue_39058_prime.crash:1:1: Expected a declaration, but got '{'.
 {<[]()>}
 ^
 
diff --git a/pkg/front_end/parser_testcases/error_recovery/issue_39060.dart.expect b/pkg/front_end/parser_testcases/error_recovery/issue_39060.dart.expect
index e6e34e2..a94d802 100644
--- a/pkg/front_end/parser_testcases/error_recovery/issue_39060.dart.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/issue_39060.dart.expect
@@ -1,18 +1,18 @@
 Problems reported:
 
-parser_test/error_recovery/issue_39060:2:6: Expected ';' after this.
+parser/error_recovery/issue_39060:2:6: Expected ';' after this.
   {s A<}>
      ^
 
-parser_test/error_recovery/issue_39060:2:8: Expected a type, but got '}'.
+parser/error_recovery/issue_39060:2:8: Expected a type, but got '}'.
   {s A<}>
        ^
 
-parser_test/error_recovery/issue_39060:3:1: Expected '[' before this.
+parser/error_recovery/issue_39060:3:1: Expected '[' before this.
 }
 ^
 
-parser_test/error_recovery/issue_39060:3:1: Expected ';' after this.
+parser/error_recovery/issue_39060:3:1: Expected ';' after this.
 }
 ^
 
diff --git a/pkg/front_end/parser_testcases/error_recovery/issue_39202.crash_dart.expect b/pkg/front_end/parser_testcases/error_recovery/issue_39202.crash_dart.expect
index a38a1ad..1f51f02 100644
--- a/pkg/front_end/parser_testcases/error_recovery/issue_39202.crash_dart.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/issue_39202.crash_dart.expect
@@ -1,30 +1,30 @@
 Problems reported:
 
-parser_test/error_recovery/issue_39202.crash:1:1: Expected a declaration, but got '('.
+parser/error_recovery/issue_39202.crash:1:1: Expected a declaration, but got '('.
 () async => a b < c $? >
 ^
 
-parser_test/error_recovery/issue_39202.crash:1:2: Expected a declaration, but got ')'.
+parser/error_recovery/issue_39202.crash:1:2: Expected a declaration, but got ')'.
 () async => a b < c $? >
  ^
 
-parser_test/error_recovery/issue_39202.crash:1:4: A function declaration needs an explicit list of parameters.
+parser/error_recovery/issue_39202.crash:1:4: A function declaration needs an explicit list of parameters.
 () async => a b < c $? >
    ^^^^^
 
-parser_test/error_recovery/issue_39202.crash:1:13: Expected ';' after this.
+parser/error_recovery/issue_39202.crash:1:13: Expected ';' after this.
 () async => a b < c $? >
             ^
 
-parser_test/error_recovery/issue_39202.crash:1:19: Expected '>' after this.
+parser/error_recovery/issue_39202.crash:1:19: Expected '>' after this.
 () async => a b < c $? >
                   ^
 
-parser_test/error_recovery/issue_39202.crash:1:25: Expected an identifier, but got ''.
+parser/error_recovery/issue_39202.crash:1:25: Expected an identifier, but got ''.
 () async => a b < c $? >
                         ^...
 
-parser_test/error_recovery/issue_39202.crash:1:25: Expected ';' after this.
+parser/error_recovery/issue_39202.crash:1:25: Expected ';' after this.
 () async => a b < c $? >
                         ^...
 
diff --git a/pkg/front_end/parser_testcases/error_recovery/issue_39230.crash_dart.expect b/pkg/front_end/parser_testcases/error_recovery/issue_39230.crash_dart.expect
index 4d40dc0..eabc61b 100644
--- a/pkg/front_end/parser_testcases/error_recovery/issue_39230.crash_dart.expect
+++ b/pkg/front_end/parser_testcases/error_recovery/issue_39230.crash_dart.expect
@@ -1,14 +1,14 @@
 Problems reported:
 
-parser_test/error_recovery/issue_39230.crash:3:5: Expected a function body, but got '/'.
+parser/error_recovery/issue_39230.crash:3:5: Expected a function body, but got '/'.
     /
     ^
 
-parser_test/error_recovery/issue_39230.crash:3:5: Operator declarations must be preceded by the keyword 'operator'.
+parser/error_recovery/issue_39230.crash:3:5: Operator declarations must be preceded by the keyword 'operator'.
     /
     ^
 
-parser_test/error_recovery/issue_39230.crash:3:5: A method declaration needs an explicit list of parameters.
+parser/error_recovery/issue_39230.crash:3:5: A method declaration needs an explicit list of parameters.
     /
     ^
 
diff --git a/pkg/front_end/parser_testcases/extensions/covariant.dart.expect b/pkg/front_end/parser_testcases/extensions/covariant.dart.expect
index a565916..c797564 100644
--- a/pkg/front_end/parser_testcases/extensions/covariant.dart.expect
+++ b/pkg/front_end/parser_testcases/extensions/covariant.dart.expect
@@ -1,6 +1,6 @@
 Problems reported:
 
-parser_test/extensions/covariant:6:12: Can't have modifier 'covariant' in an extension.
+parser/extensions/covariant:6:12: Can't have modifier 'covariant' in an extension.
   addChild(covariant A child) {}
            ^^^^^^^^^
 
diff --git a/pkg/front_end/parser_testcases/extensions/static_covariant.dart.expect b/pkg/front_end/parser_testcases/extensions/static_covariant.dart.expect
index 02f803f..1468b4e 100644
--- a/pkg/front_end/parser_testcases/extensions/static_covariant.dart.expect
+++ b/pkg/front_end/parser_testcases/extensions/static_covariant.dart.expect
@@ -1,6 +1,6 @@
 Problems reported:
 
-parser_test/extensions/static_covariant:6:19: Can't have modifier 'covariant' in an extension.
+parser/extensions/static_covariant:6:19: Can't have modifier 'covariant' in an extension.
   static addChild(covariant A child) {}
                   ^^^^^^^^^
 
diff --git a/pkg/front_end/parser_testcases/general/operator_hat_class.crash_dart.expect b/pkg/front_end/parser_testcases/general/operator_hat_class.crash_dart.expect
index c341804..448f507 100644
--- a/pkg/front_end/parser_testcases/general/operator_hat_class.crash_dart.expect
+++ b/pkg/front_end/parser_testcases/general/operator_hat_class.crash_dart.expect
@@ -1,6 +1,6 @@
 Problems reported:
 
-parser_test/general/operator_hat_class.crash:1:7: Can't use 'operator' as a name here.
+parser/general/operator_hat_class.crash:1:7: Can't use 'operator' as a name here.
 class operator {
       ^^^^^^^^
 
diff --git a/pkg/front_end/parser_testcases/nnbd/null_shorting_index.dart b/pkg/front_end/parser_testcases/nnbd/null_shorting_index.dart
new file mode 100644
index 0000000..66d340e
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/null_shorting_index.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2019, 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 Class1 {
+  int operator [](int index) => index;
+  void operator []=(int index, int value) {}
+}
+
+main() {
+  Class1? c1;
+  c1?.[0];
+  c1?.[0] = 1;
+}
diff --git a/pkg/front_end/parser_testcases/nnbd/null_shorting_index.dart.expect b/pkg/front_end/parser_testcases/nnbd/null_shorting_index.dart.expect
new file mode 100644
index 0000000..6e54c69
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/null_shorting_index.dart.expect
@@ -0,0 +1,120 @@
+beginCompilationUnit(class)
+  beginMetadataStar(class)
+  endMetadataStar(0)
+  beginClassOrNamedMixinApplicationPrelude(class)
+    handleIdentifier(Class1, classOrMixinDeclaration)
+    handleNoTypeVariables({)
+    beginClassDeclaration(class, null, Class1)
+      handleNoType(Class1)
+      handleClassExtends(null)
+      handleClassNoWithClause()
+      handleClassOrMixinImplements(null, 0)
+      handleClassHeader(class, class, null)
+      beginClassOrMixinBody(DeclarationKind.Class, {)
+        beginMetadataStar(int)
+        endMetadataStar(0)
+        beginMember()
+          beginMethod(null, null, null, null, null, operator)
+            handleIdentifier(int, typeReference)
+            handleNoTypeArguments(operator)
+            handleType(int, null)
+            handleOperatorName(operator, [])
+            handleNoTypeVariables(()
+            beginFormalParameters((, MemberKind.NonStaticMethod)
+              beginMetadataStar(int)
+              endMetadataStar(0)
+              beginFormalParameter(int, MemberKind.NonStaticMethod, null, null, null)
+                handleIdentifier(int, typeReference)
+                handleNoTypeArguments(index)
+                handleType(int, null)
+                handleIdentifier(index, formalParameterDeclaration)
+                handleFormalParameterWithoutValue())
+              endFormalParameter(null, null, index, null, null, FormalParameterKind.mandatory, MemberKind.NonStaticMethod)
+            endFormalParameters(1, (, ), MemberKind.NonStaticMethod)
+            handleNoInitializers()
+            handleAsyncModifier(null, null)
+            handleIdentifier(index, expression)
+            handleNoTypeArguments(;)
+            handleNoArguments(;)
+            handleSend(index, ;)
+            handleExpressionFunctionBody(=>, ;)
+          endClassMethod(null, int, (, null, ;)
+        endMember()
+        beginMetadataStar(void)
+        endMetadataStar(0)
+        beginMember()
+          beginMethod(null, null, null, null, null, operator)
+            handleVoidKeyword(void)
+            handleOperatorName(operator, []=)
+            handleNoTypeVariables(()
+            beginFormalParameters((, MemberKind.NonStaticMethod)
+              beginMetadataStar(int)
+              endMetadataStar(0)
+              beginFormalParameter(int, MemberKind.NonStaticMethod, null, null, null)
+                handleIdentifier(int, typeReference)
+                handleNoTypeArguments(index)
+                handleType(int, null)
+                handleIdentifier(index, formalParameterDeclaration)
+                handleFormalParameterWithoutValue(,)
+              endFormalParameter(null, null, index, null, null, FormalParameterKind.mandatory, MemberKind.NonStaticMethod)
+              beginMetadataStar(int)
+              endMetadataStar(0)
+              beginFormalParameter(int, MemberKind.NonStaticMethod, null, null, null)
+                handleIdentifier(int, typeReference)
+                handleNoTypeArguments(value)
+                handleType(int, null)
+                handleIdentifier(value, formalParameterDeclaration)
+                handleFormalParameterWithoutValue())
+              endFormalParameter(null, null, value, null, null, FormalParameterKind.mandatory, MemberKind.NonStaticMethod)
+            endFormalParameters(2, (, ), MemberKind.NonStaticMethod)
+            handleNoInitializers()
+            handleAsyncModifier(null, null)
+            beginBlockFunctionBody({)
+            endBlockFunctionBody(0, {, })
+          endClassMethod(null, void, (, null, })
+        endMember()
+      endClassOrMixinBody(DeclarationKind.Class, 2, {, })
+    endClassDeclaration(class, })
+  endTopLevelDeclaration(main)
+  beginMetadataStar(main)
+  endMetadataStar(0)
+  beginTopLevelMember(main)
+    beginTopLevelMethod(}, null)
+      handleNoType(})
+      handleIdentifier(main, topLevelFunctionDeclaration)
+      handleNoTypeVariables(()
+      beginFormalParameters((, MemberKind.TopLevelMethod)
+      endFormalParameters(0, (, ), MemberKind.TopLevelMethod)
+      handleAsyncModifier(null, null)
+      beginBlockFunctionBody({)
+        beginMetadataStar(Class1)
+        endMetadataStar(0)
+        handleIdentifier(Class1, typeReference)
+        handleNoTypeArguments(?)
+        handleType(Class1, ?)
+        beginVariablesDeclaration(c1, null, null)
+          handleIdentifier(c1, localVariableDeclaration)
+          beginInitializedIdentifier(c1)
+            handleNoVariableInitializer(;)
+          endInitializedIdentifier(c1)
+        endVariablesDeclaration(1, ;)
+        handleIdentifier(c1, expression)
+        handleNoTypeArguments(?.[)
+        handleNoArguments(?.[)
+        handleSend(c1, ?.[)
+        handleLiteralInt(0)
+        handleIndexedExpression(?.[, ])
+        handleExpressionStatement(;)
+        handleIdentifier(c1, expression)
+        handleNoTypeArguments(?.[)
+        handleNoArguments(?.[)
+        handleSend(c1, ?.[)
+        handleLiteralInt(0)
+        handleIndexedExpression(?.[, ])
+        handleLiteralInt(1)
+        handleAssignmentExpression(=)
+        handleExpressionStatement(;)
+      endBlockFunctionBody(3, {, })
+    endTopLevelMethod(main, null, })
+  endTopLevelDeclaration()
+endCompilationUnit(2, )
diff --git a/pkg/front_end/parser_testcases/nnbd/null_shorting_index.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/null_shorting_index.dart.intertwined.expect
new file mode 100644
index 0000000..b22c287
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/null_shorting_index.dart.intertwined.expect
@@ -0,0 +1,255 @@
+parseUnit(class)
+  skipErrorTokens(class)
+  listener: beginCompilationUnit(class)
+  syntheticPreviousToken(class)
+  parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext')
+    parseMetadataStar()
+      listener: beginMetadataStar(class)
+      listener: endMetadataStar(0)
+    parseTopLevelKeywordDeclaration(, class, Instance of 'DirectiveContext')
+      parseClassDeclarationModifiers(, class)
+      parseClassOrNamedMixinApplication(null, class)
+        listener: beginClassOrNamedMixinApplicationPrelude(class)
+        ensureIdentifier(class, classOrMixinDeclaration)
+          listener: handleIdentifier(Class1, classOrMixinDeclaration)
+        listener: handleNoTypeVariables({)
+        listener: beginClassDeclaration(class, null, Class1)
+        parseClass(Class1, class, class, Class1)
+          parseClassHeaderOpt(Class1, class, class)
+            parseClassExtendsOpt(Class1)
+              listener: handleNoType(Class1)
+              listener: handleClassExtends(null)
+            parseWithClauseOpt(Class1)
+              listener: handleClassNoWithClause()
+            parseClassOrMixinImplementsOpt(Class1)
+              listener: handleClassOrMixinImplements(null, 0)
+            listener: handleClassHeader(class, class, null)
+          parseClassOrMixinOrExtensionBody(Class1, DeclarationKind.Class, Class1)
+            listener: beginClassOrMixinBody(DeclarationKind.Class, {)
+            notEofOrValue(}, int)
+            parseClassOrMixinOrExtensionMemberImpl({, DeclarationKind.Class, Class1)
+              parseMetadataStar({)
+                listener: beginMetadataStar(int)
+                listener: endMetadataStar(0)
+              listener: beginMember()
+              parseMethod({, null, null, null, null, null, {, Instance of 'SimpleType', null, operator, DeclarationKind.Class, Class1)
+                listener: beginMethod(null, null, null, null, null, operator)
+                listener: handleIdentifier(int, typeReference)
+                listener: handleNoTypeArguments(operator)
+                listener: handleType(int, null)
+                parseOperatorName(int)
+                  listener: handleOperatorName(operator, [])
+                parseMethodTypeVar([])
+                  listener: handleNoTypeVariables(()
+                parseGetterOrFormalParameters([], operator, false, MemberKind.NonStaticMethod)
+                  parseFormalParameters([], MemberKind.NonStaticMethod)
+                    parseFormalParametersRest((, MemberKind.NonStaticMethod)
+                      listener: beginFormalParameters((, MemberKind.NonStaticMethod)
+                      parseFormalParameter((, FormalParameterKind.mandatory, MemberKind.NonStaticMethod)
+                        parseMetadataStar(()
+                          listener: beginMetadataStar(int)
+                          listener: endMetadataStar(0)
+                        listener: beginFormalParameter(int, MemberKind.NonStaticMethod, null, null, null)
+                        listener: handleIdentifier(int, typeReference)
+                        listener: handleNoTypeArguments(index)
+                        listener: handleType(int, null)
+                        ensureIdentifier(int, formalParameterDeclaration)
+                          listener: handleIdentifier(index, formalParameterDeclaration)
+                        listener: handleFormalParameterWithoutValue())
+                        listener: endFormalParameter(null, null, index, null, null, FormalParameterKind.mandatory, MemberKind.NonStaticMethod)
+                      listener: endFormalParameters(1, (, ), MemberKind.NonStaticMethod)
+                parseInitializersOpt())
+                  listener: handleNoInitializers()
+                parseAsyncModifierOpt())
+                  listener: handleAsyncModifier(null, null)
+                  inPlainSync()
+                inPlainSync()
+                parseFunctionBody(), false, true)
+                  parseExpressionFunctionBody(=>, false)
+                    parseExpression(=>)
+                      parsePrecedenceExpression(=>, 1, true)
+                        parseUnaryExpression(=>, true)
+                          parsePrimary(=>, expression)
+                            parseSendOrFunctionLiteral(=>, expression)
+                              parseSend(=>, expression)
+                                ensureIdentifier(=>, expression)
+                                  listener: handleIdentifier(index, expression)
+                                listener: handleNoTypeArguments(;)
+                                parseArgumentsOpt(index)
+                                  listener: handleNoArguments(;)
+                                listener: handleSend(index, ;)
+                    ensureSemicolon(index)
+                    listener: handleExpressionFunctionBody(=>, ;)
+                    inGenerator()
+                listener: endClassMethod(null, int, (, null, ;)
+              listener: endMember()
+            notEofOrValue(}, void)
+            parseClassOrMixinOrExtensionMemberImpl(;, DeclarationKind.Class, Class1)
+              parseMetadataStar(;)
+                listener: beginMetadataStar(void)
+                listener: endMetadataStar(0)
+              listener: beginMember()
+              parseMethod(;, null, null, null, null, null, ;, Instance of 'VoidType', null, operator, DeclarationKind.Class, Class1)
+                listener: beginMethod(null, null, null, null, null, operator)
+                listener: handleVoidKeyword(void)
+                parseOperatorName(void)
+                  listener: handleOperatorName(operator, []=)
+                parseMethodTypeVar([]=)
+                  listener: handleNoTypeVariables(()
+                parseGetterOrFormalParameters([]=, operator, false, MemberKind.NonStaticMethod)
+                  parseFormalParameters([]=, MemberKind.NonStaticMethod)
+                    parseFormalParametersRest((, MemberKind.NonStaticMethod)
+                      listener: beginFormalParameters((, MemberKind.NonStaticMethod)
+                      parseFormalParameter((, FormalParameterKind.mandatory, MemberKind.NonStaticMethod)
+                        parseMetadataStar(()
+                          listener: beginMetadataStar(int)
+                          listener: endMetadataStar(0)
+                        listener: beginFormalParameter(int, MemberKind.NonStaticMethod, null, null, null)
+                        listener: handleIdentifier(int, typeReference)
+                        listener: handleNoTypeArguments(index)
+                        listener: handleType(int, null)
+                        ensureIdentifier(int, formalParameterDeclaration)
+                          listener: handleIdentifier(index, formalParameterDeclaration)
+                        listener: handleFormalParameterWithoutValue(,)
+                        listener: endFormalParameter(null, null, index, null, null, FormalParameterKind.mandatory, MemberKind.NonStaticMethod)
+                      parseFormalParameter(,, FormalParameterKind.mandatory, MemberKind.NonStaticMethod)
+                        parseMetadataStar(,)
+                          listener: beginMetadataStar(int)
+                          listener: endMetadataStar(0)
+                        listener: beginFormalParameter(int, MemberKind.NonStaticMethod, null, null, null)
+                        listener: handleIdentifier(int, typeReference)
+                        listener: handleNoTypeArguments(value)
+                        listener: handleType(int, null)
+                        ensureIdentifier(int, formalParameterDeclaration)
+                          listener: handleIdentifier(value, formalParameterDeclaration)
+                        listener: handleFormalParameterWithoutValue())
+                        listener: endFormalParameter(null, null, value, null, null, FormalParameterKind.mandatory, MemberKind.NonStaticMethod)
+                      listener: endFormalParameters(2, (, ), MemberKind.NonStaticMethod)
+                parseInitializersOpt())
+                  listener: handleNoInitializers()
+                parseAsyncModifierOpt())
+                  listener: handleAsyncModifier(null, null)
+                  inPlainSync()
+                inPlainSync()
+                parseFunctionBody(), false, true)
+                  listener: beginBlockFunctionBody({)
+                  notEofOrValue(}, })
+                  listener: endBlockFunctionBody(0, {, })
+                listener: endClassMethod(null, void, (, null, })
+              listener: endMember()
+            notEofOrValue(}, })
+            listener: endClassOrMixinBody(DeclarationKind.Class, 2, {, })
+          listener: endClassDeclaration(class, })
+  listener: endTopLevelDeclaration(main)
+  parseTopLevelDeclarationImpl(}, Instance of 'DirectiveContext')
+    parseMetadataStar(})
+      listener: beginMetadataStar(main)
+      listener: endMetadataStar(0)
+    parseTopLevelMemberImpl(})
+      listener: beginTopLevelMember(main)
+      parseTopLevelMethod(}, null, }, Instance of 'NoType', null, main)
+        listener: beginTopLevelMethod(}, null)
+        listener: handleNoType(})
+        ensureIdentifier(}, topLevelFunctionDeclaration)
+          listener: handleIdentifier(main, topLevelFunctionDeclaration)
+        parseMethodTypeVar(main)
+          listener: handleNoTypeVariables(()
+        parseGetterOrFormalParameters(main, main, false, MemberKind.TopLevelMethod)
+          parseFormalParameters(main, MemberKind.TopLevelMethod)
+            parseFormalParametersRest((, MemberKind.TopLevelMethod)
+              listener: beginFormalParameters((, MemberKind.TopLevelMethod)
+              listener: endFormalParameters(0, (, ), MemberKind.TopLevelMethod)
+        parseAsyncModifierOpt())
+          listener: handleAsyncModifier(null, null)
+          inPlainSync()
+        parseFunctionBody(), false, false)
+          listener: beginBlockFunctionBody({)
+          notEofOrValue(}, Class1)
+          parseStatement({)
+            parseStatementX({)
+              parseExpressionStatementOrDeclarationAfterModifiers({, {, null, null, null, false)
+                looksLikeLocalFunction(c1)
+                listener: beginMetadataStar(Class1)
+                listener: endMetadataStar(0)
+                listener: handleIdentifier(Class1, typeReference)
+                listener: handleNoTypeArguments(?)
+                listener: handleType(Class1, ?)
+                listener: beginVariablesDeclaration(c1, null, null)
+                parseVariablesDeclarationRest(?, true)
+                  parseOptionallyInitializedIdentifier(?)
+                    ensureIdentifier(?, localVariableDeclaration)
+                      listener: handleIdentifier(c1, localVariableDeclaration)
+                    listener: beginInitializedIdentifier(c1)
+                    parseVariableInitializerOpt(c1)
+                      listener: handleNoVariableInitializer(;)
+                    listener: endInitializedIdentifier(c1)
+                  ensureSemicolon(c1)
+                  listener: endVariablesDeclaration(1, ;)
+          notEofOrValue(}, c1)
+          parseStatement(;)
+            parseStatementX(;)
+              parseExpressionStatementOrDeclarationAfterModifiers(;, ;, null, null, null, false)
+                looksLikeLocalFunction(c1)
+                parseExpressionStatement(;)
+                  parseExpression(;)
+                    parsePrecedenceExpression(;, 1, true)
+                      parseUnaryExpression(;, true)
+                        parsePrimary(;, expression)
+                          parseSendOrFunctionLiteral(;, expression)
+                            parseSend(;, expression)
+                              ensureIdentifier(;, expression)
+                                listener: handleIdentifier(c1, expression)
+                              listener: handleNoTypeArguments(?.[)
+                              parseArgumentsOpt(c1)
+                                listener: handleNoArguments(?.[)
+                              listener: handleSend(c1, ?.[)
+                      parseArgumentOrIndexStar(c1, Instance of 'NoTypeParamOrArg')
+                        parseExpression(?.[)
+                          parsePrecedenceExpression(?.[, 1, true)
+                            parseUnaryExpression(?.[, true)
+                              parsePrimary(?.[, expression)
+                                parseLiteralInt(?.[)
+                                  listener: handleLiteralInt(0)
+                        listener: handleIndexedExpression(?.[, ])
+                  ensureSemicolon(])
+                  listener: handleExpressionStatement(;)
+          notEofOrValue(}, c1)
+          parseStatement(;)
+            parseStatementX(;)
+              parseExpressionStatementOrDeclarationAfterModifiers(;, ;, null, null, null, false)
+                looksLikeLocalFunction(c1)
+                parseExpressionStatement(;)
+                  parseExpression(;)
+                    parsePrecedenceExpression(;, 1, true)
+                      parseUnaryExpression(;, true)
+                        parsePrimary(;, expression)
+                          parseSendOrFunctionLiteral(;, expression)
+                            parseSend(;, expression)
+                              ensureIdentifier(;, expression)
+                                listener: handleIdentifier(c1, expression)
+                              listener: handleNoTypeArguments(?.[)
+                              parseArgumentsOpt(c1)
+                                listener: handleNoArguments(?.[)
+                              listener: handleSend(c1, ?.[)
+                      parseArgumentOrIndexStar(c1, Instance of 'NoTypeParamOrArg')
+                        parseExpression(?.[)
+                          parsePrecedenceExpression(?.[, 1, true)
+                            parseUnaryExpression(?.[, true)
+                              parsePrimary(?.[, expression)
+                                parseLiteralInt(?.[)
+                                  listener: handleLiteralInt(0)
+                        listener: handleIndexedExpression(?.[, ])
+                      parsePrecedenceExpression(=, 1, true)
+                        parseUnaryExpression(=, true)
+                          parsePrimary(=, expression)
+                            parseLiteralInt(=)
+                              listener: handleLiteralInt(1)
+                      listener: handleAssignmentExpression(=)
+                  ensureSemicolon(1)
+                  listener: handleExpressionStatement(;)
+          notEofOrValue(}, })
+          listener: endBlockFunctionBody(3, {, })
+        listener: endTopLevelMethod(main, null, })
+  listener: endTopLevelDeclaration()
+  reportAllErrorTokens(class)
+  listener: endCompilationUnit(2, )
diff --git a/pkg/front_end/parser_testcases/nnbd/null_shorting_index.dart.parser.expect b/pkg/front_end/parser_testcases/nnbd/null_shorting_index.dart.parser.expect
new file mode 100644
index 0000000..9dc7175
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/null_shorting_index.dart.parser.expect
@@ -0,0 +1,23 @@
+class Class1 {
+int operator [](int index) => index;
+void operator []=(int index, int value) {}
+}
+
+main() {
+Class1? c1;
+c1?.[0];
+c1?.[0] = 1;
+}
+
+
+class[KeywordToken] Class1[StringToken] {[BeginToken]
+int[StringToken] operator[KeywordToken] [][SimpleToken]([BeginToken]int[StringToken] index[StringToken])[SimpleToken] =>[SimpleToken] index[StringToken];[SimpleToken]
+void[KeywordToken] operator[KeywordToken] []=[SimpleToken]([BeginToken]int[StringToken] index[StringToken],[SimpleToken] int[StringToken] value[StringToken])[SimpleToken] {[BeginToken]}[SimpleToken]
+}[SimpleToken]
+
+main[StringToken]([BeginToken])[SimpleToken] {[BeginToken]
+Class1[StringToken]?[SimpleToken] c1[StringToken];[SimpleToken]
+c1[StringToken]?.[[BeginToken]0[StringToken]][SimpleToken];[SimpleToken]
+c1[StringToken]?.[[BeginToken]0[StringToken]][SimpleToken] =[SimpleToken] 1[StringToken];[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/parser_testcases/nnbd/null_shorting_index.dart.scanner.expect b/pkg/front_end/parser_testcases/nnbd/null_shorting_index.dart.scanner.expect
new file mode 100644
index 0000000..9dc7175
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/null_shorting_index.dart.scanner.expect
@@ -0,0 +1,23 @@
+class Class1 {
+int operator [](int index) => index;
+void operator []=(int index, int value) {}
+}
+
+main() {
+Class1? c1;
+c1?.[0];
+c1?.[0] = 1;
+}
+
+
+class[KeywordToken] Class1[StringToken] {[BeginToken]
+int[StringToken] operator[KeywordToken] [][SimpleToken]([BeginToken]int[StringToken] index[StringToken])[SimpleToken] =>[SimpleToken] index[StringToken];[SimpleToken]
+void[KeywordToken] operator[KeywordToken] []=[SimpleToken]([BeginToken]int[StringToken] index[StringToken],[SimpleToken] int[StringToken] value[StringToken])[SimpleToken] {[BeginToken]}[SimpleToken]
+}[SimpleToken]
+
+main[StringToken]([BeginToken])[SimpleToken] {[BeginToken]
+Class1[StringToken]?[SimpleToken] c1[StringToken];[SimpleToken]
+c1[StringToken]?.[[BeginToken]0[StringToken]][SimpleToken];[SimpleToken]
+c1[StringToken]?.[[BeginToken]0[StringToken]][SimpleToken] =[SimpleToken] 1[StringToken];[SimpleToken]
+}[SimpleToken]
+[SimpleToken]
diff --git a/pkg/front_end/test/fasta/fast_strong_suite.dart b/pkg/front_end/test/fasta/fast_strong_suite.dart
index 26c0875..8269eb9 100644
--- a/pkg/front_end/test/fasta/fast_strong_suite.dart
+++ b/pkg/front_end/test/fasta/fast_strong_suite.dart
@@ -14,6 +14,7 @@
     Chain suite, Map<String, String> environment) {
   environment[ENABLE_FULL_COMPILE] = "";
   environment["skipVm"] = "true";
+  environment["verify"] = "false";
   return FastaContext.create(suite, environment);
 }
 
diff --git a/pkg/front_end/test/fasta/generator_to_string_test.dart b/pkg/front_end/test/fasta/generator_to_string_test.dart
index 20fe91b..22b941b 100644
--- a/pkg/front_end/test/fasta/generator_to_string_test.dart
+++ b/pkg/front_end/test/fasta/generator_to_string_test.dart
@@ -118,11 +118,8 @@
         " assignmentOperator: +=)",
         new DelayedAssignment(
             helper, token, generator, expression, assignmentOperator));
-    check(
-        "DelayedPostfixIncrement(offset: 4, binaryOperator: +,"
-        " interfaceTarget: $uri::#class1::myInterfaceTarget)",
-        new DelayedPostfixIncrement(
-            helper, token, generator, binaryOperator, interfaceTarget));
+    check("DelayedPostfixIncrement(offset: 4, binaryOperator: +)",
+        new DelayedPostfixIncrement(helper, token, generator, binaryOperator));
     check(
         "VariableUseGenerator(offset: 4, variable: dynamic #t1;\n,"
         " promotedType: void)",
@@ -143,8 +140,10 @@
         " getter: $uri::myGetter, setter: $uri::mySetter)",
         new SuperPropertyAccessGenerator(helper, token, name, getter, setter));
     check(
-        "IndexedAccessGenerator(offset: 4, receiver: expression, index: index)",
-        new IndexedAccessGenerator(helper, token, expression, index));
+        "IndexedAccessGenerator(offset: 4, receiver: expression, index: index,"
+        " isNullAware: false)",
+        new IndexedAccessGenerator(helper, token, expression, index,
+            isNullAware: false));
     check("ThisIndexedAccessGenerator(offset: 4, index: index)",
         new ThisIndexedAccessGenerator(helper, token, index));
     check(
diff --git a/pkg/front_end/test/fasta/parser/parser.status b/pkg/front_end/test/fasta/parser/parser.status
index c43b22f..94d326c3 100644
--- a/pkg/front_end/test/fasta/parser/parser.status
+++ b/pkg/front_end/test/fasta/parser/parser.status
@@ -1966,7 +1966,6 @@
 tests/lib_strong/mirrors/other_declarations_location_test: Fail
 tests/lib_strong/mirrors/syntax_error_test: Fail
 tests/lib_strong/mirrors/typevariable_mirror_metadata_test: Fail
-tests/standalone/io/process_exit_negative_test: Fail
 tests/standalone/io/snapshot_fail_script: Fail
 tests/standalone/io/test_extension: Fail
 tests/standalone/io/test_relative_extension: Fail
diff --git a/pkg/front_end/test/fasta/testing/suite.dart b/pkg/front_end/test/fasta/testing/suite.dart
index 2265921..2972102 100644
--- a/pkg/front_end/test/fasta/testing/suite.dart
+++ b/pkg/front_end/test/fasta/testing/suite.dart
@@ -141,8 +141,17 @@
 
 class TestOptions {
   final Map<ExperimentalFlag, bool> experimentalFlags;
+  final bool forceLateLowering;
 
-  TestOptions(this.experimentalFlags);
+  TestOptions(this.experimentalFlags, {this.forceLateLowering})
+      : assert(forceLateLowering != null);
+
+  Map<ExperimentalFlag, bool> computeExperimentalFlags(
+      Map<ExperimentalFlag, bool> forcedExperimentalFlags) {
+    Map<ExperimentalFlag, bool> flags = new Map.from(experimentalFlags);
+    flags.addAll(forcedExperimentalFlags);
+    return flags;
+  }
 }
 
 class FastaContext extends ChainContext with MatchContext {
@@ -152,6 +161,7 @@
   final bool onlyCrashes;
   final Map<ExperimentalFlag, bool> experimentalFlags;
   final bool skipVm;
+  final bool verify;
   final Map<Component, KernelTarget> componentToTarget =
       <Component, KernelTarget>{};
   final Map<Component, StringBuffer> componentToDiagnostics =
@@ -181,7 +191,8 @@
       this.skipVm,
       bool kernelTextSerialization,
       this.uriTranslator,
-      bool fullCompile)
+      bool fullCompile,
+      this.verify)
       : steps = <Step>[
           new Outline(fullCompile, updateComments: updateComments),
           const Print(),
@@ -226,35 +237,37 @@
   ///
   /// [forcedExperimentalFlags] is used to override the default flags for
   /// [description].
-  Map<ExperimentalFlag, bool> computeExperimentalFlags(
-      TestDescription description,
-      Map<ExperimentalFlag, bool> forcedExperimentalFlags) {
+  TestOptions computeTestOptions(TestDescription description) {
     Directory directory = new File.fromUri(description.uri).parent;
     // TODO(johnniwinther): Support nested test folders?
     TestOptions testOptions = _testOptions[directory.uri];
     if (testOptions == null) {
+      bool forceLateLowering = false;
       List<String> experimentalFlagsArguments = [];
       File optionsFile =
           new File.fromUri(directory.uri.resolve('test.options'));
       if (optionsFile.existsSync()) {
         for (String line in optionsFile.readAsStringSync().split('\n')) {
-          // TODO(johnniwinther): Support more options if need.
+          line = line.trim();
           if (line.startsWith(experimentalFlagOptions)) {
             experimentalFlagsArguments =
                 line.substring(experimentalFlagOptions.length).split('\n');
+          } else if (line.startsWith('--force-late-lowering')) {
+            forceLateLowering = true;
+          } else if (line.isNotEmpty) {
+            throw new UnsupportedError("Unsupported test option '$line'");
           }
         }
       }
-      testOptions = new TestOptions(parseExperimentalFlags(
-          parseExperimentalArguments(experimentalFlagsArguments),
-          onError: (String message) => throw new ArgumentError(message),
-          onWarning: (String message) => throw new ArgumentError(message)));
+      testOptions = new TestOptions(
+          parseExperimentalFlags(
+              parseExperimentalArguments(experimentalFlagsArguments),
+              onError: (String message) => throw new ArgumentError(message),
+              onWarning: (String message) => throw new ArgumentError(message)),
+          forceLateLowering: forceLateLowering);
       _testOptions[directory.uri] = testOptions;
     }
-    Map<ExperimentalFlag, bool> flags =
-        new Map.from(testOptions.experimentalFlags);
-    flags.addAll(forcedExperimentalFlags);
-    return flags;
+    return testOptions;
   }
 
   Expectation get verificationError => expectationSet["VerificationError"];
@@ -329,6 +342,7 @@
     bool updateExpectations = environment["updateExpectations"] == "true";
     bool updateComments = environment["updateComments"] == "true";
     bool skipVm = environment["skipVm"] == "true";
+    bool verify = environment["verify"] != "false";
     bool kernelTextSerialization =
         environment.containsKey(KERNEL_TEXT_SERIALIZATION);
     String platformBinaries = environment["platformBinaries"];
@@ -348,7 +362,8 @@
         skipVm,
         kernelTextSerialization,
         uriTranslator,
-        environment.containsKey(ENABLE_FULL_COMPILE));
+        environment.containsKey(ENABLE_FULL_COMPILE),
+        verify);
   }
 }
 
@@ -395,6 +410,7 @@
   Future<Result<Component>> run(
       TestDescription description, FastaContext context) async {
     StringBuffer errors = new StringBuffer();
+    TestOptions testOptions = context.computeTestOptions(description);
     ProcessedOptions options = new ProcessedOptions(
         options: new CompilerOptions()
           ..onDiagnostic = (DiagnosticMessage message) {
@@ -404,8 +420,8 @@
             errors.writeAll(message.plainTextFormatted, "\n");
           }
           ..environmentDefines = {}
-          ..experimentalFlags = context.computeExperimentalFlags(
-              description, context.experimentalFlags),
+          ..experimentalFlags =
+              testOptions.computeExperimentalFlags(context.experimentalFlags),
         inputs: <Uri>[description.uri]);
     return await CompilerContext.runWithOptions(options, (_) async {
       // Disable colors to ensure that expectation files are the same across
@@ -414,7 +430,11 @@
       Component platform = await context.loadPlatform();
       Ticker ticker = new Ticker();
       DillTarget dillTarget = new DillTarget(
-          ticker, context.uriTranslator, new TestVmTarget(new TargetFlags()));
+        ticker,
+        context.uriTranslator,
+        new TestVmTarget(new TargetFlags(
+            forceLateLoweringForTesting: testOptions.forceLateLowering)),
+      );
       dillTarget.loader.appendLibraries(platform);
       // We create a new URI translator to avoid reading platform libraries from
       // file system.
@@ -436,7 +456,7 @@
       context.componentToDiagnostics.clear();
       context.componentToDiagnostics[p] = errors;
       if (fullCompile) {
-        p = await sourceTarget.buildComponent();
+        p = await sourceTarget.buildComponent(verify: context.verify);
         instrumentation?.finish();
         if (instrumentation != null && instrumentation.hasProblems) {
           if (updateComments) {
@@ -559,8 +579,7 @@
     ClassHierarchyBuilder hierarchy = target.loader.builderHierarchy;
     StringBuffer sb = new StringBuffer();
     for (ClassHierarchyNode node in hierarchy.nodes.values) {
-      node.toString(sb);
-      sb.writeln();
+      sb.writeln(node);
     }
     return context.match<Component>(".hierarchy.expect", "$sb", uri, component);
   }
diff --git a/pkg/front_end/test/fasta/type_inference/type_constraint_gatherer_test.dart b/pkg/front_end/test/fasta/type_inference/type_constraint_gatherer_test.dart
index 53b52a9c..4e948de 100644
--- a/pkg/front_end/test/fasta/type_inference/type_constraint_gatherer_test.dart
+++ b/pkg/front_end/test/fasta/type_inference/type_constraint_gatherer_test.dart
@@ -232,7 +232,7 @@
     var typeSchemaEnvironment =
         new TypeSchemaEnvironment(coreTypes, new ClassHierarchy(component));
     var typeConstraintGatherer = new TypeConstraintGatherer(
-        typeSchemaEnvironment, [T1.parameter, T2.parameter]);
+        typeSchemaEnvironment, [T1.parameter, T2.parameter], testLib);
     var constraints = typeConstraintGatherer.trySubtypeMatch(a, b)
         ? typeConstraintGatherer.computeConstraints()
         : null;
diff --git a/pkg/front_end/test/fasta/type_inference/type_inference_engine_test.dart b/pkg/front_end/test/fasta/type_inference/type_inference_engine_test.dart
index 95452ab..a804319 100644
--- a/pkg/front_end/test/fasta/type_inference/type_inference_engine_test.dart
+++ b/pkg/front_end/test/fasta/type_inference/type_inference_engine_test.dart
@@ -224,7 +224,8 @@
         isFalse);
   }
 
-  TypeParameterType tpt(TypeParameter param, {int variance = null}) =>
-      new TypeParameterType(param, Nullability.legacy)
-        ..parameter.variance = variance;
+  TypeParameterType tpt(TypeParameter param, {int variance = null}) {
+    return new TypeParameterType(param, Nullability.legacy)
+      ..parameter.variance = variance;
+  }
 }
diff --git a/pkg/front_end/test/fasta/type_inference/type_schema_environment_test.dart b/pkg/front_end/test/fasta/type_inference/type_schema_environment_test.dart
index 3d9d3b1..fb49702 100644
--- a/pkg/front_end/test/fasta/type_inference/type_schema_environment_test.dart
+++ b/pkg/front_end/test/fasta/type_inference/type_schema_environment_test.dart
@@ -276,30 +276,32 @@
 
   void test_inferGenericFunctionOrType() {
     var env = _makeEnv();
+    InterfaceType listClassThisType =
+        coreTypes.thisInterfaceType(listClass, testLib.nonNullable);
     {
       // Test an instantiation of [1, 2.0] with no context.  This should infer
       // as List<?> during downwards inference.
       var inferredTypes = <DartType>[unknownType];
-      TypeParameterType T = listClass.thisType.typeArguments[0];
-      env.inferGenericFunctionOrType(
-          listClass.thisType, [T.parameter], null, null, null, inferredTypes);
+      TypeParameterType T = listClassThisType.typeArguments[0];
+      env.inferGenericFunctionOrType(listClassThisType, [T.parameter], null,
+          null, null, inferredTypes, testLib);
       expect(inferredTypes[0], unknownType);
       // And upwards inference should refine it to List<num>.
-      env.inferGenericFunctionOrType(listClass.thisType, [T.parameter], [T, T],
-          [intType, doubleType], null, inferredTypes);
+      env.inferGenericFunctionOrType(listClassThisType, [T.parameter], [T, T],
+          [intType, doubleType], null, inferredTypes, testLib);
       expect(inferredTypes[0], numType);
     }
     {
       // Test an instantiation of [1, 2.0] with a context of List<Object>.  This
       // should infer as List<Object> during downwards inference.
       var inferredTypes = <DartType>[unknownType];
-      TypeParameterType T = listClass.thisType.typeArguments[0];
-      env.inferGenericFunctionOrType(listClass.thisType, [T.parameter], null,
-          null, _list(objectType), inferredTypes);
+      TypeParameterType T = listClassThisType.typeArguments[0];
+      env.inferGenericFunctionOrType(listClassThisType, [T.parameter], null,
+          null, _list(objectType), inferredTypes, testLib);
       expect(inferredTypes[0], objectType);
       // And upwards inference should preserve the type.
-      env.inferGenericFunctionOrType(listClass.thisType, [T.parameter], [T, T],
-          [intType, doubleType], _list(objectType), inferredTypes);
+      env.inferGenericFunctionOrType(listClassThisType, [T.parameter], [T, T],
+          [intType, doubleType], _list(objectType), inferredTypes, testLib);
       expect(inferredTypes[0], objectType);
     }
   }
@@ -307,7 +309,8 @@
   void test_inferTypeFromConstraints_applyBound() {
     // class A<T extends num> {}
     var T = new TypeParameter('T', numType);
-    _addClass(_class('A', typeParameters: [T])).thisType;
+    coreTypes.thisInterfaceType(
+        _addClass(_class('A', typeParameters: [T])), testLib.nonNullable);
     var env = _makeEnv();
     {
       // With no constraints:
diff --git a/pkg/front_end/test/fasta/types/hashcode_test.dart b/pkg/front_end/test/fasta/types/hashcode_test.dart
new file mode 100644
index 0000000..404d446
--- /dev/null
+++ b/pkg/front_end/test/fasta/types/hashcode_test.dart
@@ -0,0 +1,60 @@
+import 'package:expect/expect.dart';
+import 'package:kernel/kernel.dart';
+
+FunctionType createVoidToR() {
+  TypeParameter R = TypeParameter("R", const DynamicType());
+  return new FunctionType(
+      [], new TypeParameterType(R, Nullability.legacy), Nullability.legacy,
+      typeParameters: [R]);
+}
+
+FunctionType createTTo_VoidToR() {
+  TypeParameter T = new TypeParameter("T", const DynamicType());
+  return new FunctionType([new TypeParameterType(T, Nullability.legacy)],
+      createVoidToR(), Nullability.legacy,
+      typeParameters: [T]);
+}
+
+test1() {
+  DartType voidToR1 = createVoidToR();
+  DartType voidToR2 = createVoidToR();
+  DartType voidToR3 = createTTo_VoidToR().returnType;
+  Expect.equals(voidToR1.hashCode, voidToR2.hashCode,
+      "Hash code mismatch for voidToR1 vs voidToR2."); // true
+  Expect.equals(voidToR3, voidToR2); // true
+  Expect.equals(voidToR2.hashCode, voidToR3.hashCode,
+      "Hash code mismatch for voidToR2 vs voidToR3."); // true, good!
+
+  // Get hash code first to force computing and caching the hashCode recursively
+  DartType voidToR4 = (createTTo_VoidToR()..hashCode).returnType;
+  Expect.equals(voidToR4, voidToR2); // true
+  Expect.equals(voidToR2.hashCode, voidToR4.hashCode,
+      "Hash code mismatch for voidToR2 vs voidToR4."); // false, oh no!
+}
+
+FunctionType createVoidTo_VoidToR() {
+  TypeParameter R = new TypeParameter("R", const DynamicType());
+  return new FunctionType(
+      [],
+      new FunctionType(
+          [], new TypeParameterType(R, Nullability.legacy), Nullability.legacy),
+      Nullability.legacy,
+      typeParameters: [R]);
+}
+
+test2() {
+  FunctionType outer1 = createVoidTo_VoidToR();
+  FunctionType outer2 = createVoidTo_VoidToR();
+  DartType voidToR1 = outer1.returnType;
+  DartType voidToR2 = outer2.returnType;
+  outer2.hashCode; // Trigger hashCode caching
+  Expect.equals(outer1, outer2); // true
+  Expect.equals(voidToR1.hashCode, voidToR2.hashCode,
+      "Hash code mismatch for voidToR1 vs voidToR2."); // false, OK
+  Expect.equals(outer1.hashCode, outer2.hashCode,
+      "Hash code mismatch for outer1 vs outer2."); // false, on no!
+}
+
+main() {
+  test2();
+}
diff --git a/pkg/front_end/test/fasta/types/kernel_type_parser.dart b/pkg/front_end/test/fasta/types/kernel_type_parser.dart
index d9e5d85..520d0a3 100644
--- a/pkg/front_end/test/fasta/types/kernel_type_parser.dart
+++ b/pkg/front_end/test/fasta/types/kernel_type_parser.dart
@@ -260,7 +260,13 @@
             namedParameters: f.namedParameters,
             typeParameters: f.typeParameters,
             requiredParameterCount: f.requiredParameterCount,
-            typedefType: def.thisType);
+            typedefType: new TypedefType(
+                def,
+                Nullability.nonNullable,
+                def.typeParameters
+                    .map((p) => new TypeParameterType(
+                        p, TypeParameterType.computeNullabilityFromBound(p)))
+                    .toList()));
       }
     }
     return def..type = type;
@@ -315,7 +321,8 @@
     TypeParameterType type =
         node.a.accept<Node, KernelEnvironment>(this, environment);
     DartType bound = node.b.accept<Node, KernelEnvironment>(this, environment);
-    return new TypeParameterType(type.parameter, type.nullability, bound);
+    return new TypeParameterType.intersection(
+        type.parameter, type.nullability, bound);
   }
 
   Supertype toSupertype(InterfaceType type) {
diff --git a/pkg/front_end/test/flow_analysis/assigned_variables/assigned_variables_test.dart b/pkg/front_end/test/id_tests/assigned_variables_test.dart
similarity index 98%
rename from pkg/front_end/test/flow_analysis/assigned_variables/assigned_variables_test.dart
rename to pkg/front_end/test/id_tests/assigned_variables_test.dart
index 2bdb277..412b439 100644
--- a/pkg/front_end/test/flow_analysis/assigned_variables/assigned_variables_test.dart
+++ b/pkg/front_end/test/id_tests/assigned_variables_test.dart
@@ -19,7 +19,7 @@
 
 main(List<String> args) async {
   Directory dataDir = new Directory.fromUri(Platform.script.resolve(
-      '../../../../_fe_analyzer_shared/test/flow_analysis/assigned_variables/'
+      '../../../_fe_analyzer_shared/test/flow_analysis/assigned_variables/'
       'data'));
   await runTests(dataDir,
       args: args,
diff --git a/pkg/front_end/test/constants/constant_test.dart b/pkg/front_end/test/id_tests/constant_test.dart
similarity index 100%
rename from pkg/front_end/test/constants/constant_test.dart
rename to pkg/front_end/test/id_tests/constant_test.dart
diff --git a/pkg/front_end/test/flow_analysis/definite_assignment/definite_assignment_test.dart b/pkg/front_end/test/id_tests/definite_assignment_test.dart
similarity index 96%
rename from pkg/front_end/test/flow_analysis/definite_assignment/definite_assignment_test.dart
rename to pkg/front_end/test/id_tests/definite_assignment_test.dart
index 7fa9e26..69be70e 100644
--- a/pkg/front_end/test/flow_analysis/definite_assignment/definite_assignment_test.dart
+++ b/pkg/front_end/test/id_tests/definite_assignment_test.dart
@@ -15,7 +15,7 @@
 
 main(List<String> args) async {
   Directory dataDir = new Directory.fromUri(Platform.script.resolve(
-      '../../../../_fe_analyzer_shared/test/flow_analysis/definite_assignment/'
+      '../../../_fe_analyzer_shared/test/flow_analysis/definite_assignment/'
       'data'));
   await runTests(dataDir,
       args: args,
diff --git a/pkg/front_end/test/flow_analysis/nullability/nullability_test.dart b/pkg/front_end/test/id_tests/nullability_test.dart
similarity index 96%
rename from pkg/front_end/test/flow_analysis/nullability/nullability_test.dart
rename to pkg/front_end/test/id_tests/nullability_test.dart
index c5473b0..2ff1bca 100644
--- a/pkg/front_end/test/flow_analysis/nullability/nullability_test.dart
+++ b/pkg/front_end/test/id_tests/nullability_test.dart
@@ -12,7 +12,7 @@
 
 main(List<String> args) async {
   Directory dataDir = new Directory.fromUri(Platform.script.resolve(
-      '../../../../_fe_analyzer_shared/test/flow_analysis/nullability/data'));
+      '../../../_fe_analyzer_shared/test/flow_analysis/nullability/data'));
   await runTests(dataDir,
       args: args,
       supportedMarkers: sharedMarkers,
diff --git a/pkg/front_end/test/flow_analysis/reachability/reachability_test.dart b/pkg/front_end/test/id_tests/reachability_test.dart
similarity index 98%
rename from pkg/front_end/test/flow_analysis/reachability/reachability_test.dart
rename to pkg/front_end/test/id_tests/reachability_test.dart
index 634b4df..2697b7e 100644
--- a/pkg/front_end/test/flow_analysis/reachability/reachability_test.dart
+++ b/pkg/front_end/test/id_tests/reachability_test.dart
@@ -15,7 +15,7 @@
 
 main(List<String> args) async {
   Directory dataDir = new Directory.fromUri(Platform.script.resolve(
-      '../../../../_fe_analyzer_shared/test/flow_analysis/reachability/data'));
+      '../../../_fe_analyzer_shared/test/flow_analysis/reachability/data'));
   await runTests(dataDir,
       args: args,
       supportedMarkers: sharedMarkers,
diff --git a/pkg/front_end/test/flow_analysis/type_promotion/type_promotion_test.dart b/pkg/front_end/test/id_tests/type_promotion_test.dart
similarity index 94%
rename from pkg/front_end/test/flow_analysis/type_promotion/type_promotion_test.dart
rename to pkg/front_end/test/id_tests/type_promotion_test.dart
index cfaf1e5..03f1e5b 100644
--- a/pkg/front_end/test/flow_analysis/type_promotion/type_promotion_test.dart
+++ b/pkg/front_end/test/id_tests/type_promotion_test.dart
@@ -12,9 +12,9 @@
 import 'package:kernel/ast.dart' hide Variance;
 
 main(List<String> args) async {
-  Directory dataDir = new Directory.fromUri(Platform.script.resolve(
-      '../../../../_fe_analyzer_shared/test/flow_analysis/type_promotion/'
-      'data'));
+  Directory dataDir = new Directory.fromUri(Platform.script
+      .resolve('../../../_fe_analyzer_shared/test/flow_analysis/type_promotion/'
+          'data'));
   await runTests(dataDir,
       args: args,
       supportedMarkers: sharedMarkers,
diff --git a/pkg/front_end/test/incremental_dart2js_tester.dart b/pkg/front_end/test/incremental_dart2js_tester.dart
new file mode 100644
index 0000000..7bdcdef
--- /dev/null
+++ b/pkg/front_end/test/incremental_dart2js_tester.dart
@@ -0,0 +1,171 @@
+// Copyright (c) 2019, 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' show Platform;
+
+import 'package:front_end/src/api_prototype/compiler_options.dart';
+import 'package:front_end/src/api_unstable/bazel_worker.dart';
+
+import 'package:kernel/kernel.dart'
+    show Component, Library, LibraryPart, Reference;
+
+import 'incremental_load_from_dill_suite.dart' as helper;
+
+import "incremental_utils.dart" as util;
+
+main(List<String> args) async {
+  bool fast = false;
+  bool useExperimentalInvalidation = false;
+  for (String arg in args) {
+    if (arg == "--fast") {
+      fast = true;
+    } else if (arg == "--experimental") {
+      useExperimentalInvalidation = true;
+    } else {
+      throw "Unsupported argument: $arg";
+    }
+  }
+
+  Stopwatch stopwatch = new Stopwatch()..start();
+  Uri input = Platform.script.resolve("../../compiler/bin/dart2js.dart");
+  CompilerOptions options = helper.getOptions(targetName: "None");
+  helper.TestIncrementalCompiler compiler =
+      new helper.TestIncrementalCompiler(options, input);
+  compiler.useExperimentalInvalidation = useExperimentalInvalidation;
+  Component c = await compiler.computeDelta();
+  print("Compiled dart2js to Component with ${c.libraries.length} libraries "
+      "in ${stopwatch.elapsedMilliseconds} ms.");
+  stopwatch.reset();
+  List<int> firstCompileData;
+  Map<Uri, List<int>> libToData;
+  if (fast) {
+    libToData = {};
+    c.libraries.sort((l1, l2) {
+      return "${l1.fileUri}".compareTo("${l2.fileUri}");
+    });
+
+    c.problemsAsJson?.sort();
+
+    c.computeCanonicalNames();
+
+    for (Library library in c.libraries) {
+      library.additionalExports.sort((Reference r1, Reference r2) {
+        return "${r1.canonicalName}".compareTo("${r2.canonicalName}");
+      });
+      library.problemsAsJson?.sort();
+
+      List<int> libSerialized =
+          serializeComponent(c, filter: (l) => l == library);
+      libToData[library.importUri] = libSerialized;
+    }
+  } else {
+    firstCompileData = util.postProcess(c);
+  }
+  print("Serialized in ${stopwatch.elapsedMilliseconds} ms");
+  stopwatch.reset();
+
+  List<Uri> uris = c.uriToSource.values
+      .map((s) => s != null ? s.importUri : null)
+      .where((u) => u != null && u.scheme != "dart")
+      .toSet()
+      .toList();
+
+  c = null;
+
+  List<Uri> diffs = new List<Uri>();
+
+  Stopwatch localStopwatch = new Stopwatch()..start();
+  for (int i = 0; i < uris.length; i++) {
+    Uri uri = uris[i];
+    print("Invalidating $uri ($i)");
+    compiler.invalidate(uri);
+    localStopwatch.reset();
+    Component c2 = await compiler.computeDelta(fullComponent: true);
+    print("Recompiled in ${localStopwatch.elapsedMilliseconds} ms");
+    print("invalidatedImportUrisForTesting: "
+        "${compiler.invalidatedImportUrisForTesting}");
+    print("rebuildBodiesCount: ${compiler.rebuildBodiesCount}");
+    localStopwatch.reset();
+
+    if (fast) {
+      c2.libraries.sort((l1, l2) {
+        return "${l1.fileUri}".compareTo("${l2.fileUri}");
+      });
+
+      c2.problemsAsJson?.sort();
+
+      c2.computeCanonicalNames();
+
+      int foundCount = 0;
+      for (Library library in c2.libraries) {
+        Set<Uri> uris = new Set<Uri>();
+        uris.add(library.importUri);
+        for (LibraryPart part in library.parts) {
+          Uri uri = library.importUri.resolve(part.partUri);
+          uris.add(uri);
+        }
+        if (!uris.contains(uri)) continue;
+        foundCount++;
+        library.additionalExports.sort((Reference r1, Reference r2) {
+          return "${r1.canonicalName}".compareTo("${r2.canonicalName}");
+        });
+        library.problemsAsJson?.sort();
+
+        List<int> libSerialized =
+            serializeComponent(c2, filter: (l) => l == library);
+        if (!isEqual(libToData[library.importUri], libSerialized)) {
+          print("=====");
+          print("=====");
+          print("=====");
+          print("Notice diff on $uri ($i)!");
+          libToData[library.importUri] = libSerialized;
+          diffs.add(uri);
+          print("=====");
+          print("=====");
+          print("=====");
+        }
+      }
+      if (foundCount != 1) {
+        throw "Expected to find $uri, but it $foundCount times.";
+      }
+      print("Serialized library in ${localStopwatch.elapsedMilliseconds} ms");
+    } else {
+      List<int> thisCompileData = util.postProcess(c2);
+      print("Serialized in ${localStopwatch.elapsedMilliseconds} ms");
+      if (!isEqual(firstCompileData, thisCompileData)) {
+        print("=====");
+        print("=====");
+        print("=====");
+        print("Notice diff on $uri ($i)!");
+        firstCompileData = thisCompileData;
+        diffs.add(uri);
+        print("=====");
+        print("=====");
+        print("=====");
+      }
+    }
+    print("-----");
+  }
+
+  print("A total of ${diffs.length} diffs:");
+  for (Uri uri in diffs) {
+    print(" - $uri");
+  }
+
+  print("Done after ${uris.length} recompiles in "
+      "${stopwatch.elapsedMilliseconds} ms");
+}
+
+bool isEqual(List<int> a, List<int> b) {
+  int length = a.length;
+  if (b.length != length) {
+    return false;
+  }
+  for (int i = 0; i < length; ++i) {
+    if (a[i] != b[i]) {
+      return false;
+    }
+  }
+  return true;
+}
diff --git a/pkg/front_end/test/incremental_load_from_dill_suite.dart b/pkg/front_end/test/incremental_load_from_dill_suite.dart
index 48a4d48..c6f326d 100644
--- a/pkg/front_end/test/incremental_load_from_dill_suite.dart
+++ b/pkg/front_end/test/incremental_load_from_dill_suite.dart
@@ -9,6 +9,8 @@
 import 'package:_fe_analyzer_shared/src/messages/diagnostic_message.dart'
     show DiagnosticMessage, getMessageCodeObject;
 
+import 'package:_fe_analyzer_shared/src/util/colors.dart' as colors;
+
 import 'package:_fe_analyzer_shared/src/messages/severity.dart' show Severity;
 
 import 'package:expect/expect.dart' show Expect;
@@ -77,6 +79,9 @@
 
 Future<Context> createContext(
     Chain suite, Map<String, String> environment) async {
+  // Disable colors to ensure that expectation files are the same across
+  // platforms and independent of stdin/stderr.
+  colors.enableColors = false;
   return new Context(environment["updateExpectations"] == "true");
 }
 
@@ -483,6 +488,11 @@
       }
     }
 
+    compiler.useExperimentalInvalidation = false;
+    if (world["useExperimentalInvalidation"] == true) {
+      compiler.useExperimentalInvalidation = true;
+    }
+
     List<Uri> invalidated = new List<Uri>();
     if (world["invalidate"] != null) {
       for (String filename in world["invalidate"]) {
@@ -592,7 +602,9 @@
     if (context.updateExpectations) {
       file.writeAsStringSync(actualSerialized);
     } else if (expected != actualSerialized) {
-      throw "Unexpected serialized representation. "
+      String extra = "";
+      if (expected == null) extra = "Expect file did not exist.\n";
+      throw "${extra}Unexpected serialized representation. "
           "Fix or update $uri to contain the below:\n\n"
           "$actualSerialized";
     }
@@ -629,6 +641,12 @@
       }
     }
 
+    if (world["expectsRebuildBodiesOnly"] != null) {
+      bool didRebuildBodiesOnly = compiler.rebuildBodiesCount > 0;
+      Expect.equals(world["expectsRebuildBodiesOnly"], didRebuildBodiesOnly,
+          "Whether we expected to rebuild bodies only.");
+    }
+
     if (!noFullComponent) {
       List<Library> entryLib = component.libraries
           .where((Library lib) =>
@@ -1231,6 +1249,7 @@
 
 class TestIncrementalCompiler extends IncrementalCompiler {
   Set<Uri> invalidatedImportUrisForTesting;
+  int rebuildBodiesCount;
   final Uri entryPoint;
 
   /// Filter out the automatically added entryPoint, unless it's explicitly
@@ -1292,6 +1311,11 @@
   }
 
   @override
+  void recordRebuildBodiesCountForTesting(int count) {
+    rebuildBodiesCount = count;
+  }
+
+  @override
   Future<Component> computeDelta(
       {List<Uri> entryPoints,
       bool fullComponent = false,
diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt
index 5f05c67..ac01f71 100644
--- a/pkg/front_end/test/spell_checking_list_code.txt
+++ b/pkg/front_end/test/spell_checking_list_code.txt
@@ -141,6 +141,7 @@
 clazz
 cls
 cn
+cnt
 co
 codebase
 codec
@@ -320,6 +321,8 @@
 fffff
 ffffffff
 ffi
+field1
+field2
 file's
 filenames
 finv
@@ -423,6 +426,7 @@
 insertion
 inspector
 inspired
+inst
 instanceof
 instantiator
 intentionally
@@ -454,6 +458,7 @@
 juxtaposition
 juxtapositions
 k
+k’s
 kallentu
 kernel's
 kernel2kernel
@@ -461,7 +466,6 @@
 kmillikin
 kustermann
 kv
-k’s
 l
 lacks
 lang
@@ -639,13 +643,13 @@
 quick
 quoted
 r
-r'$creation
 r'\f
 r'\r
 r'\s
 r'\t
 r'\u
 r'\v
+r'$creation
 ra
 radix
 raises
@@ -663,6 +667,7 @@
 reassigned
 rebind
 rebuild
+rebuilds
 recalculating
 recalculation
 recall
@@ -705,6 +710,7 @@
 respond
 restriction
 resumed
+ret
 rewrites
 rewrote
 rf
@@ -1021,6 +1027,8 @@
 xm
 xn
 xor
+xs
+xss
 xterm
 xx
 xxxx
@@ -1032,6 +1040,8 @@
 yet
 yielding
 yields
+ys
+yss
 z
 zi
 zip
diff --git a/pkg/front_end/test/spell_checking_list_common.txt b/pkg/front_end/test/spell_checking_list_common.txt
index 301934c..474a457 100644
--- a/pkg/front_end/test/spell_checking_list_common.txt
+++ b/pkg/front_end/test/spell_checking_list_common.txt
@@ -53,6 +53,7 @@
 acyclic
 ad
 adapt
+adapted
 add
 added
 adding
@@ -73,6 +74,7 @@
 advancing
 advice
 affect
+affected
 affects
 after
 again
@@ -84,6 +86,8 @@
 algorithm
 algorithms
 alias
+aliased
+aliases
 alignment
 all
 allocated
@@ -105,6 +109,7 @@
 alternatively
 alternatives
 although
+altogether
 always
 ambiguous
 among
@@ -217,6 +222,7 @@
 average
 avoid
 avoided
+avoiding
 avoids
 await
 awaiter
@@ -528,6 +534,7 @@
 concurrent
 condition
 conditional
+conditionals
 conditionally
 conditions
 configurable
@@ -611,6 +618,7 @@
 converting
 converts
 cookie
+coordinate
 cope
 copied
 copier
@@ -728,6 +736,7 @@
 delimiter
 delimiters
 delta
+demote
 demoted
 demoting
 demotion
@@ -762,6 +771,7 @@
 deserialize
 deserialized
 designed
+desired
 desugar
 desugared
 desugaring
@@ -916,6 +926,7 @@
 encoder
 encodes
 encoding
+encodings
 encounter
 encountered
 encountering
@@ -1073,6 +1084,7 @@
 failures
 fake
 fall
+fallback
 falls
 false
 far
@@ -1085,6 +1097,7 @@
 features
 feed
 feel
+fetch
 few
 fewer
 field
@@ -1665,6 +1678,7 @@
 lowercase
 lowered
 lowering
+lowerings
 machine
 made
 magenta
@@ -1849,6 +1863,7 @@
 nodes
 non
 none
+nonfunction
 nor
 normal
 normalize
@@ -2297,6 +2312,7 @@
 regress
 regression
 regular
+reinsert
 reissue
 rejected
 rejects
@@ -2410,6 +2426,8 @@
 reusing
 reverse
 reversed
+revert
+reverts
 review
 revise
 revision
@@ -2444,6 +2462,8 @@
 said
 sake
 same
+sample
+samples
 sanity
 satisfied
 satisfies
@@ -2515,6 +2535,7 @@
 setter
 setters
 setting
+settings
 settled
 setup
 several
@@ -2636,6 +2657,7 @@
 squiggly
 stable
 stack
+stacked
 stage
 stamps
 standalone
@@ -2649,6 +2671,7 @@
 starts
 startup
 state
+stateful
 statement
 statement's
 statements
@@ -2716,6 +2739,7 @@
 success
 successful
 successfully
+successively
 succinct
 such
 suffice
diff --git a/pkg/front_end/test/spell_checking_list_tests.txt b/pkg/front_end/test/spell_checking_list_tests.txt
index ff871b9..ebb6a1d 100644
--- a/pkg/front_end/test/spell_checking_list_tests.txt
+++ b/pkg/front_end/test/spell_checking_list_tests.txt
@@ -285,6 +285,7 @@
 reachability
 reality
 recompile
+recompiles
 redir
 redirections
 reducer
diff --git a/pkg/front_end/test/static_types/data/class_call.dart b/pkg/front_end/test/static_types/data/class_call.dart
new file mode 100644
index 0000000..9aa0258
--- /dev/null
+++ b/pkg/front_end/test/static_types/data/class_call.dart
@@ -0,0 +1,48 @@
+// Copyright (c) 2019, 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.
+
+/*cfe|dart2js.library: nnbd=false*/
+/*cfe:nnbd.library: nnbd=true*/
+
+abstract class ClassWithCall {
+  ClassWithCall call();
+  int method();
+}
+
+class Class {
+  ClassWithCall classWithCall;
+
+  int method() =>
+      /*cfe|dart2js.invoke: ClassWithCall*/
+      /*cfe:nnbd.invoke: ClassWithCall!*/
+      classWithCall()
+          . /*cfe|dart2js.invoke: int*/
+          /*cfe:nnbd.invoke: int!*/
+          method();
+}
+
+abstract class GenericClassWithCall<T> {
+  T call();
+  T method();
+}
+
+class GenericClass<S, T extends GenericClassWithCall<S>> {
+  GenericClassWithCall<T> classWithCall;
+
+  S method() =>
+      /*cfe|dart2js.invoke: T*/ /*cfe:nnbd.invoke: T!*/ classWithCall()
+          . /*cfe|dart2js.invoke: S*/ /*cfe:nnbd.invoke: S%*/ method();
+}
+
+main() {
+  new /*cfe|dart2js.GenericClass<String,GenericClassWithCall<String>>*/
+      /*cfe:nnbd.GenericClass<String!,GenericClassWithCall<String!>!>!*/
+      GenericClass<String, GenericClassWithCall<String>>
+          /*cfe|dart2js.<String,GenericClassWithCall<String>>*/
+          /*cfe:nnbd.<String!,GenericClassWithCall<String!>!>*/ ()
+      . /*cfe|dart2js.invoke: GenericClassWithCall<String>*/
+      /*cfe:nnbd.invoke: GenericClassWithCall<String!>!*/
+      classWithCall()
+      . /*cfe|dart2js.invoke: String*/ /*cfe:nnbd.invoke: String!*/ method();
+}
diff --git a/pkg/front_end/test/static_types/data/constraint_gatherer_for_future_or.dart b/pkg/front_end/test/static_types/data/constraint_gatherer_for_future_or.dart
index 33e0785..2bce49c 100644
--- a/pkg/front_end/test/static_types/data/constraint_gatherer_for_future_or.dart
+++ b/pkg/front_end/test/static_types/data/constraint_gatherer_for_future_or.dart
@@ -51,7 +51,8 @@
 void func5() {
   void foo<S>(FutureOr<S> bar) {}
 
-  /*invoke: void*/ foo /*cfe|dart2js.<int>*/ /*cfe:nnbd.<int!>*/ (/*int*/ 42);
+  /*invoke: void*/ foo /*cfe|dart2js.<int>*/ /*cfe:nnbd.<int!>*/ (
+      /*cfe|dart2js.int*/ /*cfe:nnbd.int!*/ 42);
 }
 
 // -----------------------------------------------------------------------------
@@ -60,7 +61,8 @@
 void func6() {
   void foo<S>(S bar) {}
 
-  /*invoke: void*/ foo /*cfe|dart2js.<int>*/ /*cfe:nnbd.<int!>*/ (/*int*/ 42);
+  /*invoke: void*/ foo /*cfe|dart2js.<int>*/ /*cfe:nnbd.<int!>*/ (
+      /*cfe|dart2js.int*/ /*cfe:nnbd.int!*/ 42);
 }
 
 // -----------------------------------------------------------------------------
@@ -68,7 +70,8 @@
 void func7() {
   void foo<S>(FutureOr<FutureOr<S>> bar) {}
 
-  /*invoke: void*/ foo /*cfe|dart2js.<int>*/ /*cfe:nnbd.<int!>*/ (/*int*/ 42);
+  /*invoke: void*/ foo /*cfe|dart2js.<int>*/ /*cfe:nnbd.<int!>*/ (
+      /*cfe|dart2js.int*/ /*cfe:nnbd.int!*/ 42);
 }
 
 // -----------------------------------------------------------------------------
diff --git a/pkg/front_end/test/static_types/data/greatest_lower_bound_for_future_or.dart b/pkg/front_end/test/static_types/data/greatest_lower_bound_for_future_or.dart
index 6c3c239..e2783e6 100644
--- a/pkg/front_end/test/static_types/data/greatest_lower_bound_for_future_or.dart
+++ b/pkg/front_end/test/static_types/data/greatest_lower_bound_for_future_or.dart
@@ -26,7 +26,7 @@
 
   // Type of the expression is GLB(FutureOr<T>, Foo) = T.
   /*invoke: void*/ context(
-      /*invoke: T*/ expr
+      /*cfe|dart2js.invoke: T*/ /*cfe:nnbd.invoke: T!*/ expr
           /*cfe|dart2js.<T>*/
           /*cfe:nnbd.<T!>*/ ());
 }
@@ -41,9 +41,9 @@
   // Type of the expression is GLB(FutureOr<T>, Future<Foo>) = Future<T>.
   /*invoke: void*/ context(
       /*cfe|dart2js.invoke: Future<T>*/
-      /*cfe:nnbd.invoke: Future<T!>*/ expr
+      /*cfe:nnbd.invoke: Future<T!>!*/ expr
           /*cfe|dart2js.<Future<T>>*/
-          /*cfe:nnbd.<Future<T!>>*/ ());
+          /*cfe:nnbd.<Future<T!>!>*/ ());
 }
 
 // -----------------------------------------------------------------------------
@@ -55,7 +55,7 @@
 
   // Type of the expression is GLB(T, FutureOr<Foo>) = T.
   /*invoke: void*/ context(
-      /*invoke: T*/ expr
+      /*cfe|dart2js.invoke: T*/ /*cfe:nnbd.invoke: T!*/ expr
           /*cfe|dart2js.<T>*/
           /*cfe:nnbd.<T!>*/ ());
 }
@@ -70,7 +70,7 @@
   // Type of the expression is GLB(Future<T>, FutureOr<Foo>) = Future<T>.
   /*invoke: void*/ context(
       /*cfe|dart2js.invoke: Future<T>*/
-      /*cfe:nnbd.invoke: Future<T!>*/ expr
+      /*cfe:nnbd.invoke: Future<T!>!*/ expr
           /*cfe|dart2js.<Future<T>>*/
           /*cfe:nnbd.<Future<T!>!>*/ ());
 }
@@ -87,9 +87,9 @@
   // = FutureOr<Future<T>>.
   /*invoke: void*/ context(
       /*cfe|dart2js.invoke: FutureOr<Future<T>>*/
-      /*cfe:nnbd.invoke: FutureOr<Future<T!>>*/ expr
+      /*cfe:nnbd.invoke: FutureOr<Future<T!>!>!*/ expr
           /*cfe|dart2js.<FutureOr<Future<T>>>*/
-          /*cfe:nnbd.<FutureOr<Future<T!>>>*/ ());
+          /*cfe:nnbd.<FutureOr<Future<T!>!>!>*/ ());
 }
 
 // -----------------------------------------------------------------------------
diff --git a/pkg/front_end/test/static_types/data/list_literals.dart b/pkg/front_end/test/static_types/data/list_literals.dart
index c8fb05d..8cb149c 100644
--- a/pkg/front_end/test/static_types/data/list_literals.dart
+++ b/pkg/front_end/test/static_types/data/list_literals.dart
@@ -6,13 +6,25 @@
 /*cfe:nnbd.library: nnbd=true*/
 
 main() {
-  /*List<dynamic>*/ [];
+  /*cfe|dart2js.List<dynamic>*/
+  /*cfe:nnbd.List<dynamic>!*/
+  [];
 
   /*cfe|dart2js.List<int>*/
-  /*cfe:nnbd.List<int!>*/
-  [/*int*/ 0];
+  /*cfe:nnbd.List<int!>!*/
+  [/*cfe|dart2js.int*/ /*cfe:nnbd.int!*/ 0];
 
-  /*List<num>*/ [/*int*/ 0, /*double*/ 0.5];
+  /*cfe|dart2js.List<num>*/
+  /*cfe:nnbd.List<num>!*/
+  [
+    /*cfe|dart2js.int*/ /*cfe:nnbd.int!*/ 0,
+    /*cfe|dart2js.double*/ /*cfe:nnbd.double!*/ 0.5
+  ];
 
-  /*List<Object>*/ [/*int*/ 0, /*String*/ ''];
+  /*cfe|dart2js.List<Object>*/
+  /*cfe:nnbd.List<Object>!*/
+  [
+    /*cfe|dart2js.int*/ /*cfe:nnbd.int!*/ 0,
+    /*cfe|dart2js.String*/ /*cfe:nnbd.String!*/ ''
+  ];
 }
diff --git a/pkg/front_end/test/static_types/data/literals.dart b/pkg/front_end/test/static_types/data/literals.dart
index 52c32a1..9d985bb 100644
--- a/pkg/front_end/test/static_types/data/literals.dart
+++ b/pkg/front_end/test/static_types/data/literals.dart
@@ -7,10 +7,10 @@
 
 main() {
   /*Null*/ null;
-  /*bool*/ true;
-  /*bool*/ false;
-  /*String*/ 'foo';
-  /*int*/ 42;
-  /*double*/ 0.5;
-  /*Symbol*/ #main;
+  /*cfe|dart2js.bool*/ /*cfe:nnbd.bool!*/ true;
+  /*cfe|dart2js.bool*/ /*cfe:nnbd.bool!*/ false;
+  /*cfe|dart2js.String*/ /*cfe:nnbd.String!*/ 'foo';
+  /*cfe|dart2js.int*/ /*cfe:nnbd.int!*/ 42;
+  /*cfe|dart2js.double*/ /*cfe:nnbd.double!*/ 0.5;
+  /*cfe|dart2js.Symbol*/ /*cfe:nnbd.Symbol!*/ #main;
 }
diff --git a/pkg/front_end/test/static_types/data/map_literals.dart b/pkg/front_end/test/static_types/data/map_literals.dart
index ce2e5fb..c83e20c 100644
--- a/pkg/front_end/test/static_types/data/map_literals.dart
+++ b/pkg/front_end/test/static_types/data/map_literals.dart
@@ -7,65 +7,148 @@
 
 main() {
   // ignore: unused_local_variable
-  var a0 = /*Map<dynamic,dynamic>*/ {};
+  var a0 =
+      /*cfe|dart2js.Map<dynamic,dynamic>*/
+      /*cfe:nnbd.Map<dynamic,dynamic>!*/
+      {};
 
   // ignore: unused_local_variable
   var a1 =
       /*cfe|dart2js.Map<int,double>*/
-      /*cfe:nnbd.Map<int!,double!>*/
-      {/*int*/ 0: /*double*/ 0.5 };
+      /*cfe:nnbd.Map<int!,double!>!*/
+      {
+    /*cfe|dart2js.int*/
+    /*cfe:nnbd.int!*/
+    0:
+        /*cfe|dart2js.double*/
+        /*cfe:nnbd.double!*/
+        0.5
+  };
 
   // ignore: unused_local_variable
   var a2 =
       /*cfe|dart2js.Map<double,int>*/
-      /*cfe:nnbd.Map<double!,int!>*/
-      {/*double*/ 0.5: /*int*/ 0 };
+      /*cfe:nnbd.Map<double!,int!>!*/
+      {
+    /*cfe|dart2js.double*/
+    /*cfe:nnbd.double!*/
+    0.5:
+        /*cfe|dart2js.int*/
+        /*cfe:nnbd.int!*/
+        0
+  };
 
   // ignore: unused_local_variable
   var a3 =
       /*cfe|dart2js.Map<int,num>*/
-      /*cfe:nnbd.Map<int!,num>*/
+      /*cfe:nnbd.Map<int!,num>!*/
       {
-    /*int*/ 0: /*double*/ 0.5,
-    /*int*/ 1: /*int*/ 2
+    /*cfe|dart2js.int*/
+    /*cfe:nnbd.int!*/
+    0:
+        /*cfe|dart2js.double*/
+        /*cfe:nnbd.double!*/
+        0.5,
+    /*cfe|dart2js.int*/
+    /*cfe:nnbd.int!*/
+    1:
+        /*cfe|dart2js.int*/
+        /*cfe:nnbd.int!*/
+        2
   };
 
   // ignore: unused_local_variable
   var a4 =
       /*cfe|dart2js.Map<num,double>*/
-      /*cfe:nnbd.Map<num,double!>*/
+      /*cfe:nnbd.Map<num,double!>!*/
       {
-    /*int*/ 0: /*double*/ 0.5,
-    /*double*/ 0.5: /*double*/ 0.5
+    /*cfe|dart2js.int*/
+    /*cfe:nnbd.int!*/
+    0:
+        /*cfe|dart2js.double*/
+        /*cfe:nnbd.double!*/
+        0.5,
+    /*cfe|dart2js.double*/
+    /*cfe:nnbd.double!*/
+    0.5:
+        /*cfe|dart2js.double*/
+        /*cfe:nnbd.double!*/
+        0.5
   };
 
   // ignore: unused_local_variable
-  var a5 = /*Map<num,num>*/ {
-    /*int*/ 0: /*double*/ 0.5,
-    /*double*/ 0.5: /*int*/ 0
+  var a5 =
+      /*cfe|dart2js.Map<num,num>*/
+      /*cfe:nnbd.Map<num,num>!*/
+      {
+    /*cfe|dart2js.int*/
+    /*cfe:nnbd.int!*/
+    0:
+        /*cfe|dart2js.double*/
+        /*cfe:nnbd.double!*/
+        0.5,
+    /*cfe|dart2js.double*/
+    /*cfe:nnbd.double!*/
+    0.5:
+        /*cfe|dart2js.int*/
+        /*cfe:nnbd.int!*/
+        0
   };
 
   // ignore: unused_local_variable
   var a6 =
       /*cfe|dart2js.Map<int,Object>*/
-      /*cfe:nnbd.Map<int!,Object>*/
+      /*cfe:nnbd.Map<int!,Object>!*/
       {
-    /*int*/ 0: /*double*/ 0.5,
-    /*int*/ 1: /*String*/ ''
+    /*cfe|dart2js.int*/
+    /*cfe:nnbd.int!*/
+    0:
+        /*cfe|dart2js.double*/
+        /*cfe:nnbd.double!*/
+        0.5,
+    /*cfe|dart2js.int*/
+    /*cfe:nnbd.int!*/
+    1:
+        /*cfe|dart2js.String*/
+        /*cfe:nnbd.String!*/
+        ''
   };
 
   // ignore: unused_local_variable
   var a7 =
       /*cfe|dart2js.Map<Object,double>*/
-      /*cfe:nnbd.Map<Object,double!>*/
+      /*cfe:nnbd.Map<Object,double!>!*/
       {
-    /*int*/ 0: /*double*/ 0.5,
-    /*String*/ '': /*double*/ 0.5
+    /*cfe|dart2js.int*/
+    /*cfe:nnbd.int!*/
+    0:
+        /*cfe|dart2js.double*/
+        /*cfe:nnbd.double!*/
+        0.5,
+    /*cfe|dart2js.String*/
+    /*cfe:nnbd.String!*/
+    '':
+        /*cfe|dart2js.double*/
+        /*cfe:nnbd.double!*/
+        0.5
   };
 
   // ignore: unused_local_variable
-  var a8 = /*Map<Object,Object>*/ {
-    /*int*/ 0: /*double*/ 0.5,
-    /*String*/ '': /*String*/ ''
+  var a8 =
+      /*cfe|dart2js.Map<Object,Object>*/
+      /*cfe:nnbd.Map<Object,Object>!*/
+      {
+    /*cfe|dart2js.int*/
+    /*cfe:nnbd.int!*/
+    0:
+        /*cfe|dart2js.double*/
+        /*cfe:nnbd.double!*/
+        0.5,
+    /*cfe|dart2js.String*/
+    /*cfe:nnbd.String!*/
+    '':
+        /*cfe|dart2js.String*/
+        /*cfe:nnbd.String!*/
+        ''
   };
 }
diff --git a/pkg/front_end/test/static_types/data/null_aware_for_in.dart b/pkg/front_end/test/static_types/data/null_aware_for_in.dart
index 6f59a39..be939a7 100644
--- a/pkg/front_end/test/static_types/data/null_aware_for_in.dart
+++ b/pkg/front_end/test/static_types/data/null_aware_for_in.dart
@@ -13,6 +13,8 @@
   /*cfe:nnbd.as: Class!*/
   for (
       // ignore: UNUSED_LOCAL_VARIABLE
-      Class c
-      in /*as: Iterable<dynamic>*/ /*dynamic*/ o?. /*dynamic*/ iterable) {}
+      Class c in
+      /*cfe|dart2js.as: Iterable<dynamic>*/
+      /*cfe:nnbd.as: Iterable<dynamic>!*/
+      /*dynamic*/ o?. /*dynamic*/ iterable) {}
 }
diff --git a/pkg/front_end/test/static_types/data/prefix_postfix.dart b/pkg/front_end/test/static_types/data/prefix_postfix.dart
index 71db218..2913a74 100644
--- a/pkg/front_end/test/static_types/data/prefix_postfix.dart
+++ b/pkg/front_end/test/static_types/data/prefix_postfix.dart
@@ -5,31 +5,49 @@
 /*cfe.library: nnbd=false*/
 /*cfe:nnbd.library: nnbd=true*/
 
-num numTopLevel = /*int*/ 0;
-int intTopLevel = /*int*/ 0;
-dynamic dynamicTopLevel = /*int*/ 0;
+num numTopLevel = /*cfe|dart2js.int*/ /*cfe:nnbd.int!*/ 0;
+int intTopLevel = /*cfe|dart2js.int*/ /*cfe:nnbd.int!*/ 0;
+dynamic dynamicTopLevel = /*cfe|dart2js.int*/ /*cfe:nnbd.int!*/ 0;
 
 testTopLevel() {
   /*cfe|dart2js.update: num*/
   /*cfe:nnbd.update: num!*/
   /*cfe|dart2js.num*/
   /*cfe:nnbd.num!*/
-  numTopLevel /*cfe|dart2js.invoke: num*/ /*cfe:nnbd.invoke: num!*/ /*int*/ ++;
+  numTopLevel
+      /*cfe|dart2js.invoke: num*/
+      /*cfe:nnbd.invoke: num!*/
+      /*cfe|dart2js.int*/
+      /*cfe:nnbd.int!*/
+      ++;
 
   /*cfe|dart2js.update: num*/
   /*cfe:nnbd.update: num!*/
   /*cfe|dart2js.num*/
   /*cfe:nnbd.num!*/
-  numTopLevel /*cfe|dart2js.invoke: num*/ /*cfe:nnbd.invoke: num!*/ /*int*/ --;
+  numTopLevel
+      /*cfe|dart2js.invoke: num*/
+      /*cfe:nnbd.invoke: num!*/
+      /*cfe|dart2js.int*/
+      /*cfe:nnbd.int!*/
+      --;
 
-  /*cfe|dart2js.invoke: num*/ /*cfe:nnbd.invoke: num!*/ /*int*/ ++
+  /*cfe|dart2js.invoke: num*/
+  /*cfe:nnbd.invoke: num!*/
+  /*cfe|dart2js.int*/
+  /*cfe:nnbd.int!*/
+  ++
       /*cfe|dart2js.update: num*/
       /*cfe:nnbd.update: num!*/
       /*cfe|dart2js.num*/
       /*cfe:nnbd.num!*/
       numTopLevel;
 
-  /*cfe|dart2js.invoke: num*/ /*cfe:nnbd.invoke: num!*/ /*int*/ --
+  /*cfe|dart2js.invoke: num*/
+  /*cfe:nnbd.invoke: num!*/
+  /*cfe|dart2js.int*/
+  /*cfe:nnbd.int!*/
+  --
       /*cfe|dart2js.update: num*/
       /*cfe:nnbd.update: num!*/
       /*cfe|dart2js.num*/
@@ -43,7 +61,9 @@
   intTopLevel
       /*cfe|dart2js.invoke: int*/
       /*cfe:nnbd.invoke: int!*/
-      /*int*/ ++;
+      /*cfe|dart2js.int*/
+      /*cfe:nnbd.int!*/
+      ++;
 
   /*cfe|dart2js.update: int*/
   /*cfe:nnbd.update: int!*/
@@ -52,11 +72,15 @@
   intTopLevel
       /*cfe|dart2js.invoke: int*/
       /*cfe:nnbd.invoke: int!*/
-      /*int*/ --;
+      /*cfe|dart2js.int*/
+      /*cfe:nnbd.int!*/
+      --;
 
   /*cfe|dart2js.invoke: int*/
   /*cfe:nnbd.invoke: int!*/
-  /*int*/ ++
+  /*cfe|dart2js.int*/
+  /*cfe:nnbd.int!*/
+  ++
       /*cfe|dart2js.update: int*/
       /*cfe:nnbd.update: int!*/
       /*cfe|dart2js.int*/
@@ -65,7 +89,9 @@
 
   /*cfe|dart2js.invoke: int*/
   /*cfe:nnbd.invoke: int!*/
-  /*int*/ --
+  /*cfe|dart2js.int*/
+  /*cfe:nnbd.int!*/
+  --
       /*cfe|dart2js.update: int*/
       /*cfe:nnbd.update: int!*/
       /*cfe|dart2js.int*/
@@ -73,22 +99,34 @@
       intTopLevel;
 
   /*update: dynamic*/ /*dynamic*/ dynamicTopLevel
-      /*invoke: dynamic*/ /*int*/ ++;
+      /*invoke: dynamic*/
+      /*cfe|dart2js.int*/
+      /*cfe:nnbd.int!*/
+      ++;
 
   /*update: dynamic*/ /*dynamic*/ dynamicTopLevel
-      /*invoke: dynamic*/ /*int*/ --;
+      /*invoke: dynamic*/
+      /*cfe|dart2js.int*/
+      /*cfe:nnbd.int!*/
+      --;
 
-  /*invoke: dynamic*/ /*int*/ ++
+  /*invoke: dynamic*/
+  /*cfe|dart2js.int*/
+  /*cfe:nnbd.int!*/
+  ++
       /*update: dynamic*/ /*dynamic*/ dynamicTopLevel;
 
-  /*invoke: dynamic*/ /*int*/ --
+  /*invoke: dynamic*/
+  /*cfe|dart2js.int*/
+  /*cfe:nnbd.int!*/
+  --
       /*update: dynamic*/ /*dynamic*/ dynamicTopLevel;
 }
 
 class Class {
-  num numInstance = /*int*/ 0;
-  int intInstance = /*int*/ 0;
-  dynamic dynamicInstance = /*int*/ 0;
+  num numInstance = /*cfe|dart2js.int*/ /*cfe:nnbd.int!*/ 0;
+  int intInstance = /*cfe|dart2js.int*/ /*cfe:nnbd.int!*/ 0;
+  dynamic dynamicInstance = /*cfe|dart2js.int*/ /*cfe:nnbd.int!*/ 0;
 
   testInstance() {
     /*cfe|dart2js.update: num*/
@@ -98,7 +136,9 @@
     numInstance
         /*cfe|dart2js.invoke: num*/
         /*cfe:nnbd.invoke: num!*/
-        /*int*/ ++;
+        /*cfe|dart2js.int*/
+        /*cfe:nnbd.int!*/
+        ++;
 
     /*cfe|dart2js.update: num*/
     /*cfe:nnbd.update: num!*/
@@ -107,16 +147,26 @@
     numInstance
         /*cfe|dart2js.invoke: num*/
         /*cfe:nnbd.invoke: num!*/
-        /*int*/ --;
+        /*cfe|dart2js.int*/
+        /*cfe:nnbd.int!*/
+        --;
 
-    /*cfe|dart2js.invoke: num*/ /*cfe:nnbd.invoke: num!*/ /*int*/ ++
+    /*cfe|dart2js.invoke: num*/
+    /*cfe:nnbd.invoke: num!*/
+    /*cfe|dart2js.int*/
+    /*cfe:nnbd.int!*/
+    ++
         /*cfe|dart2js.update: num*/
         /*cfe:nnbd.update: num!*/
         /*cfe|dart2js.num*/
         /*cfe:nnbd.num!*/
         numInstance;
 
-    /*cfe|dart2js.invoke: num*/ /*cfe:nnbd.invoke: num!*/ /*int*/ --
+    /*cfe|dart2js.invoke: num*/
+    /*cfe:nnbd.invoke: num!*/
+    /*cfe|dart2js.int*/
+    /*cfe:nnbd.int!*/
+    --
         /*cfe|dart2js.update: num*/
         /*cfe:nnbd.update: num!*/
         /*cfe|dart2js.num*/
@@ -130,7 +180,9 @@
     intInstance
         /*cfe|dart2js.invoke: int*/
         /*cfe:nnbd.invoke: int!*/
-        /*int*/ ++;
+        /*cfe|dart2js.int*/
+        /*cfe:nnbd.int!*/
+        ++;
 
     /*cfe|dart2js.update: int*/
     /*cfe:nnbd.update: int!*/
@@ -139,11 +191,15 @@
     intInstance
         /*cfe|dart2js.invoke: int*/
         /*cfe:nnbd.invoke: int!*/
-        /*int*/ --;
+        /*cfe|dart2js.int*/
+        /*cfe:nnbd.int!*/
+        --;
 
     /*cfe|dart2js.invoke: int*/
     /*cfe:nnbd.invoke: int!*/
-    /*int*/ ++
+    /*cfe|dart2js.int*/
+    /*cfe:nnbd.int!*/
+    ++
         /*cfe|dart2js.update: int*/
         /*cfe:nnbd.update: int!*/
         /*cfe|dart2js.int*/
@@ -152,7 +208,9 @@
 
     /*cfe|dart2js.invoke: int*/
     /*cfe:nnbd.invoke: int!*/
-    /*int*/ --
+    /*cfe|dart2js.int*/
+    /*cfe:nnbd.int!*/
+    --
         /*cfe|dart2js.update: int*/
         /*cfe:nnbd.update: int!*/
         /*cfe|dart2js.int*/
@@ -160,12 +218,24 @@
         intInstance;
 
     /*update: dynamic*/ /*dynamic*/ dynamicInstance
-        /*invoke: dynamic*/ /*int*/ ++;
+        /*invoke: dynamic*/
+        /*cfe|dart2js.int*/
+        /*cfe:nnbd.int!*/
+        ++;
     /*update: dynamic*/ /*dynamic*/ dynamicInstance
-        /*invoke: dynamic*/ /*int*/ --;
-    /*invoke: dynamic*/ /*int*/ ++
+        /*invoke: dynamic*/
+        /*cfe|dart2js.int*/
+        /*cfe:nnbd.int!*/
+        --;
+    /*invoke: dynamic*/
+    /*cfe|dart2js.int*/
+    /*cfe:nnbd.int!*/
+    ++
         /*update: dynamic*/ /*dynamic*/ dynamicInstance;
-    /*invoke: dynamic*/ /*int*/ --
+    /*invoke: dynamic*/
+    /*cfe|dart2js.int*/
+    /*cfe:nnbd.int!*/
+    --
         /*update: dynamic*/ /*dynamic*/ dynamicInstance;
   }
 }
@@ -179,7 +249,10 @@
           numInstance
       /*cfe|dart2js.invoke: num*/
       /*cfe:nnbd.invoke: num!*/
-      /*int*/ ++;
+      /*cfe|dart2js.int*/
+      /*cfe:nnbd.int!*/
+      ++;
+
   /*cfe|dart2js.Class*/
   /*cfe:nnbd.Class!*/
   c. /*cfe|dart2js.update: num*/ /*cfe:nnbd.update: num!*/
@@ -188,18 +261,31 @@
           numInstance
       /*cfe|dart2js.invoke: num*/
       /*cfe:nnbd.invoke: num!*/
-      /*int*/ --;
-  /*cfe|dart2js.invoke: num*/ /*cfe:nnbd.invoke: num!*/ /*int*/ ++
+      /*cfe|dart2js.int*/
+      /*cfe:nnbd.int!*/
+      --;
+
+  /*cfe|dart2js.invoke: num*/
+  /*cfe:nnbd.invoke: num!*/
+  /*cfe|dart2js.int*/
+  /*cfe:nnbd.int!*/
+  ++
       /*cfe|dart2js.Class*/
       /*cfe:nnbd.Class!*/
-      c. /*cfe|dart2js.update: num*/ /*cfe:nnbd.update: num!*/
+      c. /*cfe|dart2js.update: num*/
+          /*cfe:nnbd.update: num!*/
           /*cfe|dart2js.num*/
           /*cfe:nnbd.num!*/
           numInstance;
-  /*cfe|dart2js.invoke: num*/ /*cfe:nnbd.invoke: num!*/ /*int*/ --
+  /*cfe|dart2js.invoke: num*/
+  /*cfe:nnbd.invoke: num!*/
+  /*cfe|dart2js.int*/
+  /*cfe:nnbd.int!*/
+  --
       /*cfe|dart2js.Class*/
       /*cfe:nnbd.Class!*/
-      c. /*cfe|dart2js.update: num*/ /*cfe:nnbd.update: num!*/
+      c. /*cfe|dart2js.update: num*/
+          /*cfe:nnbd.update: num!*/
           /*cfe|dart2js.num*/
           /*cfe:nnbd.num!*/
           numInstance;
@@ -214,7 +300,9 @@
           intInstance
       /*cfe|dart2js.invoke: int*/
       /*cfe:nnbd.invoke: int!*/
-      /*int*/ ++;
+      /*cfe|dart2js.int*/
+      /*cfe:nnbd.int!*/
+      ++;
 
   /*cfe|dart2js.Class*/
   /*cfe:nnbd.Class!*/
@@ -226,11 +314,15 @@
           intInstance
       /*cfe|dart2js.invoke: int*/
       /*cfe:nnbd.invoke: int!*/
-      /*int*/ --;
+      /*cfe|dart2js.int*/
+      /*cfe:nnbd.int!*/
+      --;
 
   /*cfe|dart2js.invoke: int*/
   /*cfe:nnbd.invoke: int!*/
-  /*int*/ ++
+  /*cfe|dart2js.int*/
+  /*cfe:nnbd.int!*/
+  ++
       /*cfe|dart2js.Class*/
       /*cfe:nnbd.Class!*/
       c.
@@ -242,7 +334,9 @@
 
   /*cfe|dart2js.invoke: int*/
   /*cfe:nnbd.invoke: int!*/
-  /*int*/ --
+  /*cfe|dart2js.int*/
+  /*cfe:nnbd.int!*/
+  --
       /*cfe|dart2js.Class*/
       /*cfe:nnbd.Class!*/
       c.
@@ -255,83 +349,170 @@
   /*cfe|dart2js.Class*/
   /*cfe:nnbd.Class!*/
   c. /*update: dynamic*/ /*dynamic*/ dynamicInstance
-      /*invoke: dynamic*/ /*int*/ ++;
+      /*invoke: dynamic*/
+      /*cfe|dart2js.int*/
+      /*cfe:nnbd.int!*/
+      ++;
 
   /*cfe|dart2js.Class*/
   /*cfe:nnbd.Class!*/
   c. /*update: dynamic*/ /*dynamic*/ dynamicInstance
-      /*invoke: dynamic*/ /*int*/ --;
+      /*invoke: dynamic*/
+      /*cfe|dart2js.int*/
+      /*cfe:nnbd.int!*/
+      --;
 
-  /*invoke: dynamic*/ /*int*/ ++
+  /*invoke: dynamic*/
+  /*cfe|dart2js.int*/
+  /*cfe:nnbd.int!*/
+  ++
       /*cfe|dart2js.Class*/
       /*cfe:nnbd.Class!*/
       c. /*update: dynamic*/ /*dynamic*/ dynamicInstance;
 
-  /*invoke: dynamic*/ /*int*/ --
+  /*invoke: dynamic*/
+  /*cfe|dart2js.int*/
+  /*cfe:nnbd.int!*/
+  --
       /*cfe|dart2js.Class*/
       /*cfe:nnbd.Class!*/
       c. /*update: dynamic*/ /*dynamic*/ dynamicInstance;
 }
 
 testInstanceOnDynamic(dynamic c) {
-  /*dynamic*/ c. /*update: dynamic*/ /*dynamic*/ numInstance
-      /*invoke: dynamic*/ /*int*/ ++;
-  /*dynamic*/ c. /*update: dynamic*/ /*dynamic*/ numInstance
-      /*invoke: dynamic*/ /*int*/ --;
-  /*invoke: dynamic*/ /*int*/ ++ /*dynamic*/ c
-      . /*update: dynamic*/ /*dynamic*/ numInstance;
-  /*invoke: dynamic*/ /*int*/ -- /*dynamic*/ c
-      . /*update: dynamic*/ /*dynamic*/ numInstance;
+  /*dynamic*/ c.
+          /*update: dynamic*/ /*dynamic*/ numInstance
+      /*invoke: dynamic*/
+      /*cfe|dart2js.int*/
+      /*cfe:nnbd.int!*/
+      ++;
 
-  /*dynamic*/ c. /*update: dynamic*/ /*dynamic*/ intInstance
-      /*invoke: dynamic*/ /*int*/ ++;
-  /*dynamic*/ c. /*update: dynamic*/ /*dynamic*/ intInstance
-      /*invoke: dynamic*/ /*int*/ --;
-  /*invoke: dynamic*/ /*int*/ ++ /*dynamic*/ c
-      . /*update: dynamic*/ /*dynamic*/ intInstance;
-  /*invoke: dynamic*/ /*int*/ -- /*dynamic*/ c
-      . /*update: dynamic*/ /*dynamic*/ intInstance;
+  /*dynamic*/ c.
+          /*update: dynamic*/ /*dynamic*/ numInstance
+      /*invoke: dynamic*/
+      /*cfe|dart2js.int*/
+      /*cfe:nnbd.int!*/
+      --;
 
-  /*dynamic*/ c. /*update: dynamic*/ /*dynamic*/ dynamicInstance
-      /*invoke: dynamic*/ /*int*/ ++;
-  /*dynamic*/ c. /*update: dynamic*/ /*dynamic*/ dynamicInstance
-      /*invoke: dynamic*/ /*int*/ --;
-  /*invoke: dynamic*/ /*int*/ ++ /*dynamic*/ c
-      . /*update: dynamic*/ /*dynamic*/ dynamicInstance;
-  /*invoke: dynamic*/ /*int*/ -- /*dynamic*/ c
-      . /*update: dynamic*/ /*dynamic*/ dynamicInstance;
+  /*invoke: dynamic*/
+  /*cfe|dart2js.int*/
+  /*cfe:nnbd.int!*/
+  ++
+      /*dynamic*/ c.
+          /*update: dynamic*/ /*dynamic*/ numInstance;
+
+  /*invoke: dynamic*/
+  /*cfe|dart2js.int*/
+  /*cfe:nnbd.int!*/
+  --
+      /*dynamic*/ c.
+          /*update: dynamic*/ /*dynamic*/ numInstance;
+
+  /*dynamic*/ c.
+          /*update: dynamic*/ /*dynamic*/ intInstance
+      /*invoke: dynamic*/
+      /*cfe|dart2js.int*/
+      /*cfe:nnbd.int!*/
+      ++;
+
+  /*dynamic*/ c.
+          /*update: dynamic*/ /*dynamic*/ intInstance
+      /*invoke: dynamic*/
+      /*cfe|dart2js.int*/
+      /*cfe:nnbd.int!*/
+      --;
+
+  /*invoke: dynamic*/
+  /*cfe|dart2js.int*/
+  /*cfe:nnbd.int!*/
+  ++
+      /*dynamic*/ c.
+          /*update: dynamic*/ /*dynamic*/ intInstance;
+
+  /*invoke: dynamic*/
+  /*cfe|dart2js.int*/
+  /*cfe:nnbd.int!*/
+  --
+      /*dynamic*/ c.
+          /*update: dynamic*/ /*dynamic*/ intInstance;
+
+  /*dynamic*/ c.
+          /*update: dynamic*/ /*dynamic*/ dynamicInstance
+      /*invoke: dynamic*/
+      /*cfe|dart2js.int*/
+      /*cfe:nnbd.int!*/
+      ++;
+
+  /*dynamic*/ c.
+          /*update: dynamic*/ /*dynamic*/ dynamicInstance
+      /*invoke: dynamic*/
+      /*cfe|dart2js.int*/
+      /*cfe:nnbd.int!*/
+      --;
+
+  /*invoke: dynamic*/
+  /*cfe|dart2js.int*/
+  /*cfe:nnbd.int!*/
+  ++
+      /*dynamic*/ c.
+          /*update: dynamic*/ /*dynamic*/ dynamicInstance;
+
+  /*invoke: dynamic*/
+  /*cfe|dart2js.int*/
+  /*cfe:nnbd.int!*/
+  --
+      /*dynamic*/ c.
+          /*update: dynamic*/ /*dynamic*/ dynamicInstance;
 }
 
 main() {
   /// ignore: unused_local_variable
-  num numLocal = /*int*/ 0;
+  num numLocal = /*cfe|dart2js.int*/ /*cfe:nnbd.int!*/ 0;
 
   /// ignore: unused_local_variable
-  int intLocal = /*int*/ 0;
+  int intLocal = /*cfe|dart2js.int*/ /*cfe:nnbd.int!*/ 0;
 
   /// ignore: unused_local_variable
-  dynamic dynamicLocal = /*int*/ 0;
+  dynamic dynamicLocal = /*cfe|dart2js.int*/ /*cfe:nnbd.int!*/ 0;
 
   /*cfe|dart2js.update: num*/
   /*cfe:nnbd.update: num!*/
   /*cfe|dart2js.num*/
   /*cfe:nnbd.num!*/
-  numLocal /*cfe|dart2js.invoke: num*/ /*cfe:nnbd.invoke: num!*/ /*int*/ ++;
+  numLocal
+      /*cfe|dart2js.invoke: num*/
+      /*cfe:nnbd.invoke: num!*/
+      /*cfe|dart2js.int*/
+      /*cfe:nnbd.int!*/
+      ++;
 
   /*cfe|dart2js.update: num*/
   /*cfe:nnbd.update: num!*/
   /*cfe|dart2js.num*/
   /*cfe:nnbd.num!*/
-  numLocal /*cfe|dart2js.invoke: num*/ /*cfe:nnbd.invoke: num!*/ /*int*/ --;
+  numLocal
+      /*cfe|dart2js.invoke: num*/
+      /*cfe:nnbd.invoke: num!*/
+      /*cfe|dart2js.int*/
+      /*cfe:nnbd.int!*/
+      --;
 
-  /*cfe|dart2js.invoke: num*/ /*cfe:nnbd.invoke: num!*/ /*int*/ ++
+  /*cfe|dart2js.invoke: num*/
+  /*cfe:nnbd.invoke: num!*/
+  /*cfe|dart2js.int*/
+  /*cfe:nnbd.int!*/
+  ++
       /*cfe|dart2js.update: num*/
       /*cfe:nnbd.update: num!*/
       /*cfe|dart2js.num*/
       /*cfe:nnbd.num!*/
       numLocal;
 
-  /*cfe|dart2js.invoke: num*/ /*cfe:nnbd.invoke: num!*/ /*int*/ --
+  /*cfe|dart2js.invoke: num*/
+  /*cfe:nnbd.invoke: num!*/
+  /*cfe|dart2js.int*/
+  /*cfe:nnbd.int!*/
+  --
       /*cfe|dart2js.update: num*/
       /*cfe:nnbd.update: num!*/
       /*cfe|dart2js.num*/
@@ -345,7 +526,9 @@
   intLocal
       /*cfe|dart2js.invoke: int*/
       /*cfe:nnbd.invoke: int!*/
-      /*int*/ ++;
+      /*cfe|dart2js.int*/
+      /*cfe:nnbd.int!*/
+      ++;
 
   /*cfe|dart2js.update: int*/
   /*cfe:nnbd.update: int!*/
@@ -354,11 +537,15 @@
   intLocal
       /*cfe|dart2js.invoke: int*/
       /*cfe:nnbd.invoke: int!*/
-      /*int*/ --;
+      /*cfe|dart2js.int*/
+      /*cfe:nnbd.int!*/
+      --;
 
   /*cfe|dart2js.invoke: int*/
   /*cfe:nnbd.invoke: int!*/
-  /*int*/ ++
+  /*cfe|dart2js.int*/
+  /*cfe:nnbd.int!*/
+  ++
       /*cfe|dart2js.update: int*/
       /*cfe:nnbd.update: int!*/
       /*cfe|dart2js.int*/
@@ -367,18 +554,36 @@
 
   /*cfe|dart2js.invoke: int*/
   /*cfe:nnbd.invoke: int!*/
-  /*int*/ --
+  /*cfe|dart2js.int*/
+  /*cfe:nnbd.int!*/
+  --
       /*cfe|dart2js.update: int*/
       /*cfe:nnbd.update: int!*/
       /*cfe|dart2js.int*/
       /*cfe:nnbd.int!*/
       intLocal;
 
-  /*update: dynamic*/ /*dynamic*/ dynamicLocal /*invoke: dynamic*/ /*int*/ ++;
+  /*update: dynamic*/ /*dynamic*/ dynamicLocal
+      /*invoke: dynamic*/
+      /*cfe|dart2js.int*/
+      /*cfe:nnbd.int!*/
+      ++;
 
-  /*update: dynamic*/ /*dynamic*/ dynamicLocal /*invoke: dynamic*/ /*int*/ --;
+  /*update: dynamic*/ /*dynamic*/ dynamicLocal
+      /*invoke: dynamic*/
+      /*cfe|dart2js.int*/
+      /*cfe:nnbd.int!*/
+      --;
 
-  /*invoke: dynamic*/ /*int*/ ++ /*update: dynamic*/ /*dynamic*/ dynamicLocal;
+  /*invoke: dynamic*/
+  /*cfe|dart2js.int*/
+  /*cfe:nnbd.int!*/
+  ++
+      /*update: dynamic*/ /*dynamic*/ dynamicLocal;
 
-  /*invoke: dynamic*/ /*int*/ -- /*update: dynamic*/ /*dynamic*/ dynamicLocal;
+  /*invoke: dynamic*/
+  /*cfe|dart2js.int*/
+  /*cfe:nnbd.int!*/
+  --
+      /*update: dynamic*/ /*dynamic*/ dynamicLocal;
 }
diff --git a/pkg/front_end/test/static_types/data/promoted_access.dart b/pkg/front_end/test/static_types/data/promoted_access.dart
index a21bae7..26c66ce 100644
--- a/pkg/front_end/test/static_types/data/promoted_access.dart
+++ b/pkg/front_end/test/static_types/data/promoted_access.dart
@@ -24,7 +24,14 @@
 }
 
 main() {
-  var c = new /*Class<dynamic>*/ Class/*<dynamic>*/();
-  /*Class<dynamic>*/ c. /*invoke: dynamic*/ method(/*Class<dynamic>*/ c);
-  /*invoke: dynamic*/ method/*<Class<dynamic>>*/(/*Class<dynamic>*/ c);
+  var c = new
+      /*cfe|dart2js.Class<dynamic>*/
+      /*cfe:nnbd.Class<dynamic>!*/
+      Class/*<dynamic>*/();
+  /*cfe|dart2js.Class<dynamic>*/ /*cfe:nnbd.Class<dynamic>!*/ c
+      . /*invoke: dynamic*/ method(
+          /*cfe|dart2js.Class<dynamic>*/ /*cfe:nnbd.Class<dynamic>!*/ c);
+  /*invoke: dynamic*/ method
+      /*cfe|dart2js.<Class<dynamic>>*/ /*cfe:nnbd.<Class<dynamic>!>*/ (
+          /*cfe|dart2js.Class<dynamic>*/ /*cfe:nnbd.Class<dynamic>!*/ c);
 }
diff --git a/pkg/front_end/test/static_types/data/set_literals.dart b/pkg/front_end/test/static_types/data/set_literals.dart
index e7efad8..0a253e2 100644
--- a/pkg/front_end/test/static_types/data/set_literals.dart
+++ b/pkg/front_end/test/static_types/data/set_literals.dart
@@ -7,17 +7,44 @@
 
 main() {
   // ignore: unused_local_variable
-  var a0 = /*Map<dynamic,dynamic>*/ {};
+  var a0 =
+      /*cfe|dart2js.Map<dynamic,dynamic>*/
+      /*cfe:nnbd.Map<dynamic,dynamic>!*/
+      {};
 
   // ignore: unused_local_variable
   var a1 =
       /*cfe|dart2js.Set<int>*/
-      /*cfe:nnbd.Set<int!>*/
-      {/*int*/ 0};
+      /*cfe:nnbd.Set<int!>!*/
+      {
+    /*cfe|dart2js.int*/
+    /*cfe:nnbd.int!*/
+    0
+  };
 
   // ignore: unused_local_variable
-  var a2 = /*Set<num>*/ {/*int*/ 0, /*double*/ 0.5};
+  var a2 =
+      /*cfe|dart2js.Set<num>*/
+      /*cfe:nnbd.Set<num>!*/
+      {
+    /*cfe|dart2js.int*/
+    /*cfe:nnbd.int!*/
+    0,
+    /*cfe|dart2js.double*/
+    /*cfe:nnbd.double!*/
+    0.5
+  };
 
   // ignore: unused_local_variable
-  var a3 = /*Set<Object>*/ {/*int*/ 0, /*String*/ ''};
+  var a3 =
+      /*cfe|dart2js.Set<Object>*/
+      /*cfe:nnbd.Set<Object>!*/
+      {
+    /*cfe|dart2js.int*/
+    /*cfe:nnbd.int!*/
+    0,
+    /*cfe|dart2js.String*/
+    /*cfe:nnbd.String!*/
+    ''
+  };
 }
diff --git a/pkg/front_end/test/static_types/static_type_test.dart b/pkg/front_end/test/static_types/static_type_test.dart
index 91e66a0..6ae12f2 100644
--- a/pkg/front_end/test/static_types/static_type_test.dart
+++ b/pkg/front_end/test/static_types/static_type_test.dart
@@ -11,6 +11,7 @@
 import 'package:front_end/src/testing/id_testing_helper.dart';
 import 'package:front_end/src/testing/id_testing_utils.dart';
 import 'package:kernel/ast.dart';
+import 'package:kernel/type_environment.dart';
 
 main(List<String> args) async {
   Directory dataDir = new Directory.fromUri(Platform.script.resolve('data'));
@@ -49,6 +50,7 @@
 
 class StaticTypeDataExtractor extends CfeDataExtractor<String> {
   final TypeEnvironment _environment;
+  StaticTypeContext _staticTypeContext;
 
   StaticTypeDataExtractor(InternalCompilerResult compilerResult,
       Map<Id, ActualData<String>> actualMap)
@@ -58,6 +60,27 @@
         super(compilerResult, actualMap);
 
   @override
+  visitField(Field node) {
+    _staticTypeContext = new StaticTypeContext(node, _environment);
+    super.visitField(node);
+    _staticTypeContext = null;
+  }
+
+  @override
+  visitConstructor(Constructor node) {
+    _staticTypeContext = new StaticTypeContext(node, _environment);
+    super.visitConstructor(node);
+    _staticTypeContext = null;
+  }
+
+  @override
+  visitProcedure(Procedure node) {
+    _staticTypeContext = new StaticTypeContext(node, _environment);
+    super.visitProcedure(node);
+    _staticTypeContext = null;
+  }
+
+  @override
   String computeLibraryValue(Id id, Library node) {
     return 'nnbd=${node.isNonNullableByDefault}';
   }
@@ -65,7 +88,7 @@
   @override
   String computeNodeValue(Id id, TreeNode node) {
     if (node is Expression) {
-      DartType type = node.getStaticType(_environment);
+      DartType type = node.getStaticType(_staticTypeContext);
       return typeToText(type);
     } else if (node is Arguments) {
       if (node.types.isNotEmpty) {
diff --git a/pkg/front_end/test/unit_test_suites.dart b/pkg/front_end/test/unit_test_suites.dart
index a85b802..29cdd86 100644
--- a/pkg/front_end/test/unit_test_suites.dart
+++ b/pkg/front_end/test/unit_test_suites.dart
@@ -35,14 +35,17 @@
     show createContext;
 import 'spelling_test_src_suite.dart' as spelling_src show createContext;
 
+const suiteNamePrefix = "pkg/front_end/test";
+
 class Options {
   final String configurationName;
   final bool verbose;
   final bool printFailureLog;
   final Uri outputDirectory;
+  final String testFilter;
 
   Options(this.configurationName, this.verbose, this.printFailureLog,
-      this.outputDirectory);
+      this.outputDirectory, this.testFilter);
 
   static Options parse(List<String> args) {
     var parser = new ArgParser()
@@ -58,13 +61,23 @@
     var parsedArguments = parser.parse(args);
     String outputPath = parsedArguments["output-directory"] ?? ".";
     Uri outputDirectory = Uri.base.resolveUri(Uri.directory(outputPath));
-    return Options(parsedArguments["named-configuration"],
-        parsedArguments["verbose"], parsedArguments["print"], outputDirectory);
+    String filter;
+    if (parsedArguments.rest.length == 1) {
+      filter = parsedArguments.rest.single;
+      if (filter.startsWith("$suiteNamePrefix/")) {
+        filter = filter.substring(suiteNamePrefix.length + 1);
+      }
+    }
+    return Options(
+        parsedArguments["named-configuration"],
+        parsedArguments["verbose"],
+        parsedArguments["print"],
+        outputDirectory,
+        filter);
   }
 }
 
 class ResultLogger implements Logger {
-  final String suiteName;
   final String prefix;
   final bool verbose;
   final bool printFailureLog;
@@ -74,8 +87,8 @@
   final String configurationName;
   final Set<String> seenTests = {};
 
-  ResultLogger(this.suiteName, this.prefix, this.resultsPort, this.logsPort,
-      this.verbose, this.printFailureLog, this.configurationName);
+  ResultLogger(this.prefix, this.resultsPort, this.logsPort, this.verbose,
+      this.printFailureLog, this.configurationName);
 
   String getTestName(TestDescription description) {
     return "$prefix/${description.shortName}";
@@ -127,6 +140,8 @@
       if (result.trace != null) {
         failureLog = "$failureLog\n\n${result.trace}";
       }
+      failureLog = "$failureLog\n\nRe-run this test: dart "
+          "pkg/front_end/test/unit_test_suites.dart -p $testName";
       String outcome = "${result.outcome}";
       logsPort.send(jsonEncode({
         "name": testName,
@@ -183,12 +198,14 @@
   final String path;
   final int shardCount;
   final int shard;
+  final String prefix;
 
   const Suite(this.name, this.createContext, this.testingRootPath,
-      {this.path, this.shardCount: 1, this.shard: 0});
+      {this.path, this.shardCount: 1, this.shard: 0, String prefix})
+      : prefix = prefix ?? name;
 }
 
-final List<Suite> suites = [
+const List<Suite> suites = [
   const Suite(
       "fasta/expression", expression.createContext, "../../testing.json"),
   const Suite("fasta/outline", outline.createContext, "../../testing.json"),
@@ -200,13 +217,25 @@
   const Suite("fasta/text_serialization", text_serialization.createContext,
       "../../testing.json"),
   const Suite("fasta/strong1", strong.createContext, "../../testing.json",
-      path: "fasta/strong_tester.dart", shardCount: 4, shard: 0),
+      path: "fasta/strong_tester.dart",
+      shardCount: 4,
+      shard: 0,
+      prefix: "fasta/strong"),
   const Suite("fasta/strong2", strong.createContext, "../../testing.json",
-      path: "fasta/strong_tester.dart", shardCount: 4, shard: 1),
+      path: "fasta/strong_tester.dart",
+      shardCount: 4,
+      shard: 1,
+      prefix: "fasta/strong"),
   const Suite("fasta/strong3", strong.createContext, "../../testing.json",
-      path: "fasta/strong_tester.dart", shardCount: 4, shard: 2),
+      path: "fasta/strong_tester.dart",
+      shardCount: 4,
+      shard: 2,
+      prefix: "fasta/strong"),
   const Suite("fasta/strong4", strong.createContext, "../../testing.json",
-      path: "fasta/strong_tester.dart", shardCount: 4, shard: 3),
+      path: "fasta/strong_tester.dart",
+      shardCount: 4,
+      shard: 3,
+      prefix: "fasta/strong"),
   const Suite("incremental_bulk_compiler_smoke",
       incremental_bulk_compiler.createContext, "../testing.json"),
   const Suite("incremental_load_from_dill", incremental_load.createContext,
@@ -229,24 +258,32 @@
   final bool verbose;
   final bool printFailureLog;
   final String configurationName;
-  const SuiteConfiguration(this.name, this.resultsPort, this.logsPort,
-      this.verbose, this.printFailureLog, this.configurationName);
+  final String testFilter;
+  const SuiteConfiguration(
+      this.name,
+      this.resultsPort,
+      this.logsPort,
+      this.verbose,
+      this.printFailureLog,
+      this.configurationName,
+      this.testFilter);
 }
 
 void runSuite(SuiteConfiguration configuration) {
   Suite suite = suites.where((s) => s.name == configuration.name).single;
-  String name = suite.name;
-  String fullSuiteName = "pkg/front_end/test/$name";
+  String name = suite.prefix;
+  String fullSuiteName = "$suiteNamePrefix/$name";
   Uri suiteUri = Platform.script.resolve(suite.path ?? "${name}_suite.dart");
   ResultLogger logger = ResultLogger(
-      name,
       fullSuiteName,
       configuration.resultsPort,
       configuration.logsPort,
       configuration.verbose,
       configuration.printFailureLog,
       configuration.configurationName);
-  runMe(<String>[], suite.createContext,
+  runMe(
+      <String>[if (configuration.testFilter != null) configuration.testFilter],
+      suite.createContext,
       me: suiteUri,
       configurationPath: suite.testingRootPath,
       logger: logger,
@@ -269,21 +306,32 @@
   List<Future<bool>> futures = [];
   // Run test suites and record the results and possible failure logs.
   for (Suite suite in suites) {
+    String name = suite.name;
+    String filter = options.testFilter;
+    if (filter != null) {
+      // Skip suites that are not hit by the test filter, is there is one.
+      if (!filter.startsWith(suite.prefix)) {
+        continue;
+      }
+      // Remove the 'fasta/' from filters, if there, because it is not used
+      // in the name defined in testing.json.
+      if (filter.startsWith("fasta/")) {
+        filter = filter.substring("fasta/".length);
+      }
+    }
     // Start the test suite in a new isolate.
     ReceivePort exitPort = new ReceivePort();
-    String name = suite.name;
     SuiteConfiguration configuration = SuiteConfiguration(
         name,
         resultsPort.sendPort,
         logsPort.sendPort,
         options.verbose,
         options.printFailureLog,
-        options.configurationName);
+        options.configurationName,
+        filter);
     Future future = Future<bool>(() async {
       Stopwatch stopwatch = Stopwatch()..start();
       print("Running suite $name");
-      // TODO(karlklose): Implement --filter to select tests to run
-      // to implement deflaking (dartbug.com/38607).
       Isolate isolate = await Isolate.spawn<SuiteConfiguration>(
           runSuite, configuration,
           onExit: exitPort.sendPort);
@@ -320,8 +368,8 @@
   if (timeout) {
     exitCode = 1;
   } else {
-    // The testing framework (pkg/testing) sets the exitCode to 1 if any test
-    // failed, so we reset it here to indicate that the test runner was
+    // The testing framework (package:testing) sets the exitCode to `1` if any
+    // test failed, so we reset it here to indicate that the test runner was
     // successful.
     exitCode = 0;
   }
diff --git a/pkg/front_end/testcases/extensions/call_methods.dart b/pkg/front_end/testcases/extensions/call_methods.dart
new file mode 100644
index 0000000..1850a3b
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/call_methods.dart
@@ -0,0 +1,40 @@
+// Copyright (c) 2019, 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 {
+  String get call => "My name is A";
+}
+
+class B {
+  String Function() get call => () => "My name is B";
+}
+
+extension on int {
+  String get call => "My name is int";
+}
+
+extension on num {
+  String get call => "My name is num";
+}
+
+extension on String {
+  String Function() get call => () => "My name is String";
+}
+
+main() {
+  // TODO(johnniwinther): Should the be an error?
+  ""();
+}
+
+errors() {
+  1(10);
+  1("10");
+  1.0(10);
+  1.0("10");
+  A a = new A();
+  a(2);
+  a(2, "3");
+  B b = new B();
+  b();
+}
diff --git a/pkg/front_end/testcases/extensions/call_methods.dart.outline.expect b/pkg/front_end/testcases/extensions/call_methods.dart.outline.expect
new file mode 100644
index 0000000..b57cf7b
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/call_methods.dart.outline.expect
@@ -0,0 +1,35 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A*
+    ;
+  get call() → core::String*
+    ;
+}
+class B extends core::Object {
+  synthetic constructor •() → self::B*
+    ;
+  get call() → () →* core::String*
+    ;
+}
+extension _extension#0 on core::int* {
+  get call = self::_extension#0|get#call;
+}
+extension _extension#1 on core::num* {
+  get call = self::_extension#1|get#call;
+}
+extension _extension#2 on core::String* {
+  get call = self::_extension#2|get#call;
+}
+static method _extension#0|get#call(final core::int* #this) → core::String*
+  ;
+static method _extension#1|get#call(final core::num* #this) → core::String*
+  ;
+static method _extension#2|get#call(final core::String* #this) → () →* core::String*
+  ;
+static method main() → dynamic
+  ;
+static method errors() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/extensions/call_methods.dart.strong.expect b/pkg/front_end/testcases/extensions/call_methods.dart.strong.expect
new file mode 100644
index 0000000..6227c6f
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/call_methods.dart.strong.expect
@@ -0,0 +1,101 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extensions/call_methods.dart:27:5: Error: Too many positional arguments: 0 allowed, but 1 found.
+// Try removing the extra positional arguments.
+//   ""();
+//     ^
+//
+// pkg/front_end/testcases/extensions/call_methods.dart:31:4: Error: 'call' isn't a function or method and can't be invoked.
+//   1(10);
+//    ^
+//
+// pkg/front_end/testcases/extensions/call_methods.dart:32:4: Error: 'call' isn't a function or method and can't be invoked.
+//   1("10");
+//    ^
+//
+// pkg/front_end/testcases/extensions/call_methods.dart:33:6: Error: 'call' isn't a function or method and can't be invoked.
+//   1.0(10);
+//      ^
+//
+// pkg/front_end/testcases/extensions/call_methods.dart:34:6: Error: 'call' isn't a function or method and can't be invoked.
+//   1.0("10");
+//      ^
+//
+// pkg/front_end/testcases/extensions/call_methods.dart:36:4: Error: 'call' isn't a function or method and can't be invoked.
+//   a(2);
+//    ^
+//
+// pkg/front_end/testcases/extensions/call_methods.dart:37:4: Error: 'call' isn't a function or method and can't be invoked.
+//   a(2, "3");
+//    ^
+//
+// pkg/front_end/testcases/extensions/call_methods.dart:39:4: Error: Cannot invoke an instance of 'B' because it declares 'call' to be something other than a method.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/call_methods.dart'.
+// Try changing 'call' to a method or explicitly invoke 'call'.
+//   b();
+//    ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A*
+    : super core::Object::•()
+    ;
+  get call() → core::String*
+    return "My name is A";
+}
+class B extends core::Object {
+  synthetic constructor •() → self::B*
+    : super core::Object::•()
+    ;
+  get call() → () →* core::String*
+    return () → core::String* => "My name is B";
+}
+extension _extension#0 on core::int* {
+  get call = self::_extension#0|get#call;
+}
+extension _extension#1 on core::num* {
+  get call = self::_extension#1|get#call;
+}
+extension _extension#2 on core::String* {
+  get call = self::_extension#2|get#call;
+}
+static method _extension#0|get#call(final core::int* #this) → core::String*
+  return "My name is int";
+static method _extension#1|get#call(final core::num* #this) → core::String*
+  return "My name is num";
+static method _extension#2|get#call(final core::String* #this) → () →* core::String*
+  return () → core::String* => "My name is String";
+static method main() → dynamic {
+  self::_extension#2|get#call("");
+}
+static method errors() → dynamic {
+  invalid-expression "pkg/front_end/testcases/extensions/call_methods.dart:31:4: Error: 'call' isn't a function or method and can't be invoked.
+  1(10);
+   ^";
+  invalid-expression "pkg/front_end/testcases/extensions/call_methods.dart:32:4: Error: 'call' isn't a function or method and can't be invoked.
+  1(\"10\");
+   ^";
+  invalid-expression "pkg/front_end/testcases/extensions/call_methods.dart:33:6: Error: 'call' isn't a function or method and can't be invoked.
+  1.0(10);
+     ^";
+  invalid-expression "pkg/front_end/testcases/extensions/call_methods.dart:34:6: Error: 'call' isn't a function or method and can't be invoked.
+  1.0(\"10\");
+     ^";
+  self::A* a = new self::A::•();
+  invalid-expression "pkg/front_end/testcases/extensions/call_methods.dart:36:4: Error: 'call' isn't a function or method and can't be invoked.
+  a(2);
+   ^";
+  invalid-expression "pkg/front_end/testcases/extensions/call_methods.dart:37:4: Error: 'call' isn't a function or method and can't be invoked.
+  a(2, \"3\");
+   ^";
+  self::B* b = new self::B::•();
+  invalid-expression "pkg/front_end/testcases/extensions/call_methods.dart:39:4: Error: Cannot invoke an instance of 'B' because it declares 'call' to be something other than a method.
+ - 'B' is from 'pkg/front_end/testcases/extensions/call_methods.dart'.
+Try changing 'call' to a method or explicitly invoke 'call'.
+  b();
+   ^";
+}
diff --git a/pkg/front_end/testcases/extensions/call_methods.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/call_methods.dart.strong.transformed.expect
new file mode 100644
index 0000000..6227c6f
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/call_methods.dart.strong.transformed.expect
@@ -0,0 +1,101 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extensions/call_methods.dart:27:5: Error: Too many positional arguments: 0 allowed, but 1 found.
+// Try removing the extra positional arguments.
+//   ""();
+//     ^
+//
+// pkg/front_end/testcases/extensions/call_methods.dart:31:4: Error: 'call' isn't a function or method and can't be invoked.
+//   1(10);
+//    ^
+//
+// pkg/front_end/testcases/extensions/call_methods.dart:32:4: Error: 'call' isn't a function or method and can't be invoked.
+//   1("10");
+//    ^
+//
+// pkg/front_end/testcases/extensions/call_methods.dart:33:6: Error: 'call' isn't a function or method and can't be invoked.
+//   1.0(10);
+//      ^
+//
+// pkg/front_end/testcases/extensions/call_methods.dart:34:6: Error: 'call' isn't a function or method and can't be invoked.
+//   1.0("10");
+//      ^
+//
+// pkg/front_end/testcases/extensions/call_methods.dart:36:4: Error: 'call' isn't a function or method and can't be invoked.
+//   a(2);
+//    ^
+//
+// pkg/front_end/testcases/extensions/call_methods.dart:37:4: Error: 'call' isn't a function or method and can't be invoked.
+//   a(2, "3");
+//    ^
+//
+// pkg/front_end/testcases/extensions/call_methods.dart:39:4: Error: Cannot invoke an instance of 'B' because it declares 'call' to be something other than a method.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/call_methods.dart'.
+// Try changing 'call' to a method or explicitly invoke 'call'.
+//   b();
+//    ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A*
+    : super core::Object::•()
+    ;
+  get call() → core::String*
+    return "My name is A";
+}
+class B extends core::Object {
+  synthetic constructor •() → self::B*
+    : super core::Object::•()
+    ;
+  get call() → () →* core::String*
+    return () → core::String* => "My name is B";
+}
+extension _extension#0 on core::int* {
+  get call = self::_extension#0|get#call;
+}
+extension _extension#1 on core::num* {
+  get call = self::_extension#1|get#call;
+}
+extension _extension#2 on core::String* {
+  get call = self::_extension#2|get#call;
+}
+static method _extension#0|get#call(final core::int* #this) → core::String*
+  return "My name is int";
+static method _extension#1|get#call(final core::num* #this) → core::String*
+  return "My name is num";
+static method _extension#2|get#call(final core::String* #this) → () →* core::String*
+  return () → core::String* => "My name is String";
+static method main() → dynamic {
+  self::_extension#2|get#call("");
+}
+static method errors() → dynamic {
+  invalid-expression "pkg/front_end/testcases/extensions/call_methods.dart:31:4: Error: 'call' isn't a function or method and can't be invoked.
+  1(10);
+   ^";
+  invalid-expression "pkg/front_end/testcases/extensions/call_methods.dart:32:4: Error: 'call' isn't a function or method and can't be invoked.
+  1(\"10\");
+   ^";
+  invalid-expression "pkg/front_end/testcases/extensions/call_methods.dart:33:6: Error: 'call' isn't a function or method and can't be invoked.
+  1.0(10);
+     ^";
+  invalid-expression "pkg/front_end/testcases/extensions/call_methods.dart:34:6: Error: 'call' isn't a function or method and can't be invoked.
+  1.0(\"10\");
+     ^";
+  self::A* a = new self::A::•();
+  invalid-expression "pkg/front_end/testcases/extensions/call_methods.dart:36:4: Error: 'call' isn't a function or method and can't be invoked.
+  a(2);
+   ^";
+  invalid-expression "pkg/front_end/testcases/extensions/call_methods.dart:37:4: Error: 'call' isn't a function or method and can't be invoked.
+  a(2, \"3\");
+   ^";
+  self::B* b = new self::B::•();
+  invalid-expression "pkg/front_end/testcases/extensions/call_methods.dart:39:4: Error: Cannot invoke an instance of 'B' because it declares 'call' to be something other than a method.
+ - 'B' is from 'pkg/front_end/testcases/extensions/call_methods.dart'.
+Try changing 'call' to a method or explicitly invoke 'call'.
+  b();
+   ^";
+}
diff --git a/pkg/front_end/testcases/extensions/deferred_explicit_access.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/deferred_explicit_access.dart.strong.transformed.expect
index ddb1b0a..47f973b 100644
--- a/pkg/front_end/testcases/extensions/deferred_explicit_access.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/extensions/deferred_explicit_access.dart.strong.transformed.expect
@@ -20,7 +20,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   dynamic :saved_try_context_var0;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
diff --git a/pkg/front_end/testcases/extensions/deferred_import_hidden.dart.strong.expect b/pkg/front_end/testcases/extensions/deferred_import_hidden.dart.strong.expect
index 1341a83..8fe4a36 100644
--- a/pkg/front_end/testcases/extensions/deferred_import_hidden.dart.strong.expect
+++ b/pkg/front_end/testcases/extensions/deferred_import_hidden.dart.strong.expect
@@ -1,6 +1,7 @@
 library;
 import self as self;
 import "deferred_explicit_access_lib.dart" as def;
+import "dart:core" as core;
 
 import "org-dartlang-testcase:///deferred_explicit_access_lib.dart" deferred as prefix;
 
@@ -15,7 +16,7 @@
   self::expect(87, let final dynamic #t7 = CheckLibraryIsLoaded(prefix) in def::topLevelMethod());
 }
 static method expect(dynamic expected, dynamic actual) → dynamic {
-  if(!expected.{dart.core::Object::==}(actual))
+  if(!expected.{core::Object::==}(actual))
     throw "Expected ${expected}, actual ${actual}";
 }
 
diff --git a/pkg/front_end/testcases/extensions/deferred_import_hidden.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/deferred_import_hidden.dart.strong.transformed.expect
index 0508e3e..bcb6ce3 100644
--- a/pkg/front_end/testcases/extensions/deferred_import_hidden.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/extensions/deferred_import_hidden.dart.strong.transformed.expect
@@ -12,7 +12,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   dynamic :saved_try_context_var0;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
diff --git a/pkg/front_end/testcases/extensions/import_via_prefix.dart.strong.expect b/pkg/front_end/testcases/extensions/import_via_prefix.dart.strong.expect
index 255aa8c..7030c4a 100644
--- a/pkg/front_end/testcases/extensions/import_via_prefix.dart.strong.expect
+++ b/pkg/front_end/testcases/extensions/import_via_prefix.dart.strong.expect
@@ -1,6 +1,7 @@
 library;
 import self as self;
 import "import_via_prefix_lib.dart" as imp;
+import "dart:core" as core;
 
 import "org-dartlang-testcase:///import_via_prefix_lib.dart" as prefix;
 
@@ -8,7 +9,7 @@
   self::expect(3, imp::Extension|method("foo"));
 }
 static method expect(dynamic expected, dynamic actual) → dynamic {
-  if(!expected.{dart.core::Object::==}(actual))
+  if(!expected.{core::Object::==}(actual))
     throw "Expected ${expected}, actual ${actual}";
 }
 
diff --git a/pkg/front_end/testcases/extensions/import_via_prefix.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/import_via_prefix.dart.strong.transformed.expect
index 255aa8c..7030c4a 100644
--- a/pkg/front_end/testcases/extensions/import_via_prefix.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/extensions/import_via_prefix.dart.strong.transformed.expect
@@ -1,6 +1,7 @@
 library;
 import self as self;
 import "import_via_prefix_lib.dart" as imp;
+import "dart:core" as core;
 
 import "org-dartlang-testcase:///import_via_prefix_lib.dart" as prefix;
 
@@ -8,7 +9,7 @@
   self::expect(3, imp::Extension|method("foo"));
 }
 static method expect(dynamic expected, dynamic actual) → dynamic {
-  if(!expected.{dart.core::Object::==}(actual))
+  if(!expected.{core::Object::==}(actual))
     throw "Expected ${expected}, actual ${actual}";
 }
 
diff --git a/pkg/front_end/testcases/extensions/index.dart.strong.expect b/pkg/front_end/testcases/extensions/index.dart.strong.expect
index cc8481e..52fbaa5 100644
--- a/pkg/front_end/testcases/extensions/index.dart.strong.expect
+++ b/pkg/front_end/testcases/extensions/index.dart.strong.expect
@@ -72,11 +72,11 @@
   self::expect("3", self::Extension|[]<core::int*, core::String*>(map1, 3));
   self::MapLike<core::int*, core::int*>* map2 = new self::MapLike::•<core::int*, core::int*>();
   self::expect(1, let final self::MapLike<core::int*, core::int*>* #t61 = map2 in let final core::int* #t62 = 0 in let final core::int* #t63 = 1 in let final void #t64 = self::Extension|[]=<core::int*, core::int*>(#t61, #t62, #t63) in #t63);
-  self::expect(3, let final core::Object* #t65 = map2 in let final core::int* #t66 = 0 in let final core::int* #t67 = self::Extension|[]<core::int*, core::int*>(#t65, #t66).{core::num::+}(2) in let final void #t68 = self::Extension|[]=<core::int*, core::int*>(#t65, #t66, #t67) in #t67);
-  self::expect(5, let final core::Object* #t69 = map2 in let final core::int* #t70 = 0 in let final core::int* #t71 = self::Extension|[]<core::int*, core::int*>(#t69, #t70).{core::num::+}(2) in let final void #t72 = self::Extension|[]=<core::int*, core::int*>(#t69, #t70, #t71) in #t71);
-  self::expect(5, let final core::Object* #t73 = map2 in let final core::int* #t74 = 0 in let final core::int* #t75 = self::Extension|[]<core::int*, core::int*>(#t73, #t74) in let final void #t76 = self::Extension|[]=<core::int*, core::int*>(#t73, #t74, #t75.{core::num::+}(1)) in #t75);
+  self::expect(3, let final self::MapLike<core::int*, core::int*>* #t65 = map2 in let final core::int* #t66 = 0 in let final core::int* #t67 = self::Extension|[]<core::int*, core::int*>(#t65, #t66).{core::num::+}(2) in let final void #t68 = self::Extension|[]=<core::int*, core::int*>(#t65, #t66, #t67) in #t67);
+  self::expect(5, let final self::MapLike<core::int*, core::int*>* #t69 = map2 in let final core::int* #t70 = 0 in let final core::int* #t71 = self::Extension|[]<core::int*, core::int*>(#t69, #t70).{core::num::+}(2) in let final void #t72 = self::Extension|[]=<core::int*, core::int*>(#t69, #t70, #t71) in #t71);
+  self::expect(5, let final self::MapLike<core::int*, core::int*>* #t73 = map2 in let final core::int* #t74 = 0 in let final core::int* #t75 = self::Extension|[]<core::int*, core::int*>(#t73, #t74) in let final void #t76 = self::Extension|[]=<core::int*, core::int*>(#t73, #t74, #t75.{core::num::+}(1)) in #t75);
   self::expect(6, self::Extension|[]<core::int*, core::int*>(map2, 0));
-  self::expect(5, let final core::Object* #t77 = map2 in let final core::int* #t78 = 0 in let final core::int* #t79 = self::Extension|[]<core::int*, core::int*>(#t77, #t78).{core::num::-}(1) in let final void #t80 = self::Extension|[]=<core::int*, core::int*>(#t77, #t78, #t79) in #t79);
+  self::expect(5, let final self::MapLike<core::int*, core::int*>* #t77 = map2 in let final core::int* #t78 = 0 in let final core::int* #t79 = self::Extension|[]<core::int*, core::int*>(#t77, #t78).{core::num::-}(1) in let final void #t80 = self::Extension|[]=<core::int*, core::int*>(#t77, #t78, #t79) in #t79);
   self::expect(5, self::Extension|[]<core::int*, core::int*>(map2, 0));
 }
 static method explicitInferredTypeArguments() → dynamic {
@@ -99,11 +99,11 @@
   self::expect("3", self::Extension|[]<core::int*, core::String*>(map1, 3));
   self::MapLike<core::int*, core::int*>* map2 = new self::MapLike::•<core::int*, core::int*>();
   self::expect(1, let final self::MapLike<core::int*, core::int*>* #t99 = map2 in let final core::int* #t100 = 0 in let final core::int* #t101 = 1 in let final void #t102 = self::Extension|[]=<core::int*, core::int*>(#t99, #t100, #t101) in #t101);
-  self::expect(3, let final core::Object* #t103 = map2 in let final core::int* #t104 = 0 in let final core::int* #t105 = self::Extension|[]<core::int*, core::int*>(#t103, #t104).{core::num::+}(2) in let final void #t106 = self::Extension|[]=<core::int*, core::int*>(#t103, #t104, #t105) in #t105);
-  self::expect(5, let final core::Object* #t107 = map2 in let final core::int* #t108 = 0 in let final core::int* #t109 = self::Extension|[]<core::int*, core::int*>(#t107, #t108).{core::num::+}(2) in let final void #t110 = self::Extension|[]=<core::int*, core::int*>(#t107, #t108, #t109) in #t109);
-  self::expect(5, let final core::Object* #t111 = map2 in let final core::int* #t112 = 0 in let final core::int* #t113 = self::Extension|[]<core::int*, core::int*>(#t111, #t112) in let final void #t114 = self::Extension|[]=<core::int*, core::int*>(#t111, #t112, #t113.{core::num::+}(1)) in #t113);
+  self::expect(3, let final self::MapLike<core::int*, core::int*>* #t103 = map2 in let final core::int* #t104 = 0 in let final core::int* #t105 = self::Extension|[]<core::int*, core::int*>(#t103, #t104).{core::num::+}(2) in let final void #t106 = self::Extension|[]=<core::int*, core::int*>(#t103, #t104, #t105) in #t105);
+  self::expect(5, let final self::MapLike<core::int*, core::int*>* #t107 = map2 in let final core::int* #t108 = 0 in let final core::int* #t109 = self::Extension|[]<core::int*, core::int*>(#t107, #t108).{core::num::+}(2) in let final void #t110 = self::Extension|[]=<core::int*, core::int*>(#t107, #t108, #t109) in #t109);
+  self::expect(5, let final self::MapLike<core::int*, core::int*>* #t111 = map2 in let final core::int* #t112 = 0 in let final core::int* #t113 = self::Extension|[]<core::int*, core::int*>(#t111, #t112) in let final void #t114 = self::Extension|[]=<core::int*, core::int*>(#t111, #t112, #t113.{core::num::+}(1)) in #t113);
   self::expect(6, self::Extension|[]<core::int*, core::int*>(map2, 0));
-  self::expect(5, let final core::Object* #t115 = map2 in let final core::int* #t116 = 0 in let final core::int* #t117 = self::Extension|[]<core::int*, core::int*>(#t115, #t116).{core::num::-}(1) in let final void #t118 = self::Extension|[]=<core::int*, core::int*>(#t115, #t116, #t117) in #t117);
+  self::expect(5, let final self::MapLike<core::int*, core::int*>* #t115 = map2 in let final core::int* #t116 = 0 in let final core::int* #t117 = self::Extension|[]<core::int*, core::int*>(#t115, #t116).{core::num::-}(1) in let final void #t118 = self::Extension|[]=<core::int*, core::int*>(#t115, #t116, #t117) in #t117);
   self::expect(5, self::Extension|[]<core::int*, core::int*>(map2, 0));
 }
 static method expect(dynamic expected, dynamic actual) → dynamic {
diff --git a/pkg/front_end/testcases/extensions/index.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/index.dart.strong.transformed.expect
index cc8481e..52fbaa5 100644
--- a/pkg/front_end/testcases/extensions/index.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/extensions/index.dart.strong.transformed.expect
@@ -72,11 +72,11 @@
   self::expect("3", self::Extension|[]<core::int*, core::String*>(map1, 3));
   self::MapLike<core::int*, core::int*>* map2 = new self::MapLike::•<core::int*, core::int*>();
   self::expect(1, let final self::MapLike<core::int*, core::int*>* #t61 = map2 in let final core::int* #t62 = 0 in let final core::int* #t63 = 1 in let final void #t64 = self::Extension|[]=<core::int*, core::int*>(#t61, #t62, #t63) in #t63);
-  self::expect(3, let final core::Object* #t65 = map2 in let final core::int* #t66 = 0 in let final core::int* #t67 = self::Extension|[]<core::int*, core::int*>(#t65, #t66).{core::num::+}(2) in let final void #t68 = self::Extension|[]=<core::int*, core::int*>(#t65, #t66, #t67) in #t67);
-  self::expect(5, let final core::Object* #t69 = map2 in let final core::int* #t70 = 0 in let final core::int* #t71 = self::Extension|[]<core::int*, core::int*>(#t69, #t70).{core::num::+}(2) in let final void #t72 = self::Extension|[]=<core::int*, core::int*>(#t69, #t70, #t71) in #t71);
-  self::expect(5, let final core::Object* #t73 = map2 in let final core::int* #t74 = 0 in let final core::int* #t75 = self::Extension|[]<core::int*, core::int*>(#t73, #t74) in let final void #t76 = self::Extension|[]=<core::int*, core::int*>(#t73, #t74, #t75.{core::num::+}(1)) in #t75);
+  self::expect(3, let final self::MapLike<core::int*, core::int*>* #t65 = map2 in let final core::int* #t66 = 0 in let final core::int* #t67 = self::Extension|[]<core::int*, core::int*>(#t65, #t66).{core::num::+}(2) in let final void #t68 = self::Extension|[]=<core::int*, core::int*>(#t65, #t66, #t67) in #t67);
+  self::expect(5, let final self::MapLike<core::int*, core::int*>* #t69 = map2 in let final core::int* #t70 = 0 in let final core::int* #t71 = self::Extension|[]<core::int*, core::int*>(#t69, #t70).{core::num::+}(2) in let final void #t72 = self::Extension|[]=<core::int*, core::int*>(#t69, #t70, #t71) in #t71);
+  self::expect(5, let final self::MapLike<core::int*, core::int*>* #t73 = map2 in let final core::int* #t74 = 0 in let final core::int* #t75 = self::Extension|[]<core::int*, core::int*>(#t73, #t74) in let final void #t76 = self::Extension|[]=<core::int*, core::int*>(#t73, #t74, #t75.{core::num::+}(1)) in #t75);
   self::expect(6, self::Extension|[]<core::int*, core::int*>(map2, 0));
-  self::expect(5, let final core::Object* #t77 = map2 in let final core::int* #t78 = 0 in let final core::int* #t79 = self::Extension|[]<core::int*, core::int*>(#t77, #t78).{core::num::-}(1) in let final void #t80 = self::Extension|[]=<core::int*, core::int*>(#t77, #t78, #t79) in #t79);
+  self::expect(5, let final self::MapLike<core::int*, core::int*>* #t77 = map2 in let final core::int* #t78 = 0 in let final core::int* #t79 = self::Extension|[]<core::int*, core::int*>(#t77, #t78).{core::num::-}(1) in let final void #t80 = self::Extension|[]=<core::int*, core::int*>(#t77, #t78, #t79) in #t79);
   self::expect(5, self::Extension|[]<core::int*, core::int*>(map2, 0));
 }
 static method explicitInferredTypeArguments() → dynamic {
@@ -99,11 +99,11 @@
   self::expect("3", self::Extension|[]<core::int*, core::String*>(map1, 3));
   self::MapLike<core::int*, core::int*>* map2 = new self::MapLike::•<core::int*, core::int*>();
   self::expect(1, let final self::MapLike<core::int*, core::int*>* #t99 = map2 in let final core::int* #t100 = 0 in let final core::int* #t101 = 1 in let final void #t102 = self::Extension|[]=<core::int*, core::int*>(#t99, #t100, #t101) in #t101);
-  self::expect(3, let final core::Object* #t103 = map2 in let final core::int* #t104 = 0 in let final core::int* #t105 = self::Extension|[]<core::int*, core::int*>(#t103, #t104).{core::num::+}(2) in let final void #t106 = self::Extension|[]=<core::int*, core::int*>(#t103, #t104, #t105) in #t105);
-  self::expect(5, let final core::Object* #t107 = map2 in let final core::int* #t108 = 0 in let final core::int* #t109 = self::Extension|[]<core::int*, core::int*>(#t107, #t108).{core::num::+}(2) in let final void #t110 = self::Extension|[]=<core::int*, core::int*>(#t107, #t108, #t109) in #t109);
-  self::expect(5, let final core::Object* #t111 = map2 in let final core::int* #t112 = 0 in let final core::int* #t113 = self::Extension|[]<core::int*, core::int*>(#t111, #t112) in let final void #t114 = self::Extension|[]=<core::int*, core::int*>(#t111, #t112, #t113.{core::num::+}(1)) in #t113);
+  self::expect(3, let final self::MapLike<core::int*, core::int*>* #t103 = map2 in let final core::int* #t104 = 0 in let final core::int* #t105 = self::Extension|[]<core::int*, core::int*>(#t103, #t104).{core::num::+}(2) in let final void #t106 = self::Extension|[]=<core::int*, core::int*>(#t103, #t104, #t105) in #t105);
+  self::expect(5, let final self::MapLike<core::int*, core::int*>* #t107 = map2 in let final core::int* #t108 = 0 in let final core::int* #t109 = self::Extension|[]<core::int*, core::int*>(#t107, #t108).{core::num::+}(2) in let final void #t110 = self::Extension|[]=<core::int*, core::int*>(#t107, #t108, #t109) in #t109);
+  self::expect(5, let final self::MapLike<core::int*, core::int*>* #t111 = map2 in let final core::int* #t112 = 0 in let final core::int* #t113 = self::Extension|[]<core::int*, core::int*>(#t111, #t112) in let final void #t114 = self::Extension|[]=<core::int*, core::int*>(#t111, #t112, #t113.{core::num::+}(1)) in #t113);
   self::expect(6, self::Extension|[]<core::int*, core::int*>(map2, 0));
-  self::expect(5, let final core::Object* #t115 = map2 in let final core::int* #t116 = 0 in let final core::int* #t117 = self::Extension|[]<core::int*, core::int*>(#t115, #t116).{core::num::-}(1) in let final void #t118 = self::Extension|[]=<core::int*, core::int*>(#t115, #t116, #t117) in #t117);
+  self::expect(5, let final self::MapLike<core::int*, core::int*>* #t115 = map2 in let final core::int* #t116 = 0 in let final core::int* #t117 = self::Extension|[]<core::int*, core::int*>(#t115, #t116).{core::num::-}(1) in let final void #t118 = self::Extension|[]=<core::int*, core::int*>(#t115, #t116, #t117) in #t117);
   self::expect(5, self::Extension|[]<core::int*, core::int*>(map2, 0));
 }
 static method expect(dynamic expected, dynamic actual) → dynamic {
diff --git a/pkg/front_end/testcases/general/async_function.dart.strong.transformed.expect b/pkg/front_end/testcases/general/async_function.dart.strong.transformed.expect
index ca61355..a4a39f8 100644
--- a/pkg/front_end/testcases/general/async_function.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/async_function.dart.strong.transformed.expect
@@ -2,6 +2,7 @@
 import self as self;
 import "dart:async" as asy;
 import "dart:core" as core;
+import "dart:_internal" as _in;
 
 import "dart:async";
 
@@ -12,7 +13,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
     try {
@@ -39,7 +40,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
     try {
@@ -61,7 +62,7 @@
   return :async_completer.{asy::Completer::future};
 }
 static method syncStarString() → core::Iterable<core::String*>* /* originally sync* */ {
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   function :sync_op(core::_SyncIterator<core::String*>* :iterator) → core::bool* yielding {
     {
@@ -83,7 +84,7 @@
   return new core::_SyncIterable::•<core::String*>(:sync_op);
 }
 static method syncStarString2() → core::Iterable<core::String*>* /* originally sync* */ {
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   function :sync_op(core::_SyncIterator<core::String*>* :iterator) → core::bool* yielding {
     {
@@ -102,7 +103,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   dynamic :saved_try_context_var0;
   dynamic :saved_try_context_var1;
@@ -120,7 +121,7 @@
           else
             [yield] null;
           [yield] let dynamic #t1 = asy::_awaitHelper(self::asyncString(), :async_op_then, :async_op_error, :async_op) in null;
-          if(:controller.{asy::_AsyncStarStreamController::add}(:result))
+          if(:controller.{asy::_AsyncStarStreamController::add}(_in::unsafeCast<core::String*>(:result)))
             return null;
           else
             [yield] null;
@@ -146,7 +147,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   dynamic :saved_try_context_var0;
   dynamic :saved_try_context_var1;
@@ -181,7 +182,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   dynamic :saved_try_context_var0;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
@@ -189,7 +190,7 @@
       #L5:
       {
         [yield] let dynamic #t2 = asy::_awaitHelper(self::asyncString(), :async_op_then, :async_op_error, :async_op) in null;
-        core::String* str = :result;
+        core::String* str = _in::unsafeCast<core::String*>(:result);
       }
       asy::_completeOnAsyncReturn(:async_completer, :return_value);
       return;
diff --git a/pkg/front_end/testcases/general/async_nested.dart.strong.transformed.expect b/pkg/front_end/testcases/general/async_nested.dart.strong.transformed.expect
index 256ef3f..27b7653 100644
--- a/pkg/front_end/testcases/general/async_nested.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/async_nested.dart.strong.transformed.expect
@@ -2,6 +2,7 @@
 import self as self;
 import "dart:core" as core;
 import "dart:async" as asy;
+import "dart:_internal" as _in;
 
 import "dart:async";
 
@@ -23,12 +24,12 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   dynamic :saved_try_context_var0;
-  dynamic :async_temporary_0;
-  dynamic :async_temporary_1;
-  dynamic :async_temporary_2;
+  self::Node* :async_temporary_0;
+  self::Node* :async_temporary_1;
+  self::Node* :async_temporary_2;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
     try {
       #L1:
@@ -36,16 +37,16 @@
         core::String* expected = "1 2 3 4 5 6 7 8 9 10";
         :async_temporary_2 = new self::Node::•("2", <self::Node*>[]);
         [yield] let dynamic #t4 = asy::_awaitHelper(asy::Future::value<self::Node*>(new self::Node::•("7", <self::Node*>[])), :async_op_then, :async_op_error, :async_op) in null;
-        [yield] let dynamic #t5 = asy::_awaitHelper(asy::Future::value<self::Node*>(new self::Node::•("6", <self::Node*>[:result])), :async_op_then, :async_op_error, :async_op) in null;
-        :async_temporary_1 = :result;
+        [yield] let dynamic #t5 = asy::_awaitHelper(asy::Future::value<self::Node*>(new self::Node::•("6", <self::Node*>[_in::unsafeCast<self::Node*>(:result)])), :async_op_then, :async_op_error, :async_op) in null;
+        :async_temporary_1 = _in::unsafeCast<self::Node*>(:result);
         [yield] let dynamic #t6 = asy::_awaitHelper(asy::Future::value<self::Node*>(new self::Node::•("8", <self::Node*>[])), :async_op_then, :async_op_error, :async_op) in null;
-        :async_temporary_0 = :result;
+        :async_temporary_0 = _in::unsafeCast<self::Node*>(:result);
         [yield] let dynamic #t7 = asy::_awaitHelper(asy::Future::value<self::Node*>(new self::Node::•("9", <self::Node*>[])), :async_op_then, :async_op_error, :async_op) in null;
-        [yield] let dynamic #t8 = asy::_awaitHelper(asy::Future::value<self::Node*>(new self::Node::•("4", <self::Node*>[new self::Node::•("5", <self::Node*>[:async_temporary_1, :async_temporary_0, :result])])), :async_op_then, :async_op_error, :async_op) in null;
-        [yield] let dynamic #t9 = asy::_awaitHelper(asy::Future::value<self::Node*>(new self::Node::•("3", <self::Node*>[:result])), :async_op_then, :async_op_error, :async_op) in null;
-        :async_temporary_0 = :result;
+        [yield] let dynamic #t8 = asy::_awaitHelper(asy::Future::value<self::Node*>(new self::Node::•("4", <self::Node*>[new self::Node::•("5", <self::Node*>[:async_temporary_1, :async_temporary_0, _in::unsafeCast<self::Node*>(:result)])])), :async_op_then, :async_op_error, :async_op) in null;
+        [yield] let dynamic #t9 = asy::_awaitHelper(asy::Future::value<self::Node*>(new self::Node::•("3", <self::Node*>[_in::unsafeCast<self::Node*>(:result)])), :async_op_then, :async_op_error, :async_op) in null;
+        :async_temporary_0 = _in::unsafeCast<self::Node*>(:result);
         [yield] let dynamic #t10 = asy::_awaitHelper(asy::Future::value<self::Node*>(new self::Node::•("10", <self::Node*>[])), :async_op_then, :async_op_error, :async_op) in null;
-        self::Node* node = new self::Node::•("1", <self::Node*>[:async_temporary_2, :async_temporary_0, :result]);
+        self::Node* node = new self::Node::•("1", <self::Node*>[:async_temporary_2, :async_temporary_0, _in::unsafeCast<self::Node*>(:result)]);
         core::String* actual = node.{self::Node::toSimpleString}() as{TypeError} core::String*;
         core::print(actual);
         if(!actual.{core::String::==}(expected)) {
diff --git a/pkg/front_end/testcases/general/await.dart.strong.transformed.expect b/pkg/front_end/testcases/general/await.dart.strong.transformed.expect
index 1e0da3e..a4fa440 100644
--- a/pkg/front_end/testcases/general/await.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/await.dart.strong.transformed.expect
@@ -2,6 +2,7 @@
 import self as self;
 import "dart:async" as asy;
 import "dart:core" as core;
+import "dart:_internal" as _in;
 
 static method main() → dynamic /* originally async */ {
   final asy::_AsyncAwaitCompleter<dynamic>* :async_completer = new asy::_AsyncAwaitCompleter::•<dynamic>();
@@ -9,7 +10,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   dynamic :saved_try_context_var0;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
@@ -17,7 +18,7 @@
       #L1:
       {
         [yield] let dynamic #t1 = asy::_awaitHelper("Hello, World!", :async_op_then, :async_op_error, :async_op) in null;
-        core::print(:result);
+        core::print(_in::unsafeCast<core::String*>(:result));
       }
       asy::_completeOnAsyncReturn(:async_completer, :return_value);
       return;
diff --git a/pkg/front_end/testcases/general/await_complex.dart b/pkg/front_end/testcases/general/await_complex.dart
new file mode 100644
index 0000000..4cae35f
--- /dev/null
+++ b/pkg/front_end/testcases/general/await_complex.dart
@@ -0,0 +1,256 @@
+// Copyright (c) 2014, 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.
+
+// This test was adapted from language_2/await_test
+
+import 'dart:async';
+
+int globalVariable = 1;
+int topLevelFoo(int param) => 1;
+int get topLevelGetter => globalVariable;
+void set topLevelSetter(val) {
+  globalVariable = val;
+}
+
+class C {
+  static int staticField = 1;
+  static int get staticGetter => staticField;
+  static void set staticSetter(val) {
+    staticField = val;
+  }
+
+  static int staticFoo(int param) => param;
+
+  int field = 1;
+  int get getter => field;
+  void set setter(val) {
+    field = val;
+  }
+
+  int foo(int param) => param;
+}
+
+dummy() => 1;
+
+staticMembers() async {
+  var a = C.staticField + await dummy();
+  expect(2, a);
+  var f = (C.staticField = 1) + await dummy();
+  expect(2, f);
+  var b = C.staticGetter + await dummy();
+  expect(2, b);
+  var c = (C.staticSetter = 1) + await dummy();
+  expect(2, c);
+  var d = C.staticFoo(2) + await dummy();
+  expect(3, d);
+  var e = C.staticField +
+      C.staticGetter +
+      (C.staticSetter = 1) +
+      C.staticFoo(1) +
+      await dummy();
+  expect(5, e);
+}
+
+topLevelMembers() async {
+  var a = globalVariable + await dummy();
+  expect(2, a);
+  var b = topLevelGetter + await dummy();
+  expect(2, b);
+  var c = (topLevelSetter = 1) + await dummy();
+  expect(2, c);
+  var d = topLevelFoo(1) + await dummy();
+  expect(2, d);
+  var e = globalVariable +
+      topLevelGetter +
+      (topLevelSetter = 1) +
+      topLevelFoo(1) +
+      await dummy();
+  expect(5, e);
+}
+
+instanceMembers() async {
+  var inst = new C();
+  var a = inst.field + await dummy();
+  expect(2, a);
+  var b = inst.getter + await dummy();
+  expect(2, b);
+  var c = (inst.setter = 1) + await dummy();
+  expect(2, c);
+  var d = inst.foo(1) + await dummy();
+  expect(2, d);
+  var e = inst.field +
+      inst.getter +
+      (inst.setter = 1) +
+      inst.foo(1) +
+      await dummy();
+  expect(5, e);
+}
+
+others() async {
+  var a = "${globalVariable} ${await dummy()} " + await "someString";
+  expect("1 1 someString", a);
+  var c = new C();
+  var d = c.field + await dummy();
+  var cnt = 2;
+  var b = [1, 2, 3];
+  b[cnt] = await dummy();
+  expect(1, b[cnt]);
+  var e = b[0] + await dummy();
+  expect(2, e);
+}
+
+conditionals() async {
+  var a = false;
+  var b = true;
+  var c = (a || b) || await dummy();
+  expect(true, c);
+  var d = (a || b) ? a : await dummy();
+  expect(false, d);
+  var e = (a is int) ? await dummy() : 2;
+  expect(2, e);
+  try {
+    var f = (a is int) ? await dummy() : 2;
+  } catch (e) {}
+}
+
+asserts() async {
+  for (final FutureOr<T> Function<T>(T) func in <Function>[id, future]) {
+    assert(await func(true));
+    assert(id(true), await func("message"));
+    assert(await func(true), await (func("message")));
+    try {
+      assert(await func(false), await (func("message")));
+      if (assertStatementsEnabled) throw "Didn't throw";
+    } on AssertionError catch (e) {
+      expect("message", e.message);
+    }
+  }
+}
+
+controlFlow() async {
+  for (final FutureOr<T> Function<T>(T) func in <Function>[id, future]) {
+    // For.
+    var c = 0;
+    for (var i = await (func(0)); await func(i < 5); await func(i++)) {
+      c++;
+    }
+    expect(5, c);
+    // While.
+    c = 0;
+    while (await func(c < 5)) c++;
+    expect(5, c);
+    // Do-while.
+    c = 0;
+    do {
+      c++;
+    } while (await func(c < 5));
+    expect(5, c);
+    // If.
+    if (await func(c == 5)) {
+      expect(5, c);
+    } else {
+      throw "unreachable";
+    }
+    // Throw.
+    try {
+      throw await func("string");
+    } on String {
+      // OK.
+    }
+
+    try {
+      await (throw "string");
+    } on String {
+      // OK.
+    }
+    // Try/catch/finally
+    try {
+      try {
+        throw "string";
+      } catch (e) {
+        expect("string", e);
+        expect(0, await func(0));
+        rethrow;
+      } finally {
+        expect(0, await func(0));
+      }
+    } catch (e) {
+      expect(0, await func(0));
+      expect("string", e);
+    } finally {
+      expect(0, await func(0));
+    }
+    // Switch
+    switch (await func(2)) {
+      case 2:
+        break;
+      default:
+        throw "unreachable";
+    }
+    // Return.
+    expect(
+        42,
+        await () async {
+          return await func(42);
+        }());
+    expect(
+        42,
+        await () async {
+          return func(42);
+        }());
+    // Yield.
+    Stream<int> testStream1() async* {
+      yield await func(42);
+    }
+
+    expectList([42], await testStream1().toList());
+    // Yield*
+    Stream<int> testStream2() async* {
+      yield* await func(intStream());
+    }
+
+    expectList([42], await testStream2().toList());
+  }
+}
+
+FutureOr<T> future<T>(T value) async => value;
+FutureOr<T> id<T>(T value) => value;
+
+Stream<int> intStream() async* {
+  yield 42;
+}
+
+final bool assertStatementsEnabled = () {
+  try {
+    assert(false);
+    return false;
+  } catch (_) {
+    return true;
+  }
+}();
+
+main() async {
+  for (int i = 0; i < 11; i++) {
+    await staticMembers();
+    await topLevelMembers();
+    await instanceMembers();
+    await conditionals();
+    await others();
+    await asserts();
+    await controlFlow();
+  }
+}
+
+expect(expected, actual) {
+  if (expected != actual) throw 'Expected $expected, actual $actual';
+}
+
+expectList(List expected, List actual) {
+  if (expected.length != actual.length) {
+    throw 'Expected $expected, actual $actual';
+  }
+  for (int i = 0; i < expected.length; i++) {
+    expect(expected[i], actual[i]);
+  }
+}
diff --git a/pkg/front_end/testcases/general/await_complex.dart.outline.expect b/pkg/front_end/testcases/general/await_complex.dart.outline.expect
new file mode 100644
index 0000000..7d5cecc
--- /dev/null
+++ b/pkg/front_end/testcases/general/await_complex.dart.outline.expect
@@ -0,0 +1,61 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "dart:async" as asy;
+
+import "dart:async";
+
+class C extends core::Object {
+  static field core::int* staticField;
+  field core::int* field;
+  synthetic constructor •() → self::C*
+    ;
+  static get staticGetter() → core::int*
+    ;
+  static set staticSetter(dynamic val) → void
+    ;
+  static method staticFoo(core::int* param) → core::int*
+    ;
+  get getter() → core::int*
+    ;
+  set setter(dynamic val) → void
+    ;
+  method foo(core::int* param) → core::int*
+    ;
+}
+static field core::int* globalVariable;
+static final field core::bool* assertStatementsEnabled;
+static method topLevelFoo(core::int* param) → core::int*
+  ;
+static get topLevelGetter() → core::int*
+  ;
+static set topLevelSetter(dynamic val) → void
+  ;
+static method dummy() → dynamic
+  ;
+static method staticMembers() → dynamic
+  ;
+static method topLevelMembers() → dynamic
+  ;
+static method instanceMembers() → dynamic
+  ;
+static method others() → dynamic
+  ;
+static method conditionals() → dynamic
+  ;
+static method asserts() → dynamic
+  ;
+static method controlFlow() → dynamic
+  ;
+static method future<T extends core::Object* = dynamic>(self::future::T* value) → asy::FutureOr<self::future::T*>*
+  ;
+static method id<T extends core::Object* = dynamic>(self::id::T* value) → asy::FutureOr<self::id::T*>*
+  ;
+static method intStream() → asy::Stream<core::int*>*
+  ;
+static method main() → dynamic
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
+static method expectList(core::List<dynamic>* expected, core::List<dynamic>* actual) → dynamic
+  ;
diff --git a/pkg/front_end/testcases/general/await_complex.dart.strong.expect b/pkg/front_end/testcases/general/await_complex.dart.strong.expect
new file mode 100644
index 0000000..9cf401a
--- /dev/null
+++ b/pkg/front_end/testcases/general/await_complex.dart.strong.expect
@@ -0,0 +1,250 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "dart:async" as asy;
+
+import "dart:async";
+
+class C extends core::Object {
+  static field core::int* staticField = 1;
+  field core::int* field = 1;
+  synthetic constructor •() → self::C*
+    : super core::Object::•()
+    ;
+  static get staticGetter() → core::int*
+    return self::C::staticField;
+  static set staticSetter(dynamic val) → void {
+    self::C::staticField = val as{TypeError} core::int*;
+  }
+  static method staticFoo(core::int* param) → core::int*
+    return param;
+  get getter() → core::int*
+    return this.{self::C::field};
+  set setter(dynamic val) → void {
+    this.{self::C::field} = val as{TypeError} core::int*;
+  }
+  method foo(core::int* param) → core::int*
+    return param;
+}
+static field core::int* globalVariable = 1;
+static final field core::bool* assertStatementsEnabled = (() → core::bool* {
+  try {
+    assert(false);
+    return false;
+  }
+  on dynamic catch(final dynamic _) {
+    return true;
+  }
+}).call();
+static method topLevelFoo(core::int* param) → core::int*
+  return 1;
+static get topLevelGetter() → core::int*
+  return self::globalVariable;
+static set topLevelSetter(dynamic val) → void {
+  self::globalVariable = val as{TypeError} core::int*;
+}
+static method dummy() → dynamic
+  return 1;
+static method staticMembers() → dynamic async {
+  core::num* a = self::C::staticField.{core::num::+}(await self::dummy() as{TypeError} core::num*);
+  self::expect(2, a);
+  core::num* f = (self::C::staticField = 1).{core::num::+}(await self::dummy() as{TypeError} core::num*);
+  self::expect(2, f);
+  core::num* b = self::C::staticGetter.{core::num::+}(await self::dummy() as{TypeError} core::num*);
+  self::expect(2, b);
+  core::num* c = (self::C::staticSetter = 1).{core::num::+}(await self::dummy() as{TypeError} core::num*);
+  self::expect(2, c);
+  core::num* d = self::C::staticFoo(2).{core::num::+}(await self::dummy() as{TypeError} core::num*);
+  self::expect(3, d);
+  core::num* e = self::C::staticField.{core::num::+}(self::C::staticGetter).{core::num::+}(self::C::staticSetter = 1).{core::num::+}(self::C::staticFoo(1)).{core::num::+}(await self::dummy() as{TypeError} core::num*);
+  self::expect(5, e);
+}
+static method topLevelMembers() → dynamic async {
+  core::num* a = self::globalVariable.{core::num::+}(await self::dummy() as{TypeError} core::num*);
+  self::expect(2, a);
+  core::num* b = self::topLevelGetter.{core::num::+}(await self::dummy() as{TypeError} core::num*);
+  self::expect(2, b);
+  core::num* c = (self::topLevelSetter = 1).{core::num::+}(await self::dummy() as{TypeError} core::num*);
+  self::expect(2, c);
+  core::num* d = self::topLevelFoo(1).{core::num::+}(await self::dummy() as{TypeError} core::num*);
+  self::expect(2, d);
+  core::num* e = self::globalVariable.{core::num::+}(self::topLevelGetter).{core::num::+}(self::topLevelSetter = 1).{core::num::+}(self::topLevelFoo(1)).{core::num::+}(await self::dummy() as{TypeError} core::num*);
+  self::expect(5, e);
+}
+static method instanceMembers() → dynamic async {
+  self::C* inst = new self::C::•();
+  core::num* a = inst.{self::C::field}.{core::num::+}(await self::dummy() as{TypeError} core::num*);
+  self::expect(2, a);
+  core::num* b = inst.{self::C::getter}.{core::num::+}(await self::dummy() as{TypeError} core::num*);
+  self::expect(2, b);
+  core::num* c = (inst.{self::C::setter} = 1).{core::num::+}(await self::dummy() as{TypeError} core::num*);
+  self::expect(2, c);
+  core::num* d = inst.{self::C::foo}(1).{core::num::+}(await self::dummy() as{TypeError} core::num*);
+  self::expect(2, d);
+  core::num* e = inst.{self::C::field}.{core::num::+}(inst.{self::C::getter}).{core::num::+}(inst.{self::C::setter} = 1).{core::num::+}(inst.{self::C::foo}(1)).{core::num::+}(await self::dummy() as{TypeError} core::num*);
+  self::expect(5, e);
+}
+static method others() → dynamic async {
+  core::String* a = "${self::globalVariable} ${await self::dummy()} ".{core::String::+}(await "someString");
+  self::expect("1 1 someString", a);
+  self::C* c = new self::C::•();
+  core::num* d = c.{self::C::field}.{core::num::+}(await self::dummy() as{TypeError} core::num*);
+  core::int* cnt = 2;
+  core::List<core::int*>* b = <core::int*>[1, 2, 3];
+  b.{core::List::[]=}(cnt, await self::dummy() as{TypeError} core::int*);
+  self::expect(1, b.{core::List::[]}(cnt));
+  core::num* e = b.{core::List::[]}(0).{core::num::+}(await self::dummy() as{TypeError} core::num*);
+  self::expect(2, e);
+}
+static method conditionals() → dynamic async {
+  core::bool* a = false;
+  core::bool* b = true;
+  core::bool* c = a || b || await self::dummy() as{TypeError} core::bool*;
+  self::expect(true, c);
+  dynamic d = a || b ?{dynamic} a : await self::dummy();
+  self::expect(false, d);
+  dynamic e = a is core::int* ?{dynamic} await self::dummy() : 2;
+  self::expect(2, e);
+  try {
+    dynamic f = a is core::int* ?{dynamic} await self::dummy() : 2;
+  }
+  on dynamic catch(final dynamic e) {
+  }
+}
+static method asserts() → dynamic async {
+  for (final core::Function* #t1 in <core::Function*>[#C1, #C2]) {
+    final <T extends core::Object* = dynamic>(T*) →* asy::FutureOr<T*>* func = #t1 as{TypeError} <T extends core::Object* = dynamic>(T*) →* asy::FutureOr<T*>*;
+    assert(await func.call<core::bool*>(true));
+    assert(self::id<core::bool*>(true) as{TypeError} core::bool*, await func.call<core::String*>("message"));
+    assert(await func.call<core::bool*>(true), await func.call<core::String*>("message"));
+    try {
+      assert(await func.call<core::bool*>(false), await func.call<core::String*>("message"));
+      if(self::assertStatementsEnabled)
+        throw "Didn't throw";
+    }
+    on core::AssertionError* catch(final core::AssertionError* e) {
+      self::expect("message", e.{core::AssertionError::message});
+    }
+  }
+}
+static method controlFlow() → dynamic async {
+  for (final core::Function* #t2 in <core::Function*>[#C1, #C2]) {
+    final <T extends core::Object* = dynamic>(T*) →* asy::FutureOr<T*>* func = #t2 as{TypeError} <T extends core::Object* = dynamic>(T*) →* asy::FutureOr<T*>*;
+    core::int* c = 0;
+    for (core::int* i = await func.call<core::int*>(0); await func.call<core::bool*>(i.{core::num::<}(5)); await func.call<core::int*>(let final core::int* #t3 = i in let final core::int* #t4 = i = #t3.{core::num::+}(1) in #t3)) {
+      c = c.{core::num::+}(1);
+    }
+    self::expect(5, c);
+    c = 0;
+    while (await func.call<core::bool*>(c.{core::num::<}(5)))
+      c = c.{core::num::+}(1);
+    self::expect(5, c);
+    c = 0;
+    do {
+      c = c.{core::num::+}(1);
+    }
+    while (await func.call<core::bool*>(c.{core::num::<}(5)))
+    self::expect(5, c);
+    if(await func.call<core::bool*>(c.{core::num::==}(5))) {
+      self::expect(5, c);
+    }
+    else {
+      throw "unreachable";
+    }
+    try {
+      throw await func.call<core::String*>("string");
+    }
+    on core::String* catch(no-exception-var) {
+    }
+    try {
+      await throw "string";
+    }
+    on core::String* catch(no-exception-var) {
+    }
+    try
+      try {
+        try
+          try {
+            throw "string";
+          }
+          on dynamic catch(final dynamic e) {
+            self::expect("string", e);
+            self::expect(0, await func.call<core::int*>(0));
+            rethrow;
+          }
+        finally {
+          self::expect(0, await func.call<core::int*>(0));
+        }
+      }
+      on dynamic catch(final dynamic e) {
+        self::expect(0, await func.call<core::int*>(0));
+        self::expect("string", e);
+      }
+    finally {
+      self::expect(0, await func.call<core::int*>(0));
+    }
+    #L1:
+    switch(await func.call<core::int*>(2)) {
+      #L2:
+      case #C3:
+        {
+          break #L1;
+        }
+      #L3:
+      default:
+        {
+          throw "unreachable";
+        }
+    }
+    self::expect(42, await(() → asy::Future<dynamic>* async {
+      return await func.call<dynamic>(42);
+    }).call());
+    self::expect(42, await(() → asy::Future<dynamic>* async {
+      return func.call<dynamic>(42);
+    }).call());
+    function testStream1() → asy::Stream<core::int*>* async* {
+      yield await func.call<core::int*>(42);
+    }
+    self::expectList(<dynamic>[42], await testStream1.call().{asy::Stream::toList}());
+    function testStream2() → asy::Stream<core::int*>* async* {
+      yield* await func.call<asy::Stream<core::int*>*>(self::intStream());
+    }
+    self::expectList(<dynamic>[42], await testStream2.call().{asy::Stream::toList}());
+  }
+}
+static method future<T extends core::Object* = dynamic>(self::future::T* value) → asy::FutureOr<self::future::T*>* async 
+  return value;
+static method id<T extends core::Object* = dynamic>(self::id::T* value) → asy::FutureOr<self::id::T*>*
+  return value;
+static method intStream() → asy::Stream<core::int*>* async* {
+  yield 42;
+}
+static method main() → dynamic async {
+  for (core::int* i = 0; i.{core::num::<}(11); i = i.{core::num::+}(1)) {
+    await self::staticMembers();
+    await self::topLevelMembers();
+    await self::instanceMembers();
+    await self::conditionals();
+    await self::others();
+    await self::asserts();
+    await self::controlFlow();
+  }
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+static method expectList(core::List<dynamic>* expected, core::List<dynamic>* actual) → dynamic {
+  if(!expected.{core::List::length}.{core::num::==}(actual.{core::List::length})) {
+    throw "Expected ${expected}, actual ${actual}";
+  }
+  for (core::int* i = 0; i.{core::num::<}(expected.{core::List::length}); i = i.{core::num::+}(1)) {
+    self::expect(expected.{core::List::[]}(i), actual.{core::List::[]}(i));
+  }
+}
+
+constants  {
+  #C1 = tearoff self::id
+  #C2 = tearoff self::future
+  #C3 = 2
+}
diff --git a/pkg/front_end/testcases/general/await_complex.dart.strong.transformed.expect b/pkg/front_end/testcases/general/await_complex.dart.strong.transformed.expect
new file mode 100644
index 0000000..afff0fe
--- /dev/null
+++ b/pkg/front_end/testcases/general/await_complex.dart.strong.transformed.expect
@@ -0,0 +1,801 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "dart:async" as asy;
+import "dart:_internal" as _in;
+
+import "dart:async";
+
+class C extends core::Object {
+  static field core::int* staticField = 1;
+  field core::int* field = 1;
+  synthetic constructor •() → self::C*
+    : super core::Object::•()
+    ;
+  static get staticGetter() → core::int*
+    return self::C::staticField;
+  static set staticSetter(dynamic val) → void {
+    self::C::staticField = val as{TypeError} core::int*;
+  }
+  static method staticFoo(core::int* param) → core::int*
+    return param;
+  get getter() → core::int*
+    return this.{self::C::field};
+  set setter(dynamic val) → void {
+    this.{self::C::field} = val as{TypeError} core::int*;
+  }
+  method foo(core::int* param) → core::int*
+    return param;
+}
+static field core::int* globalVariable = 1;
+static final field core::bool* assertStatementsEnabled = (() → core::bool* {
+  try {
+    assert(false);
+    return false;
+  }
+  on dynamic catch(final dynamic _) {
+    return true;
+  }
+}).call();
+static method topLevelFoo(core::int* param) → core::int*
+  return 1;
+static get topLevelGetter() → core::int*
+  return self::globalVariable;
+static set topLevelSetter(dynamic val) → void {
+  self::globalVariable = val as{TypeError} core::int*;
+}
+static method dummy() → dynamic
+  return 1;
+static method staticMembers() → dynamic /* originally async */ {
+  final asy::_AsyncAwaitCompleter<dynamic>* :async_completer = new asy::_AsyncAwaitCompleter::•<dynamic>();
+  asy::FutureOr<dynamic>* :return_value;
+  dynamic :async_stack_trace;
+  dynamic :async_op_then;
+  dynamic :async_op_error;
+  core::int* :await_jump_var = 0;
+  dynamic :await_ctx_var;
+  dynamic :saved_try_context_var0;
+  core::int* :async_temporary_0;
+  core::int* :async_temporary_1;
+  core::int* :async_temporary_2;
+  core::int* :async_temporary_3;
+  core::int* :async_temporary_4;
+  core::int* :async_temporary_5;
+  function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
+    try {
+      #L1:
+      {
+        :async_temporary_0 = self::C::staticField;
+        [yield] let dynamic #t1 = asy::_awaitHelper(self::dummy(), :async_op_then, :async_op_error, :async_op) in null;
+        core::num* a = :async_temporary_0.{core::num::+}(:result as{TypeError} core::num*);
+        self::expect(2, a);
+        :async_temporary_1 = self::C::staticField = 1;
+        [yield] let dynamic #t2 = asy::_awaitHelper(self::dummy(), :async_op_then, :async_op_error, :async_op) in null;
+        core::num* f = :async_temporary_1.{core::num::+}(:result as{TypeError} core::num*);
+        self::expect(2, f);
+        :async_temporary_2 = self::C::staticGetter;
+        [yield] let dynamic #t3 = asy::_awaitHelper(self::dummy(), :async_op_then, :async_op_error, :async_op) in null;
+        core::num* b = :async_temporary_2.{core::num::+}(:result as{TypeError} core::num*);
+        self::expect(2, b);
+        :async_temporary_3 = self::C::staticSetter = 1;
+        [yield] let dynamic #t4 = asy::_awaitHelper(self::dummy(), :async_op_then, :async_op_error, :async_op) in null;
+        core::num* c = :async_temporary_3.{core::num::+}(:result as{TypeError} core::num*);
+        self::expect(2, c);
+        :async_temporary_4 = self::C::staticFoo(2);
+        [yield] let dynamic #t5 = asy::_awaitHelper(self::dummy(), :async_op_then, :async_op_error, :async_op) in null;
+        core::num* d = :async_temporary_4.{core::num::+}(:result as{TypeError} core::num*);
+        self::expect(3, d);
+        :async_temporary_5 = self::C::staticField.{core::num::+}(self::C::staticGetter).{core::num::+}(self::C::staticSetter = 1).{core::num::+}(self::C::staticFoo(1));
+        [yield] let dynamic #t6 = asy::_awaitHelper(self::dummy(), :async_op_then, :async_op_error, :async_op) in null;
+        core::num* e = :async_temporary_5.{core::num::+}(:result as{TypeError} core::num*);
+        self::expect(5, e);
+      }
+      asy::_completeOnAsyncReturn(:async_completer, :return_value);
+      return;
+    }
+    on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+      :async_completer.{asy::Completer::completeError}(:exception, :stack_trace);
+    }
+  :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+  :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+  :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+  :async_completer.start(:async_op);
+  return :async_completer.{asy::Completer::future};
+}
+static method topLevelMembers() → dynamic /* originally async */ {
+  final asy::_AsyncAwaitCompleter<dynamic>* :async_completer = new asy::_AsyncAwaitCompleter::•<dynamic>();
+  asy::FutureOr<dynamic>* :return_value;
+  dynamic :async_stack_trace;
+  dynamic :async_op_then;
+  dynamic :async_op_error;
+  core::int* :await_jump_var = 0;
+  dynamic :await_ctx_var;
+  dynamic :saved_try_context_var0;
+  core::int* :async_temporary_0;
+  core::int* :async_temporary_1;
+  core::int* :async_temporary_2;
+  core::int* :async_temporary_3;
+  core::int* :async_temporary_4;
+  function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
+    try {
+      #L2:
+      {
+        :async_temporary_0 = self::globalVariable;
+        [yield] let dynamic #t7 = asy::_awaitHelper(self::dummy(), :async_op_then, :async_op_error, :async_op) in null;
+        core::num* a = :async_temporary_0.{core::num::+}(:result as{TypeError} core::num*);
+        self::expect(2, a);
+        :async_temporary_1 = self::topLevelGetter;
+        [yield] let dynamic #t8 = asy::_awaitHelper(self::dummy(), :async_op_then, :async_op_error, :async_op) in null;
+        core::num* b = :async_temporary_1.{core::num::+}(:result as{TypeError} core::num*);
+        self::expect(2, b);
+        :async_temporary_2 = self::topLevelSetter = 1;
+        [yield] let dynamic #t9 = asy::_awaitHelper(self::dummy(), :async_op_then, :async_op_error, :async_op) in null;
+        core::num* c = :async_temporary_2.{core::num::+}(:result as{TypeError} core::num*);
+        self::expect(2, c);
+        :async_temporary_3 = self::topLevelFoo(1);
+        [yield] let dynamic #t10 = asy::_awaitHelper(self::dummy(), :async_op_then, :async_op_error, :async_op) in null;
+        core::num* d = :async_temporary_3.{core::num::+}(:result as{TypeError} core::num*);
+        self::expect(2, d);
+        :async_temporary_4 = self::globalVariable.{core::num::+}(self::topLevelGetter).{core::num::+}(self::topLevelSetter = 1).{core::num::+}(self::topLevelFoo(1));
+        [yield] let dynamic #t11 = asy::_awaitHelper(self::dummy(), :async_op_then, :async_op_error, :async_op) in null;
+        core::num* e = :async_temporary_4.{core::num::+}(:result as{TypeError} core::num*);
+        self::expect(5, e);
+      }
+      asy::_completeOnAsyncReturn(:async_completer, :return_value);
+      return;
+    }
+    on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+      :async_completer.{asy::Completer::completeError}(:exception, :stack_trace);
+    }
+  :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+  :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+  :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+  :async_completer.start(:async_op);
+  return :async_completer.{asy::Completer::future};
+}
+static method instanceMembers() → dynamic /* originally async */ {
+  final asy::_AsyncAwaitCompleter<dynamic>* :async_completer = new asy::_AsyncAwaitCompleter::•<dynamic>();
+  asy::FutureOr<dynamic>* :return_value;
+  dynamic :async_stack_trace;
+  dynamic :async_op_then;
+  dynamic :async_op_error;
+  core::int* :await_jump_var = 0;
+  dynamic :await_ctx_var;
+  dynamic :saved_try_context_var0;
+  core::int* :async_temporary_0;
+  core::int* :async_temporary_1;
+  core::int* :async_temporary_2;
+  core::int* :async_temporary_3;
+  core::int* :async_temporary_4;
+  function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
+    try {
+      #L3:
+      {
+        self::C* inst = new self::C::•();
+        :async_temporary_0 = inst.{self::C::field};
+        [yield] let dynamic #t12 = asy::_awaitHelper(self::dummy(), :async_op_then, :async_op_error, :async_op) in null;
+        core::num* a = :async_temporary_0.{core::num::+}(:result as{TypeError} core::num*);
+        self::expect(2, a);
+        :async_temporary_1 = inst.{self::C::getter};
+        [yield] let dynamic #t13 = asy::_awaitHelper(self::dummy(), :async_op_then, :async_op_error, :async_op) in null;
+        core::num* b = :async_temporary_1.{core::num::+}(:result as{TypeError} core::num*);
+        self::expect(2, b);
+        :async_temporary_2 = inst.{self::C::setter} = 1;
+        [yield] let dynamic #t14 = asy::_awaitHelper(self::dummy(), :async_op_then, :async_op_error, :async_op) in null;
+        core::num* c = :async_temporary_2.{core::num::+}(:result as{TypeError} core::num*);
+        self::expect(2, c);
+        :async_temporary_3 = inst.{self::C::foo}(1);
+        [yield] let dynamic #t15 = asy::_awaitHelper(self::dummy(), :async_op_then, :async_op_error, :async_op) in null;
+        core::num* d = :async_temporary_3.{core::num::+}(:result as{TypeError} core::num*);
+        self::expect(2, d);
+        :async_temporary_4 = inst.{self::C::field}.{core::num::+}(inst.{self::C::getter}).{core::num::+}(inst.{self::C::setter} = 1).{core::num::+}(inst.{self::C::foo}(1));
+        [yield] let dynamic #t16 = asy::_awaitHelper(self::dummy(), :async_op_then, :async_op_error, :async_op) in null;
+        core::num* e = :async_temporary_4.{core::num::+}(:result as{TypeError} core::num*);
+        self::expect(5, e);
+      }
+      asy::_completeOnAsyncReturn(:async_completer, :return_value);
+      return;
+    }
+    on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+      :async_completer.{asy::Completer::completeError}(:exception, :stack_trace);
+    }
+  :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+  :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+  :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+  :async_completer.start(:async_op);
+  return :async_completer.{asy::Completer::future};
+}
+static method others() → dynamic /* originally async */ {
+  final asy::_AsyncAwaitCompleter<dynamic>* :async_completer = new asy::_AsyncAwaitCompleter::•<dynamic>();
+  asy::FutureOr<dynamic>* :return_value;
+  dynamic :async_stack_trace;
+  dynamic :async_op_then;
+  dynamic :async_op_error;
+  core::int* :await_jump_var = 0;
+  dynamic :await_ctx_var;
+  dynamic :saved_try_context_var0;
+  core::String* :async_temporary_0;
+  core::int* :async_temporary_1;
+  core::int* :async_temporary_2;
+  core::List<core::int*>* :async_temporary_3;
+  core::int* :async_temporary_4;
+  function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
+    try {
+      #L4:
+      {
+        :async_temporary_0 = self::globalVariable;
+        [yield] let dynamic #t17 = asy::_awaitHelper(self::dummy(), :async_op_then, :async_op_error, :async_op) in null;
+        :async_temporary_0 = "${:async_temporary_0} ${:result} ";
+        [yield] let dynamic #t18 = asy::_awaitHelper("someString", :async_op_then, :async_op_error, :async_op) in null;
+        core::String* a = :async_temporary_0.{core::String::+}(_in::unsafeCast<core::String*>(:result));
+        self::expect("1 1 someString", a);
+        self::C* c = new self::C::•();
+        :async_temporary_1 = c.{self::C::field};
+        [yield] let dynamic #t19 = asy::_awaitHelper(self::dummy(), :async_op_then, :async_op_error, :async_op) in null;
+        core::num* d = :async_temporary_1.{core::num::+}(:result as{TypeError} core::num*);
+        core::int* cnt = 2;
+        core::List<core::int*>* b = <core::int*>[1, 2, 3];
+        :async_temporary_3 = b;
+        :async_temporary_2 = cnt;
+        [yield] let dynamic #t20 = asy::_awaitHelper(self::dummy(), :async_op_then, :async_op_error, :async_op) in null;
+        :async_temporary_3.{core::List::[]=}(:async_temporary_2, :result as{TypeError} core::int*);
+        self::expect(1, b.{core::List::[]}(cnt));
+        :async_temporary_4 = b.{core::List::[]}(0);
+        [yield] let dynamic #t21 = asy::_awaitHelper(self::dummy(), :async_op_then, :async_op_error, :async_op) in null;
+        core::num* e = :async_temporary_4.{core::num::+}(:result as{TypeError} core::num*);
+        self::expect(2, e);
+      }
+      asy::_completeOnAsyncReturn(:async_completer, :return_value);
+      return;
+    }
+    on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+      :async_completer.{asy::Completer::completeError}(:exception, :stack_trace);
+    }
+  :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+  :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+  :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+  :async_completer.start(:async_op);
+  return :async_completer.{asy::Completer::future};
+}
+static method conditionals() → dynamic /* originally async */ {
+  final asy::_AsyncAwaitCompleter<dynamic>* :async_completer = new asy::_AsyncAwaitCompleter::•<dynamic>();
+  asy::FutureOr<dynamic>* :return_value;
+  dynamic :async_stack_trace;
+  dynamic :async_op_then;
+  dynamic :async_op_error;
+  core::int* :await_jump_var = 0;
+  dynamic :await_ctx_var;
+  dynamic :saved_try_context_var0;
+  dynamic :saved_try_context_var1;
+  core::bool* :async_temporary_0;
+  dynamic :async_temporary_1;
+  dynamic :async_temporary_2;
+  dynamic :async_temporary_3;
+  function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
+    try {
+      #L5:
+      {
+        core::bool* a = false;
+        core::bool* b = true;
+        :async_temporary_0 = (a || b).==(true);
+        if(:async_temporary_0)
+          ;
+        else {
+          [yield] let dynamic #t22 = asy::_awaitHelper(self::dummy(), :async_op_then, :async_op_error, :async_op) in null;
+          :async_temporary_0 = (:result as{TypeError} core::bool*).==(true);
+        }
+        core::bool* c = :async_temporary_0;
+        self::expect(true, c);
+        if(a || b) {
+          :async_temporary_1 = a;
+        }
+        else {
+          [yield] let dynamic #t23 = asy::_awaitHelper(self::dummy(), :async_op_then, :async_op_error, :async_op) in null;
+          :async_temporary_1 = :result;
+        }
+        dynamic d = :async_temporary_1;
+        self::expect(false, d);
+        if(a is core::int*) {
+          [yield] let dynamic #t24 = asy::_awaitHelper(self::dummy(), :async_op_then, :async_op_error, :async_op) in null;
+          :async_temporary_2 = :result;
+        }
+        else {
+          :async_temporary_2 = 2;
+        }
+        dynamic e = :async_temporary_2;
+        self::expect(2, e);
+        try {
+          if(a is core::int*) {
+            [yield] let dynamic #t25 = asy::_awaitHelper(self::dummy(), :async_op_then, :async_op_error, :async_op) in null;
+            :async_temporary_3 = :result;
+          }
+          else {
+            :async_temporary_3 = 2;
+          }
+          dynamic f = :async_temporary_3;
+        }
+        on dynamic catch(final dynamic e) {
+        }
+      }
+      asy::_completeOnAsyncReturn(:async_completer, :return_value);
+      return;
+    }
+    on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+      :async_completer.{asy::Completer::completeError}(:exception, :stack_trace);
+    }
+  :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+  :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+  :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+  :async_completer.start(:async_op);
+  return :async_completer.{asy::Completer::future};
+}
+static method asserts() → dynamic /* originally async */ {
+  final asy::_AsyncAwaitCompleter<dynamic>* :async_completer = new asy::_AsyncAwaitCompleter::•<dynamic>();
+  asy::FutureOr<dynamic>* :return_value;
+  dynamic :async_stack_trace;
+  dynamic :async_op_then;
+  dynamic :async_op_error;
+  core::int* :await_jump_var = 0;
+  dynamic :await_ctx_var;
+  dynamic :saved_try_context_var0;
+  dynamic :saved_try_context_var1;
+  function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
+    try {
+      #L6:
+      {
+        for (final core::Function* #t26 in <core::Function*>[#C1, #C2]) {
+          final <T extends core::Object* = dynamic>(T*) →* asy::FutureOr<T*>* func = #t26 as{TypeError} <T extends core::Object* = dynamic>(T*) →* asy::FutureOr<T*>*;
+          assert {
+            [yield] let dynamic #t27 = asy::_awaitHelper(func.call<core::bool*>(true), :async_op_then, :async_op_error, :async_op) in null;
+            assert(_in::unsafeCast<core::bool*>(:result));
+          }
+          assert {
+            if(self::id<core::bool*>(true) as{TypeError} core::bool*)
+              ;
+            else {
+              [yield] let dynamic #t28 = asy::_awaitHelper(func.call<core::String*>("message"), :async_op_then, :async_op_error, :async_op) in null;
+              assert(false, _in::unsafeCast<core::String*>(:result));
+            }
+          }
+          assert {
+            [yield] let dynamic #t29 = asy::_awaitHelper(func.call<core::bool*>(true), :async_op_then, :async_op_error, :async_op) in null;
+            if(_in::unsafeCast<core::bool*>(:result))
+              ;
+            else {
+              [yield] let dynamic #t30 = asy::_awaitHelper(func.call<core::String*>("message"), :async_op_then, :async_op_error, :async_op) in null;
+              assert(false, _in::unsafeCast<core::String*>(:result));
+            }
+          }
+          try {
+            assert {
+              [yield] let dynamic #t31 = asy::_awaitHelper(func.call<core::bool*>(false), :async_op_then, :async_op_error, :async_op) in null;
+              if(_in::unsafeCast<core::bool*>(:result))
+                ;
+              else {
+                [yield] let dynamic #t32 = asy::_awaitHelper(func.call<core::String*>("message"), :async_op_then, :async_op_error, :async_op) in null;
+                assert(false, _in::unsafeCast<core::String*>(:result));
+              }
+            }
+            if(self::assertStatementsEnabled)
+              throw "Didn't throw";
+          }
+          on core::AssertionError* catch(final core::AssertionError* e) {
+            self::expect("message", e.{core::AssertionError::message});
+          }
+        }
+      }
+      asy::_completeOnAsyncReturn(:async_completer, :return_value);
+      return;
+    }
+    on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+      :async_completer.{asy::Completer::completeError}(:exception, :stack_trace);
+    }
+  :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+  :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+  :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+  :async_completer.start(:async_op);
+  return :async_completer.{asy::Completer::future};
+}
+static method controlFlow() → dynamic /* originally async */ {
+  final asy::_AsyncAwaitCompleter<dynamic>* :async_completer = new asy::_AsyncAwaitCompleter::•<dynamic>();
+  asy::FutureOr<dynamic>* :return_value;
+  dynamic :async_stack_trace;
+  dynamic :async_op_then;
+  dynamic :async_op_error;
+  core::int* :await_jump_var = 0;
+  dynamic :await_ctx_var;
+  dynamic :saved_try_context_var0;
+  dynamic :saved_try_context_var1;
+  dynamic :saved_try_context_var2;
+  dynamic :saved_try_context_var3;
+  dynamic :exception0;
+  dynamic :stack_trace0;
+  core::List<dynamic>* :async_temporary_0;
+  core::List<dynamic>* :async_temporary_1;
+  function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
+    try {
+      #L7:
+      {
+        for (final core::Function* #t33 in <core::Function*>[#C1, #C2]) {
+          final <T extends core::Object* = dynamic>(T*) →* asy::FutureOr<T*>* func = #t33 as{TypeError} <T extends core::Object* = dynamic>(T*) →* asy::FutureOr<T*>*;
+          core::int* c = 0;
+          {
+            dynamic #t34 = true;
+            core::int* #t35;
+            #L8:
+            while (true) {
+              core::int* i;
+              if(#t34) {
+                #t34 = false;
+                [yield] let dynamic #t36 = asy::_awaitHelper(func.call<core::int*>(0), :async_op_then, :async_op_error, :async_op) in null;
+                i = _in::unsafeCast<core::int*>(:result);
+              }
+              else {
+                i = #t35;
+                [yield] let dynamic #t37 = asy::_awaitHelper(func.call<core::int*>(let final core::int* #t38 = i in let final core::int* #t39 = i = #t38.{core::num::+}(1) in #t38), :async_op_then, :async_op_error, :async_op) in null;
+                _in::unsafeCast<core::int*>(:result);
+              }
+              [yield] let dynamic #t40 = asy::_awaitHelper(func.call<core::bool*>(i.{core::num::<}(5)), :async_op_then, :async_op_error, :async_op) in null;
+              if(_in::unsafeCast<core::bool*>(:result)) {
+                {
+                  c = c.{core::num::+}(1);
+                }
+                #t35 = i;
+              }
+              else
+                break #L8;
+            }
+          }
+          self::expect(5, c);
+          c = 0;
+          #L9:
+          while (true) {
+            [yield] let dynamic #t41 = asy::_awaitHelper(func.call<core::bool*>(c.{core::num::<}(5)), :async_op_then, :async_op_error, :async_op) in null;
+            if(_in::unsafeCast<core::bool*>(:result))
+              c = c.{core::num::+}(1);
+            else
+              break #L9;
+          }
+          self::expect(5, c);
+          c = 0;
+          do {
+            c = c.{core::num::+}(1);
+            [yield] let dynamic #t42 = asy::_awaitHelper(func.call<core::bool*>(c.{core::num::<}(5)), :async_op_then, :async_op_error, :async_op) in null;
+          }
+          while (_in::unsafeCast<core::bool*>(:result))
+          self::expect(5, c);
+          [yield] let dynamic #t43 = asy::_awaitHelper(func.call<core::bool*>(c.{core::num::==}(5)), :async_op_then, :async_op_error, :async_op) in null;
+          if(_in::unsafeCast<core::bool*>(:result)) {
+            self::expect(5, c);
+          }
+          else {
+            throw "unreachable";
+          }
+          try {
+            [yield] let dynamic #t44 = asy::_awaitHelper(func.call<core::String*>("string"), :async_op_then, :async_op_error, :async_op) in null;
+            throw _in::unsafeCast<core::String*>(:result);
+          }
+          on core::String* catch(no-exception-var) {
+          }
+          try {
+            [yield] let dynamic #t45 = asy::_awaitHelper(throw "string", :async_op_then, :async_op_error, :async_op) in null;
+            _in::unsafeCast<<BottomType>>(:result);
+          }
+          on core::String* catch(no-exception-var) {
+          }
+          try
+            try {
+              try
+                try {
+                  throw "string";
+                }
+                on dynamic catch(final dynamic e) {
+                  self::expect("string", e);
+                  [yield] let dynamic #t46 = asy::_awaitHelper(func.call<core::int*>(0), :async_op_then, :async_op_error, :async_op) in null;
+                  self::expect(0, _in::unsafeCast<core::int*>(:result));
+                  rethrow;
+                }
+              finally {
+                [yield] let dynamic #t47 = asy::_awaitHelper(func.call<core::int*>(0), :async_op_then, :async_op_error, :async_op) in null;
+                self::expect(0, _in::unsafeCast<core::int*>(:result));
+              }
+            }
+            on dynamic catch(final dynamic e) {
+              [yield] let dynamic #t48 = asy::_awaitHelper(func.call<core::int*>(0), :async_op_then, :async_op_error, :async_op) in null;
+              self::expect(0, _in::unsafeCast<core::int*>(:result));
+              self::expect("string", e);
+            }
+          finally {
+            [yield] let dynamic #t49 = asy::_awaitHelper(func.call<core::int*>(0), :async_op_then, :async_op_error, :async_op) in null;
+            self::expect(0, _in::unsafeCast<core::int*>(:result));
+          }
+          #L10:
+          {
+            [yield] let dynamic #t50 = asy::_awaitHelper(func.call<core::int*>(2), :async_op_then, :async_op_error, :async_op) in null;
+            switch(_in::unsafeCast<core::int*>(:result)) {
+              #L11:
+              case #C3:
+                {
+                  break #L10;
+                }
+              #L12:
+              default:
+                {
+                  throw "unreachable";
+                }
+            }
+          }
+          [yield] let dynamic #t51 = asy::_awaitHelper((() → asy::Future<dynamic>* /* originally async */ {
+            final asy::_AsyncAwaitCompleter<dynamic>* :async_completer = new asy::_AsyncAwaitCompleter::•<dynamic>();
+            asy::FutureOr<dynamic>* :return_value;
+            dynamic :async_stack_trace;
+            dynamic :async_op_then;
+            dynamic :async_op_error;
+            core::int* :await_jump_var = 0;
+            dynamic :await_ctx_var;
+            dynamic :saved_try_context_var0;
+            function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
+              try {
+                #L13:
+                {
+                  [yield] let dynamic #t52 = asy::_awaitHelper(func.call<dynamic>(42), :async_op_then, :async_op_error, :async_op) in null;
+                  :return_value = :result;
+                  break #L13;
+                }
+                asy::_completeOnAsyncReturn(:async_completer, :return_value);
+                return;
+              }
+              on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+                :async_completer.{asy::Completer::completeError}(:exception, :stack_trace);
+              }
+            :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+            :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+            :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+            :async_completer.start(:async_op);
+            return :async_completer.{asy::Completer::future};
+          }).call(), :async_op_then, :async_op_error, :async_op) in null;
+          self::expect(42, :result);
+          [yield] let dynamic #t53 = asy::_awaitHelper((() → asy::Future<dynamic>* /* originally async */ {
+            final asy::_AsyncAwaitCompleter<dynamic>* :async_completer = new asy::_AsyncAwaitCompleter::•<dynamic>();
+            asy::FutureOr<dynamic>* :return_value;
+            dynamic :async_stack_trace;
+            dynamic :async_op_then;
+            dynamic :async_op_error;
+            core::int* :await_jump_var = 0;
+            dynamic :await_ctx_var;
+            function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
+              try {
+                #L14:
+                {
+                  :return_value = func.call<dynamic>(42);
+                  break #L14;
+                }
+                asy::_completeOnAsyncReturn(:async_completer, :return_value);
+                return;
+              }
+              on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+                :async_completer.{asy::Completer::completeError}(:exception, :stack_trace);
+              }
+            :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+            :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+            :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+            :async_completer.start(:async_op);
+            return :async_completer.{asy::Completer::future};
+          }).call(), :async_op_then, :async_op_error, :async_op) in null;
+          self::expect(42, :result);
+          function testStream1() → asy::Stream<core::int*>* /* originally async* */ {
+            asy::_AsyncStarStreamController<core::int*>* :controller;
+            dynamic :controller_stream;
+            dynamic :async_stack_trace;
+            dynamic :async_op_then;
+            dynamic :async_op_error;
+            core::int* :await_jump_var = 0;
+            dynamic :await_ctx_var;
+            dynamic :saved_try_context_var0;
+            dynamic :saved_try_context_var1;
+            function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
+              try
+                try {
+                  #L15:
+                  {
+                    [yield] let dynamic #t54 = asy::_awaitHelper(func.call<core::int*>(42), :async_op_then, :async_op_error, :async_op) in null;
+                    if(:controller.{asy::_AsyncStarStreamController::add}(_in::unsafeCast<core::int*>(:result)))
+                      return null;
+                    else
+                      [yield] null;
+                  }
+                  return;
+                }
+                on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+                  :controller.{asy::_AsyncStarStreamController::addError}(:exception, :stack_trace);
+                }
+              finally {
+                :controller.{asy::_AsyncStarStreamController::close}();
+              }
+            :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+            :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+            :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+            :controller = new asy::_AsyncStarStreamController::•<core::int*>(:async_op);
+            :controller_stream = :controller.{asy::_AsyncStarStreamController::stream};
+            return :controller_stream;
+          }
+          :async_temporary_0 = <dynamic>[42];
+          [yield] let dynamic #t55 = asy::_awaitHelper(testStream1.call().{asy::Stream::toList}(), :async_op_then, :async_op_error, :async_op) in null;
+          self::expectList(:async_temporary_0, _in::unsafeCast<core::List<core::int*>*>(:result));
+          function testStream2() → asy::Stream<core::int*>* /* originally async* */ {
+            asy::_AsyncStarStreamController<core::int*>* :controller;
+            dynamic :controller_stream;
+            dynamic :async_stack_trace;
+            dynamic :async_op_then;
+            dynamic :async_op_error;
+            core::int* :await_jump_var = 0;
+            dynamic :await_ctx_var;
+            dynamic :saved_try_context_var0;
+            dynamic :saved_try_context_var1;
+            function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
+              try
+                try {
+                  #L16:
+                  {
+                    [yield] let dynamic #t56 = asy::_awaitHelper(func.call<asy::Stream<core::int*>*>(self::intStream()), :async_op_then, :async_op_error, :async_op) in null;
+                    if(:controller.{asy::_AsyncStarStreamController::addStream}(_in::unsafeCast<asy::Stream<core::int*>*>(:result)))
+                      return null;
+                    else
+                      [yield] null;
+                  }
+                  return;
+                }
+                on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+                  :controller.{asy::_AsyncStarStreamController::addError}(:exception, :stack_trace);
+                }
+              finally {
+                :controller.{asy::_AsyncStarStreamController::close}();
+              }
+            :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+            :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+            :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+            :controller = new asy::_AsyncStarStreamController::•<core::int*>(:async_op);
+            :controller_stream = :controller.{asy::_AsyncStarStreamController::stream};
+            return :controller_stream;
+          }
+          :async_temporary_1 = <dynamic>[42];
+          [yield] let dynamic #t57 = asy::_awaitHelper(testStream2.call().{asy::Stream::toList}(), :async_op_then, :async_op_error, :async_op) in null;
+          self::expectList(:async_temporary_1, _in::unsafeCast<core::List<core::int*>*>(:result));
+        }
+      }
+      asy::_completeOnAsyncReturn(:async_completer, :return_value);
+      return;
+    }
+    on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+      :async_completer.{asy::Completer::completeError}(:exception, :stack_trace);
+    }
+  :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+  :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+  :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+  :async_completer.start(:async_op);
+  return :async_completer.{asy::Completer::future};
+}
+static method future<T extends core::Object* = dynamic>(self::future::T* value) → asy::FutureOr<self::future::T*>* /* originally async */ {
+  final asy::_AsyncAwaitCompleter<self::future::T*>* :async_completer = new asy::_AsyncAwaitCompleter::•<self::future::T*>();
+  asy::FutureOr<self::future::T*>* :return_value;
+  dynamic :async_stack_trace;
+  dynamic :async_op_then;
+  dynamic :async_op_error;
+  core::int* :await_jump_var = 0;
+  dynamic :await_ctx_var;
+  function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
+    try {
+      #L17:
+      {
+        :return_value = value;
+        break #L17;
+      }
+      asy::_completeOnAsyncReturn(:async_completer, :return_value);
+      return;
+    }
+    on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+      :async_completer.{asy::Completer::completeError}(:exception, :stack_trace);
+    }
+  :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+  :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+  :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+  :async_completer.start(:async_op);
+  return :async_completer.{asy::Completer::future};
+}
+static method id<T extends core::Object* = dynamic>(self::id::T* value) → asy::FutureOr<self::id::T*>*
+  return value;
+static method intStream() → asy::Stream<core::int*>* /* originally async* */ {
+  asy::_AsyncStarStreamController<core::int*>* :controller;
+  dynamic :controller_stream;
+  dynamic :async_stack_trace;
+  dynamic :async_op_then;
+  dynamic :async_op_error;
+  core::int* :await_jump_var = 0;
+  dynamic :await_ctx_var;
+  dynamic :saved_try_context_var0;
+  dynamic :saved_try_context_var1;
+  function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
+    try
+      try {
+        #L18:
+        {
+          if(:controller.{asy::_AsyncStarStreamController::add}(42))
+            return null;
+          else
+            [yield] null;
+        }
+        return;
+      }
+      on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+        :controller.{asy::_AsyncStarStreamController::addError}(:exception, :stack_trace);
+      }
+    finally {
+      :controller.{asy::_AsyncStarStreamController::close}();
+    }
+  :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+  :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+  :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+  :controller = new asy::_AsyncStarStreamController::•<core::int*>(:async_op);
+  :controller_stream = :controller.{asy::_AsyncStarStreamController::stream};
+  return :controller_stream;
+}
+static method main() → dynamic /* originally async */ {
+  final asy::_AsyncAwaitCompleter<dynamic>* :async_completer = new asy::_AsyncAwaitCompleter::•<dynamic>();
+  asy::FutureOr<dynamic>* :return_value;
+  dynamic :async_stack_trace;
+  dynamic :async_op_then;
+  dynamic :async_op_error;
+  core::int* :await_jump_var = 0;
+  dynamic :await_ctx_var;
+  dynamic :saved_try_context_var0;
+  function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
+    try {
+      #L19:
+      {
+        for (core::int* i = 0; i.{core::num::<}(11); i = i.{core::num::+}(1)) {
+          [yield] let dynamic #t58 = asy::_awaitHelper(self::staticMembers(), :async_op_then, :async_op_error, :async_op) in null;
+          :result;
+          [yield] let dynamic #t59 = asy::_awaitHelper(self::topLevelMembers(), :async_op_then, :async_op_error, :async_op) in null;
+          :result;
+          [yield] let dynamic #t60 = asy::_awaitHelper(self::instanceMembers(), :async_op_then, :async_op_error, :async_op) in null;
+          :result;
+          [yield] let dynamic #t61 = asy::_awaitHelper(self::conditionals(), :async_op_then, :async_op_error, :async_op) in null;
+          :result;
+          [yield] let dynamic #t62 = asy::_awaitHelper(self::others(), :async_op_then, :async_op_error, :async_op) in null;
+          :result;
+          [yield] let dynamic #t63 = asy::_awaitHelper(self::asserts(), :async_op_then, :async_op_error, :async_op) in null;
+          :result;
+          [yield] let dynamic #t64 = asy::_awaitHelper(self::controlFlow(), :async_op_then, :async_op_error, :async_op) in null;
+          :result;
+        }
+      }
+      asy::_completeOnAsyncReturn(:async_completer, :return_value);
+      return;
+    }
+    on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+      :async_completer.{asy::Completer::completeError}(:exception, :stack_trace);
+    }
+  :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+  :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+  :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+  :async_completer.start(:async_op);
+  return :async_completer.{asy::Completer::future};
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+static method expectList(core::List<dynamic>* expected, core::List<dynamic>* actual) → dynamic {
+  if(!expected.{core::List::length}.{core::num::==}(actual.{core::List::length})) {
+    throw "Expected ${expected}, actual ${actual}";
+  }
+  for (core::int* i = 0; i.{core::num::<}(expected.{core::List::length}); i = i.{core::num::+}(1)) {
+    self::expect(expected.{core::List::[]}(i), actual.{core::List::[]}(i));
+  }
+}
+
+constants  {
+  #C1 = tearoff self::id
+  #C2 = tearoff self::future
+  #C3 = 2
+}
diff --git a/pkg/front_end/testcases/general/await_in_cascade.dart b/pkg/front_end/testcases/general/await_in_cascade.dart
new file mode 100644
index 0000000..47cc183
--- /dev/null
+++ b/pkg/front_end/testcases/general/await_in_cascade.dart
@@ -0,0 +1,20 @@
+// 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.
+
+// This test was adapted from language_2/await_in_cascade_  test
+
+import 'dart:async';
+
+class C {
+  Future<List<int>> m() async => []..add(await _m());
+  Future<int> _m() async => 42;
+}
+
+main() async {
+  expect(42, (await new C().m()).first);
+}
+
+expect(expected, actual) {
+  if (expected != actual) throw 'Expected $expected, actual $actual';
+}
diff --git a/pkg/front_end/testcases/general/await_in_cascade.dart.outline.expect b/pkg/front_end/testcases/general/await_in_cascade.dart.outline.expect
new file mode 100644
index 0000000..c59c111
--- /dev/null
+++ b/pkg/front_end/testcases/general/await_in_cascade.dart.outline.expect
@@ -0,0 +1,19 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "dart:async" as asy;
+
+import "dart:async";
+
+class C extends core::Object {
+  synthetic constructor •() → self::C*
+    ;
+  method m() → asy::Future<core::List<core::int*>*>*
+    ;
+  method _m() → asy::Future<core::int*>*
+    ;
+}
+static method main() → dynamic
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
diff --git a/pkg/front_end/testcases/general/await_in_cascade.dart.strong.expect b/pkg/front_end/testcases/general/await_in_cascade.dart.strong.expect
new file mode 100644
index 0000000..4db7c74
--- /dev/null
+++ b/pkg/front_end/testcases/general/await_in_cascade.dart.strong.expect
@@ -0,0 +1,23 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "dart:async" as asy;
+
+import "dart:async";
+
+class C extends core::Object {
+  synthetic constructor •() → self::C*
+    : super core::Object::•()
+    ;
+  method m() → asy::Future<core::List<core::int*>*>* async 
+    return let final core::List<core::int*>* #t1 = <core::int*>[] in let final void #t2 = #t1.{core::List::add}(await this.{self::C::_m}()) in #t1;
+  method _m() → asy::Future<core::int*>* async 
+    return 42;
+}
+static method main() → dynamic async {
+  self::expect(42, (await new self::C::•().{self::C::m}()).{core::Iterable::first});
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
diff --git a/pkg/front_end/testcases/general/await_in_cascade.dart.strong.transformed.expect b/pkg/front_end/testcases/general/await_in_cascade.dart.strong.transformed.expect
new file mode 100644
index 0000000..be2d683
--- /dev/null
+++ b/pkg/front_end/testcases/general/await_in_cascade.dart.strong.transformed.expect
@@ -0,0 +1,102 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "dart:async" as asy;
+import "dart:_internal" as _in;
+
+import "dart:async";
+
+class C extends core::Object {
+  synthetic constructor •() → self::C*
+    : super core::Object::•()
+    ;
+  method m() → asy::Future<core::List<core::int*>*>* /* originally async */ {
+    final asy::_AsyncAwaitCompleter<core::List<core::int*>*>* :async_completer = new asy::_AsyncAwaitCompleter::•<core::List<core::int*>*>();
+    asy::FutureOr<core::List<core::int*>*>* :return_value;
+    dynamic :async_stack_trace;
+    dynamic :async_op_then;
+    dynamic :async_op_error;
+    core::int* :await_jump_var = 0;
+    dynamic :await_ctx_var;
+    dynamic :saved_try_context_var0;
+    function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
+      try {
+        #L1:
+        {
+          final core::List<core::int*>* #t1 = <core::int*>[];
+          [yield] let dynamic #t2 = asy::_awaitHelper(this.{self::C::_m}(), :async_op_then, :async_op_error, :async_op) in null;
+          :return_value = let final void #t3 = #t1.{core::List::add}(_in::unsafeCast<core::int*>(:result)) in #t1;
+          break #L1;
+        }
+        asy::_completeOnAsyncReturn(:async_completer, :return_value);
+        return;
+      }
+      on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+        :async_completer.{asy::Completer::completeError}(:exception, :stack_trace);
+      }
+    :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+    :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+    :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+    :async_completer.start(:async_op);
+    return :async_completer.{asy::Completer::future};
+  }
+  method _m() → asy::Future<core::int*>* /* originally async */ {
+    final asy::_AsyncAwaitCompleter<core::int*>* :async_completer = new asy::_AsyncAwaitCompleter::•<core::int*>();
+    asy::FutureOr<core::int*>* :return_value;
+    dynamic :async_stack_trace;
+    dynamic :async_op_then;
+    dynamic :async_op_error;
+    core::int* :await_jump_var = 0;
+    dynamic :await_ctx_var;
+    function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
+      try {
+        #L2:
+        {
+          :return_value = 42;
+          break #L2;
+        }
+        asy::_completeOnAsyncReturn(:async_completer, :return_value);
+        return;
+      }
+      on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+        :async_completer.{asy::Completer::completeError}(:exception, :stack_trace);
+      }
+    :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+    :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+    :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+    :async_completer.start(:async_op);
+    return :async_completer.{asy::Completer::future};
+  }
+}
+static method main() → dynamic /* originally async */ {
+  final asy::_AsyncAwaitCompleter<dynamic>* :async_completer = new asy::_AsyncAwaitCompleter::•<dynamic>();
+  asy::FutureOr<dynamic>* :return_value;
+  dynamic :async_stack_trace;
+  dynamic :async_op_then;
+  dynamic :async_op_error;
+  core::int* :await_jump_var = 0;
+  dynamic :await_ctx_var;
+  dynamic :saved_try_context_var0;
+  function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
+    try {
+      #L3:
+      {
+        [yield] let dynamic #t4 = asy::_awaitHelper(new self::C::•().{self::C::m}(), :async_op_then, :async_op_error, :async_op) in null;
+        self::expect(42, _in::unsafeCast<core::List<core::int*>*>(:result).{core::Iterable::first});
+      }
+      asy::_completeOnAsyncReturn(:async_completer, :return_value);
+      return;
+    }
+    on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+      :async_completer.{asy::Completer::completeError}(:exception, :stack_trace);
+    }
+  :async_stack_trace = asy::_asyncStackTraceHelper(:async_op);
+  :async_op_then = asy::_asyncThenWrapperHelper(:async_op);
+  :async_op_error = asy::_asyncErrorWrapperHelper(:async_op);
+  :async_completer.start(:async_op);
+  return :async_completer.{asy::Completer::future};
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
diff --git a/pkg/front_end/testcases/general/bug33196.dart.strong.transformed.expect b/pkg/front_end/testcases/general/bug33196.dart.strong.transformed.expect
index b555ba7..ca4c8a8 100644
--- a/pkg/front_end/testcases/general/bug33196.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/bug33196.dart.strong.transformed.expect
@@ -15,7 +15,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
     try {
diff --git a/pkg/front_end/testcases/general/bug33206.dart.strong.transformed.expect b/pkg/front_end/testcases/general/bug33206.dart.strong.transformed.expect
index 6e31cf5..052b974 100644
--- a/pkg/front_end/testcases/general/bug33206.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/bug33206.dart.strong.transformed.expect
@@ -2,6 +2,7 @@
 import self as self;
 import "dart:core" as core;
 import "dart:async" as asy;
+import "dart:_internal" as _in;
 
 import "dart:async";
 
@@ -26,7 +27,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
     try {
@@ -55,7 +56,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
     try {
@@ -82,7 +83,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   dynamic :saved_try_context_var0;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
@@ -91,10 +92,10 @@
       {
         final self::Y* #t1 = new self::Y::•();
         [yield] let dynamic #t2 = asy::_awaitHelper(self::f1(), :async_op_then, :async_op_error, :async_op) in null;
-        final void #t3 = #t1.{self::Y::f}(:result);
+        final void #t3 = #t1.{self::Y::f}(_in::unsafeCast<core::List<core::Object*>*>(:result));
         final void #t4 = #t1.{self::Y::f}(self::f2());
         [yield] let dynamic #t5 = asy::_awaitHelper(self::f3(), :async_op_then, :async_op_error, :async_op) in null;
-        :return_value = new self::X::•(#t1, :result);
+        :return_value = new self::X::•(#t1, _in::unsafeCast<core::Object*>(:result));
         break #L3;
       }
       asy::_completeOnAsyncReturn(:async_completer, :return_value);
@@ -115,7 +116,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   dynamic :saved_try_context_var0;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
@@ -123,7 +124,7 @@
       #L4:
       {
         [yield] let dynamic #t6 = asy::_awaitHelper(self::foo(), :async_op_then, :async_op_error, :async_op) in null;
-        core::print(:result);
+        core::print(_in::unsafeCast<self::X*>(:result));
       }
       asy::_completeOnAsyncReturn(:async_completer, :return_value);
       return;
diff --git a/pkg/front_end/testcases/general/call.dart.strong.expect b/pkg/front_end/testcases/general/call.dart.strong.expect
index 0346035..58e7da3 100644
--- a/pkg/front_end/testcases/general/call.dart.strong.expect
+++ b/pkg/front_end/testcases/general/call.dart.strong.expect
@@ -76,11 +76,11 @@
   dynamic string3 = callable.{self::Callable::call}.call(1);
   dynamic string4 = callable.{self::Callable::call}.call.call(1);
   self::CallableGetter* callableGetter = new self::CallableGetter::•();
-  dynamic string5 = let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/general/call.dart:29:31: Error: Cannot invoke an instance of 'CallableGetter' because it declares 'call' to be something other than a method.
+  dynamic string5 = invalid-expression "pkg/front_end/testcases/general/call.dart:29:31: Error: Cannot invoke an instance of 'CallableGetter' because it declares 'call' to be something other than a method.
  - 'CallableGetter' is from 'pkg/front_end/testcases/general/call.dart'.
 Try changing 'call' to a method or explicitly invoke 'call'.
   var string5 = callableGetter(1);
-                              ^" in callableGetter.{self::CallableGetter::call}(1);
+                              ^";
   dynamic string6 = callableGetter.{self::CallableGetter::call}(1);
   dynamic string7 = callableGetter.{self::CallableGetter::call}.call(1);
   dynamic string8 = callableGetter.{self::CallableGetter::call}.call.call(1);
@@ -92,11 +92,11 @@
   dynamic nothing6 = callable.{self::Callable::call}();
   dynamic nothing7 = callable.{self::Callable::call}.call();
   dynamic nothing8 = callable.{self::Callable::call}.call.call();
-  dynamic nothing9 = let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/general/call.dart:44:32: Error: Cannot invoke an instance of 'CallableGetter' because it declares 'call' to be something other than a method.
+  dynamic nothing9 = invalid-expression "pkg/front_end/testcases/general/call.dart:44:32: Error: Cannot invoke an instance of 'CallableGetter' because it declares 'call' to be something other than a method.
  - 'CallableGetter' is from 'pkg/front_end/testcases/general/call.dart'.
 Try changing 'call' to a method or explicitly invoke 'call'.
   var nothing9 = callableGetter();
-                               ^" in callableGetter.{self::CallableGetter::call}();
+                               ^";
   dynamic nothing10 = callableGetter.{self::CallableGetter::call}();
   dynamic nothing11 = callableGetter.{self::CallableGetter::call}.call();
   dynamic nothing12 = callableGetter.{self::CallableGetter::call}.call.call();
diff --git a/pkg/front_end/testcases/general/cascade.dart.strong.expect b/pkg/front_end/testcases/general/cascade.dart.strong.expect
index 1536d20..ed144d6 100644
--- a/pkg/front_end/testcases/general/cascade.dart.strong.expect
+++ b/pkg/front_end/testcases/general/cascade.dart.strong.expect
@@ -15,7 +15,7 @@
 // pkg/front_end/testcases/general/cascade.dart:29:12: Error: The method '[]' isn't defined for the class 'int'.
 // Try correcting the name to the name of an existing method, or defining a method named '[]'.
 //     ..first[0].toString()
-//            ^^
+//            ^
 //
 // pkg/front_end/testcases/general/cascade.dart:30:11: Error: The getter 'last' isn't defined for the class 'int'.
 // Try correcting the name to the name of an existing getter, or defining a getter or field named 'last'.
@@ -41,7 +41,7 @@
             ^^^^".{core::Object::toString}() in let final void #t16 = invalid-expression "pkg/front_end/testcases/general/cascade.dart:29:12: Error: The method '[]' isn't defined for the class 'int'.
 Try correcting the name to the name of an existing method, or defining a method named '[]'.
     ..first[0].toString()
-           ^^".{core::Object::toString}() in let final void #t17 = invalid-expression "pkg/front_end/testcases/general/cascade.dart:30:11: Error: The getter 'last' isn't defined for the class 'int'.
+           ^".{core::Object::toString}() in let final void #t17 = invalid-expression "pkg/front_end/testcases/general/cascade.dart:30:11: Error: The getter 'last' isn't defined for the class 'int'.
 Try correcting the name to the name of an existing getter, or defining a getter or field named 'last'.
     ..[0].last.toString();
           ^^^^".{core::Object::toString}() in #t13;
diff --git a/pkg/front_end/testcases/general/cascade.dart.strong.transformed.expect b/pkg/front_end/testcases/general/cascade.dart.strong.transformed.expect
index 1536d20..ed144d6 100644
--- a/pkg/front_end/testcases/general/cascade.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/cascade.dart.strong.transformed.expect
@@ -15,7 +15,7 @@
 // pkg/front_end/testcases/general/cascade.dart:29:12: Error: The method '[]' isn't defined for the class 'int'.
 // Try correcting the name to the name of an existing method, or defining a method named '[]'.
 //     ..first[0].toString()
-//            ^^
+//            ^
 //
 // pkg/front_end/testcases/general/cascade.dart:30:11: Error: The getter 'last' isn't defined for the class 'int'.
 // Try correcting the name to the name of an existing getter, or defining a getter or field named 'last'.
@@ -41,7 +41,7 @@
             ^^^^".{core::Object::toString}() in let final void #t16 = invalid-expression "pkg/front_end/testcases/general/cascade.dart:29:12: Error: The method '[]' isn't defined for the class 'int'.
 Try correcting the name to the name of an existing method, or defining a method named '[]'.
     ..first[0].toString()
-           ^^".{core::Object::toString}() in let final void #t17 = invalid-expression "pkg/front_end/testcases/general/cascade.dart:30:11: Error: The getter 'last' isn't defined for the class 'int'.
+           ^".{core::Object::toString}() in let final void #t17 = invalid-expression "pkg/front_end/testcases/general/cascade.dart:30:11: Error: The getter 'last' isn't defined for the class 'int'.
 Try correcting the name to the name of an existing getter, or defining a getter or field named 'last'.
     ..[0].last.toString();
           ^^^^".{core::Object::toString}() in #t13;
diff --git a/pkg/front_end/testcases/general/check_deferred_before_args2.dart.strong.transformed.expect b/pkg/front_end/testcases/general/check_deferred_before_args2.dart.strong.transformed.expect
index 422eb51..d20f094 100644
--- a/pkg/front_end/testcases/general/check_deferred_before_args2.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/check_deferred_before_args2.dart.strong.transformed.expect
@@ -13,7 +13,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   dynamic :saved_try_context_var0;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
diff --git a/pkg/front_end/testcases/general/control_flow_collection_inference.dart.strong.transformed.expect b/pkg/front_end/testcases/general/control_flow_collection_inference.dart.strong.transformed.expect
index 4360cc9..afb21c7 100644
--- a/pkg/front_end/testcases/general/control_flow_collection_inference.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/control_flow_collection_inference.dart.strong.transformed.expect
@@ -425,6 +425,7 @@
 import "dart:core" as core;
 import "dart:collection" as col;
 import "dart:async" as asy;
+import "dart:_internal" as _in;
 
 class A extends core::Object {
   synthetic constructor •() → self::A*
@@ -1813,7 +1814,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   dynamic :saved_try_context_var0;
   dynamic :saved_try_context_var1;
@@ -2100,7 +2101,7 @@
             while (true) {
               dynamic #t399 = asy::_asyncStarMoveNextHelper(:stream);
               [yield] let dynamic #t400 = asy::_awaitHelper(:for-iterator.{asy::_StreamIterator::moveNext}(), :async_op_then, :async_op_error, :async_op) in null;
-              if(:result) {
+              if(_in::unsafeCast<core::bool*>(:result)) {
                 dynamic i = :for-iterator.{asy::_StreamIterator::current};
                 #t397.{core::List::add}(i);
               }
@@ -2127,7 +2128,7 @@
             while (true) {
               dynamic #t404 = asy::_asyncStarMoveNextHelper(:stream);
               [yield] let dynamic #t405 = asy::_awaitHelper(:for-iterator.{asy::_StreamIterator::moveNext}(), :async_op_then, :async_op_error, :async_op) in null;
-              if(:result) {
+              if(_in::unsafeCast<core::bool*>(:result)) {
                 dynamic i = :for-iterator.{asy::_StreamIterator::current};
                 #t402.{core::Set::add}(i);
               }
@@ -2156,7 +2157,7 @@
             while (true) {
               dynamic #t409 = asy::_asyncStarMoveNextHelper(:stream);
               [yield] let dynamic #t410 = asy::_awaitHelper(:for-iterator.{asy::_StreamIterator::moveNext}(), :async_op_then, :async_op_error, :async_op) in null;
-              if(:result) {
+              if(_in::unsafeCast<core::bool*>(:result)) {
                 dynamic i = :for-iterator.{asy::_StreamIterator::current};
                 #t407.{core::Map::[]=}("bar", i);
               }
@@ -2186,7 +2187,7 @@
             while (true) {
               dynamic #t415 = asy::_asyncStarMoveNextHelper(:stream);
               [yield] let dynamic #t416 = asy::_awaitHelper(:for-iterator.{asy::_StreamIterator::moveNext}(), :async_op_then, :async_op_error, :async_op) in null;
-              if(:result) {
+              if(_in::unsafeCast<core::bool*>(:result)) {
                 core::int* i = :for-iterator.{asy::_StreamIterator::current};
                 #t412.{core::List::add}(i);
               }
@@ -2214,7 +2215,7 @@
             while (true) {
               dynamic #t421 = asy::_asyncStarMoveNextHelper(:stream);
               [yield] let dynamic #t422 = asy::_awaitHelper(:for-iterator.{asy::_StreamIterator::moveNext}(), :async_op_then, :async_op_error, :async_op) in null;
-              if(:result) {
+              if(_in::unsafeCast<core::bool*>(:result)) {
                 core::int* i = :for-iterator.{asy::_StreamIterator::current};
                 #t418.{core::Set::add}(i);
               }
@@ -2244,7 +2245,7 @@
             while (true) {
               dynamic #t427 = asy::_asyncStarMoveNextHelper(:stream);
               [yield] let dynamic #t428 = asy::_awaitHelper(:for-iterator.{asy::_StreamIterator::moveNext}(), :async_op_then, :async_op_error, :async_op) in null;
-              if(:result) {
+              if(_in::unsafeCast<core::bool*>(:result)) {
                 core::int* i = :for-iterator.{asy::_StreamIterator::current};
                 #t424.{core::Map::[]=}("bar", i);
               }
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_05.dart.strong.expect b/pkg/front_end/testcases/general/error_locations/error_location_05.dart.strong.expect
index b4a23c0..d9a0e7e 100644
--- a/pkg/front_end/testcases/general/error_locations/error_location_05.dart.strong.expect
+++ b/pkg/front_end/testcases/general/error_locations/error_location_05.dart.strong.expect
@@ -20,7 +20,7 @@
 import "dart:core" as core;
 
 part error_location_05_lib1.dart;
-static method /* from org-dartlang-testcase:///error_location_05_lib1.dart */ x1(dynamic z = #C1, {dynamic z = #C1}) → dynamic {}
+static method /* from org-dartlang-testcase:///error_location_05_lib1.dart */ x1(dynamic z, {dynamic z = #C1}) → dynamic {}
 static method /* from org-dartlang-testcase:///error_location_05_lib1.dart */ x2() → dynamic {
   function y(dynamic z, {dynamic z = #C1}) → core::Null? {}
 }
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_05.dart.strong.transformed.expect b/pkg/front_end/testcases/general/error_locations/error_location_05.dart.strong.transformed.expect
index b4a23c0..d9a0e7e 100644
--- a/pkg/front_end/testcases/general/error_locations/error_location_05.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/error_locations/error_location_05.dart.strong.transformed.expect
@@ -20,7 +20,7 @@
 import "dart:core" as core;
 
 part error_location_05_lib1.dart;
-static method /* from org-dartlang-testcase:///error_location_05_lib1.dart */ x1(dynamic z = #C1, {dynamic z = #C1}) → dynamic {}
+static method /* from org-dartlang-testcase:///error_location_05_lib1.dart */ x1(dynamic z, {dynamic z = #C1}) → dynamic {}
 static method /* from org-dartlang-testcase:///error_location_05_lib1.dart */ x2() → dynamic {
   function y(dynamic z, {dynamic z = #C1}) → core::Null? {}
 }
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_06.dart.strong.expect b/pkg/front_end/testcases/general/error_locations/error_location_06.dart.strong.expect
index 2d14468..a8ad767 100644
--- a/pkg/front_end/testcases/general/error_locations/error_location_06.dart.strong.expect
+++ b/pkg/front_end/testcases/general/error_locations/error_location_06.dart.strong.expect
@@ -20,7 +20,7 @@
 import "dart:core" as core;
 
 part error_location_06_lib1.dart;
-static method /* from org-dartlang-testcase:///error_location_06_lib1.dart */ x1(dynamic z = #C1, {dynamic z = #C1}) → dynamic {}
+static method /* from org-dartlang-testcase:///error_location_06_lib1.dart */ x1(dynamic z, {dynamic z = #C1}) → dynamic {}
 static method /* from org-dartlang-testcase:///error_location_06_lib1.dart */ x2() → dynamic {
   function y(dynamic z, {dynamic z = #C1}) → core::Null? {}
 }
diff --git a/pkg/front_end/testcases/general/error_locations/error_location_06.dart.strong.transformed.expect b/pkg/front_end/testcases/general/error_locations/error_location_06.dart.strong.transformed.expect
index 2d14468..a8ad767 100644
--- a/pkg/front_end/testcases/general/error_locations/error_location_06.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/error_locations/error_location_06.dart.strong.transformed.expect
@@ -20,7 +20,7 @@
 import "dart:core" as core;
 
 part error_location_06_lib1.dart;
-static method /* from org-dartlang-testcase:///error_location_06_lib1.dart */ x1(dynamic z = #C1, {dynamic z = #C1}) → dynamic {}
+static method /* from org-dartlang-testcase:///error_location_06_lib1.dart */ x1(dynamic z, {dynamic z = #C1}) → dynamic {}
 static method /* from org-dartlang-testcase:///error_location_06_lib1.dart */ x2() → dynamic {
   function y(dynamic z, {dynamic z = #C1}) → core::Null? {}
 }
diff --git a/pkg/front_end/testcases/general/ffi_sample.dart b/pkg/front_end/testcases/general/ffi_sample.dart
new file mode 100644
index 0000000..db95797
--- /dev/null
+++ b/pkg/front_end/testcases/general/ffi_sample.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2019, 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.
+
+// This test was adapted from samples/ffi/coordinate.dart
+
+import 'dart:ffi';
+
+import "package:ffi/ffi.dart";
+
+/// Sample struct for dart:ffi library.
+class Coordinate extends Struct {
+  @Double()
+  double x;
+
+  @Double()
+  double y;
+
+  Pointer<Coordinate> next;
+
+  factory Coordinate.allocate(double x, double y, Pointer<Coordinate> next) {
+    return allocate<Coordinate>().ref
+      ..x = x
+      ..y = y
+      ..next = next;
+  }
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/general/ffi_sample.dart.outline.expect b/pkg/front_end/testcases/general/ffi_sample.dart.outline.expect
new file mode 100644
index 0000000..37826b4
--- /dev/null
+++ b/pkg/front_end/testcases/general/ffi_sample.dart.outline.expect
@@ -0,0 +1,19 @@
+library;
+import self as self;
+import "dart:ffi" as ffi;
+import "dart:core" as core;
+
+import "dart:ffi";
+import "package:ffi/ffi.dart";
+
+class Coordinate extends ffi::Struct {
+  @ffi::Double::•()
+  field core::double* x;
+  @ffi::Double::•()
+  field core::double* y;
+  field ffi::Pointer<self::Coordinate*>* next;
+  static factory allocate(core::double* x, core::double* y, ffi::Pointer<self::Coordinate*>* next) → self::Coordinate*
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/general/ffi_sample.dart.strong.expect b/pkg/front_end/testcases/general/ffi_sample.dart.strong.expect
new file mode 100644
index 0000000..acbd85c
--- /dev/null
+++ b/pkg/front_end/testcases/general/ffi_sample.dart.strong.expect
@@ -0,0 +1,24 @@
+library;
+import self as self;
+import "dart:ffi" as ffi;
+import "dart:core" as core;
+import "package:ffi/src/allocation.dart" as all;
+
+import "dart:ffi";
+import "package:ffi/ffi.dart";
+
+class Coordinate extends ffi::Struct {
+  @#C1
+  field core::double* x = null;
+  @#C1
+  field core::double* y = null;
+  field ffi::Pointer<self::Coordinate*>* next = null;
+  static factory allocate(core::double* x, core::double* y, ffi::Pointer<self::Coordinate*>* next) → self::Coordinate* {
+    return let final self::Coordinate* #t1 = ffi::StructPointer|get#ref<self::Coordinate*>(all::allocate<self::Coordinate*>()) in let final void #t2 = #t1.{self::Coordinate::x} = x in let final void #t3 = #t1.{self::Coordinate::y} = y in let final void #t4 = #t1.{self::Coordinate::next} = next in #t1;
+  }
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = ffi::Double {}
+}
diff --git a/pkg/front_end/testcases/general/ffi_sample.dart.strong.transformed.expect b/pkg/front_end/testcases/general/ffi_sample.dart.strong.transformed.expect
new file mode 100644
index 0000000..2b10843
--- /dev/null
+++ b/pkg/front_end/testcases/general/ffi_sample.dart.strong.transformed.expect
@@ -0,0 +1,54 @@
+library;
+import self as self;
+import "dart:core" as core;
+import "dart:ffi" as ffi;
+import "package:ffi/src/allocation.dart" as all;
+
+import "dart:ffi";
+import "package:ffi/ffi.dart";
+
+@#C3
+class Coordinate extends ffi::Struct {
+  @#C3
+  static final field core::int* #sizeOf = (#C6).{core::List::[]}(ffi::_abi())/* from null */;
+  @#C3
+  constructor #fromPointer(dynamic #pointer) → dynamic
+    : super ffi::Struct::_fromPointer(#pointer)
+    ;
+  static factory allocate(core::double* x, core::double* y, ffi::Pointer<self::Coordinate*>* next) → self::Coordinate* {
+    return let final self::Coordinate* #t1 = ffi::StructPointer|get#ref<self::Coordinate*>(all::allocate<self::Coordinate*>()) in let final void #t2 = #t1.{self::Coordinate::x} = x in let final void #t3 = #t1.{self::Coordinate::y} = y in let final void #t4 = #t1.{self::Coordinate::next} = next in #t1;
+  }
+  get #_ptr_x() → ffi::Pointer<ffi::Double*>*
+    return this.{ffi::Struct::_addressOf}.{ffi::Pointer::cast}<ffi::Double*>();
+  get x() → core::double*
+    return ffi::_loadDouble(this.{self::Coordinate::#_ptr_x}, #C7);
+  set x(core::double* #v) → void
+    return ffi::_storeDouble(this.{self::Coordinate::#_ptr_x}, #C7, #v);
+  get #_ptr_y() → ffi::Pointer<ffi::Double*>*
+    return this.{ffi::Struct::_addressOf}.{ffi::Pointer::_offsetBy}((#C9).{core::List::[]}(ffi::_abi())).{ffi::Pointer::cast}<ffi::Double*>();
+  get y() → core::double*
+    return ffi::_loadDouble(this.{self::Coordinate::#_ptr_y}, #C7);
+  set y(core::double* #v) → void
+    return ffi::_storeDouble(this.{self::Coordinate::#_ptr_y}, #C7, #v);
+  get #_ptr_next() → ffi::Pointer<ffi::Pointer<self::Coordinate*>*>*
+    return this.{ffi::Struct::_addressOf}.{ffi::Pointer::_offsetBy}((#C11).{core::List::[]}(ffi::_abi())).{ffi::Pointer::cast}<ffi::Pointer<self::Coordinate*>*>();
+  get next() → ffi::Pointer<self::Coordinate*>*
+    return ffi::_loadPointer<ffi::Pointer<self::Coordinate*>*>(this.{self::Coordinate::#_ptr_next}, #C7);
+  set next(ffi::Pointer<self::Coordinate*>* #v) → void
+    return ffi::_storePointer<ffi::Pointer<self::Coordinate*>*>(this.{self::Coordinate::#_ptr_next}, #C7, #v);
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = "vm:entry-point"
+  #C2 = null
+  #C3 = core::pragma {name:#C1, options:#C2}
+  #C4 = 24
+  #C5 = 20
+  #C6 = <core::int*>[#C4, #C5, #C4]
+  #C7 = 0
+  #C8 = 8
+  #C9 = <core::int*>[#C8, #C8, #C8]
+  #C10 = 16
+  #C11 = <core::int*>[#C10, #C10, #C10]
+}
diff --git a/pkg/front_end/testcases/general/future_or_test.dart.strong.transformed.expect b/pkg/front_end/testcases/general/future_or_test.dart.strong.transformed.expect
index 9ec74f5..1d1c466 100644
--- a/pkg/front_end/testcases/general/future_or_test.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/future_or_test.dart.strong.transformed.expect
@@ -23,7 +23,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
@@ -56,7 +56,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
diff --git a/pkg/front_end/testcases/general/issue39344.dart b/pkg/front_end/testcases/general/issue39344.dart
new file mode 100644
index 0000000..e8fe329
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue39344.dart
@@ -0,0 +1,86 @@
+// Copyright (c) 2019, 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 {}
+
+class B extends A {}
+
+List<B> xs;
+List<List<B>> xss;
+
+class Class<T extends A> {
+  void method1a(T t) {
+    if (t is B) {
+      // `t` is now promoted to T & B
+
+      // The list literal has type List<T>, not List<T & B>
+      var ys = [t];
+      xs = ys;
+    }
+  }
+
+  void method1b(T t) {
+    if (t is B) {
+      // `t` is now promoted to T & B
+
+      // The list literal has type List<List<T>>, not List<List<T & B>>
+      var yss = [
+        [t]
+      ];
+      xss = yss;
+    }
+  }
+
+  void method2a(T t) {
+    dynamic alias;
+    if (t is B) {
+      // `t` is now promoted to T & B
+
+      // The list literal has type List<T>, not List<T & B>
+      var ys = [t];
+      alias = ys;
+      xs = alias;
+    }
+  }
+
+  void method2b(T t) {
+    dynamic alias;
+    if (t is B) {
+      // `t` is now promoted to T & B
+
+      // The list literal has type List<List<T>>, not List<List<T & B>>
+      var yss = [
+        [t]
+      ];
+      alias = yss;
+      xss = alias;
+    }
+  }
+}
+
+void main() {
+  throws(() {
+    Class<A>().method2a(B());
+    print(xs.runtimeType); // 'List<A>'.
+  });
+  throws(() {
+    Class<A>().method2b(B());
+    print(xs.runtimeType); // 'List<A>'.
+  });
+}
+
+void errors() {
+  Class<A>().method1a(B());
+  Class<A>().method1b(B());
+}
+
+void throws(void Function() f) {
+  try {
+    f();
+  } catch (e) {
+    print(e);
+    return;
+  }
+  throw 'Expected throws';
+}
diff --git a/pkg/front_end/testcases/general/issue39344.dart.outline.expect b/pkg/front_end/testcases/general/issue39344.dart.outline.expect
new file mode 100644
index 0000000..18fa4de
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue39344.dart.outline.expect
@@ -0,0 +1,32 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A*
+    ;
+}
+class B extends self::A {
+  synthetic constructor •() → self::B*
+    ;
+}
+class Class<T extends self::A* = self::A*> extends core::Object {
+  synthetic constructor •() → self::Class<self::Class::T*>*
+    ;
+  method method1a(generic-covariant-impl self::Class::T* t) → void
+    ;
+  method method1b(generic-covariant-impl self::Class::T* t) → void
+    ;
+  method method2a(generic-covariant-impl self::Class::T* t) → void
+    ;
+  method method2b(generic-covariant-impl self::Class::T* t) → void
+    ;
+}
+static field core::List<self::B*>* xs;
+static field core::List<core::List<self::B*>*>* xss;
+static method main() → void
+  ;
+static method errors() → void
+  ;
+static method throws(() →* void f) → void
+  ;
diff --git a/pkg/front_end/testcases/general/issue39344.dart.strong.expect b/pkg/front_end/testcases/general/issue39344.dart.strong.expect
new file mode 100644
index 0000000..8c367fc
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue39344.dart.strong.expect
@@ -0,0 +1,96 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/issue39344.dart:19:12: Error: A value of type 'List<T>' can't be assigned to a variable of type 'List<B>'.
+//  - 'List' is from 'dart:core'.
+//  - 'B' is from 'pkg/front_end/testcases/general/issue39344.dart'.
+//       xs = ys;
+//            ^
+//
+// pkg/front_end/testcases/general/issue39344.dart:31:13: Error: A value of type 'List<List<T>>' can't be assigned to a variable of type 'List<List<B>>'.
+//  - 'List' is from 'dart:core'.
+//  - 'B' is from 'pkg/front_end/testcases/general/issue39344.dart'.
+//       xss = yss;
+//             ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A*
+    : super core::Object::•()
+    ;
+}
+class B extends self::A {
+  synthetic constructor •() → self::B*
+    : super self::A::•()
+    ;
+}
+class Class<T extends self::A* = self::A*> extends core::Object {
+  synthetic constructor •() → self::Class<self::Class::T*>*
+    : super core::Object::•()
+    ;
+  method method1a(generic-covariant-impl self::Class::T* t) → void {
+    if(t is self::B*) {
+      core::List<self::Class::T*>* ys = <self::Class::T*>[t{self::Class::T* & self::B* /* '*' & '*' = '*' */}];
+      self::xs = let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/general/issue39344.dart:19:12: Error: A value of type 'List<T>' can't be assigned to a variable of type 'List<B>'.
+ - 'List' is from 'dart:core'.
+ - 'B' is from 'pkg/front_end/testcases/general/issue39344.dart'.
+      xs = ys;
+           ^" in ys as{TypeError} core::List<self::B*>*;
+    }
+  }
+  method method1b(generic-covariant-impl self::Class::T* t) → void {
+    if(t is self::B*) {
+      core::List<core::List<self::Class::T*>*>* yss = <core::List<self::Class::T*>*>[<self::Class::T*>[t{self::Class::T* & self::B* /* '*' & '*' = '*' */}]];
+      self::xss = let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/general/issue39344.dart:31:13: Error: A value of type 'List<List<T>>' can't be assigned to a variable of type 'List<List<B>>'.
+ - 'List' is from 'dart:core'.
+ - 'B' is from 'pkg/front_end/testcases/general/issue39344.dart'.
+      xss = yss;
+            ^" in yss as{TypeError} core::List<core::List<self::B*>*>*;
+    }
+  }
+  method method2a(generic-covariant-impl self::Class::T* t) → void {
+    dynamic alias;
+    if(t is self::B*) {
+      core::List<self::Class::T*>* ys = <self::Class::T*>[t{self::Class::T* & self::B* /* '*' & '*' = '*' */}];
+      alias = ys;
+      self::xs = alias as{TypeError} core::List<self::B*>*;
+    }
+  }
+  method method2b(generic-covariant-impl self::Class::T* t) → void {
+    dynamic alias;
+    if(t is self::B*) {
+      core::List<core::List<self::Class::T*>*>* yss = <core::List<self::Class::T*>*>[<self::Class::T*>[t{self::Class::T* & self::B* /* '*' & '*' = '*' */}]];
+      alias = yss;
+      self::xss = alias as{TypeError} core::List<core::List<self::B*>*>*;
+    }
+  }
+}
+static field core::List<self::B*>* xs;
+static field core::List<core::List<self::B*>*>* xss;
+static method main() → void {
+  self::throws(() → core::Null? {
+    new self::Class::•<self::A*>().{self::Class::method2a}(new self::B::•());
+    core::print(self::xs.{core::Object::runtimeType});
+  });
+  self::throws(() → core::Null? {
+    new self::Class::•<self::A*>().{self::Class::method2b}(new self::B::•());
+    core::print(self::xs.{core::Object::runtimeType});
+  });
+}
+static method errors() → void {
+  new self::Class::•<self::A*>().{self::Class::method1a}(new self::B::•());
+  new self::Class::•<self::A*>().{self::Class::method1b}(new self::B::•());
+}
+static method throws(() →* void f) → void {
+  try {
+    f.call();
+  }
+  on dynamic catch(final dynamic e) {
+    core::print(e);
+    return;
+  }
+  throw "Expected throws";
+}
diff --git a/pkg/front_end/testcases/general/issue39344.dart.strong.transformed.expect b/pkg/front_end/testcases/general/issue39344.dart.strong.transformed.expect
new file mode 100644
index 0000000..8c367fc
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue39344.dart.strong.transformed.expect
@@ -0,0 +1,96 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/issue39344.dart:19:12: Error: A value of type 'List<T>' can't be assigned to a variable of type 'List<B>'.
+//  - 'List' is from 'dart:core'.
+//  - 'B' is from 'pkg/front_end/testcases/general/issue39344.dart'.
+//       xs = ys;
+//            ^
+//
+// pkg/front_end/testcases/general/issue39344.dart:31:13: Error: A value of type 'List<List<T>>' can't be assigned to a variable of type 'List<List<B>>'.
+//  - 'List' is from 'dart:core'.
+//  - 'B' is from 'pkg/front_end/testcases/general/issue39344.dart'.
+//       xss = yss;
+//             ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A*
+    : super core::Object::•()
+    ;
+}
+class B extends self::A {
+  synthetic constructor •() → self::B*
+    : super self::A::•()
+    ;
+}
+class Class<T extends self::A* = self::A*> extends core::Object {
+  synthetic constructor •() → self::Class<self::Class::T*>*
+    : super core::Object::•()
+    ;
+  method method1a(generic-covariant-impl self::Class::T* t) → void {
+    if(t is self::B*) {
+      core::List<self::Class::T*>* ys = <self::Class::T*>[t{self::Class::T* & self::B* /* '*' & '*' = '*' */}];
+      self::xs = let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/general/issue39344.dart:19:12: Error: A value of type 'List<T>' can't be assigned to a variable of type 'List<B>'.
+ - 'List' is from 'dart:core'.
+ - 'B' is from 'pkg/front_end/testcases/general/issue39344.dart'.
+      xs = ys;
+           ^" in ys as{TypeError} core::List<self::B*>*;
+    }
+  }
+  method method1b(generic-covariant-impl self::Class::T* t) → void {
+    if(t is self::B*) {
+      core::List<core::List<self::Class::T*>*>* yss = <core::List<self::Class::T*>*>[<self::Class::T*>[t{self::Class::T* & self::B* /* '*' & '*' = '*' */}]];
+      self::xss = let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/general/issue39344.dart:31:13: Error: A value of type 'List<List<T>>' can't be assigned to a variable of type 'List<List<B>>'.
+ - 'List' is from 'dart:core'.
+ - 'B' is from 'pkg/front_end/testcases/general/issue39344.dart'.
+      xss = yss;
+            ^" in yss as{TypeError} core::List<core::List<self::B*>*>*;
+    }
+  }
+  method method2a(generic-covariant-impl self::Class::T* t) → void {
+    dynamic alias;
+    if(t is self::B*) {
+      core::List<self::Class::T*>* ys = <self::Class::T*>[t{self::Class::T* & self::B* /* '*' & '*' = '*' */}];
+      alias = ys;
+      self::xs = alias as{TypeError} core::List<self::B*>*;
+    }
+  }
+  method method2b(generic-covariant-impl self::Class::T* t) → void {
+    dynamic alias;
+    if(t is self::B*) {
+      core::List<core::List<self::Class::T*>*>* yss = <core::List<self::Class::T*>*>[<self::Class::T*>[t{self::Class::T* & self::B* /* '*' & '*' = '*' */}]];
+      alias = yss;
+      self::xss = alias as{TypeError} core::List<core::List<self::B*>*>*;
+    }
+  }
+}
+static field core::List<self::B*>* xs;
+static field core::List<core::List<self::B*>*>* xss;
+static method main() → void {
+  self::throws(() → core::Null? {
+    new self::Class::•<self::A*>().{self::Class::method2a}(new self::B::•());
+    core::print(self::xs.{core::Object::runtimeType});
+  });
+  self::throws(() → core::Null? {
+    new self::Class::•<self::A*>().{self::Class::method2b}(new self::B::•());
+    core::print(self::xs.{core::Object::runtimeType});
+  });
+}
+static method errors() → void {
+  new self::Class::•<self::A*>().{self::Class::method1a}(new self::B::•());
+  new self::Class::•<self::A*>().{self::Class::method1b}(new self::B::•());
+}
+static method throws(() →* void f) → void {
+  try {
+    f.call();
+  }
+  on dynamic catch(final dynamic e) {
+    core::print(e);
+    return;
+  }
+  throw "Expected throws";
+}
diff --git a/pkg/front_end/testcases/general/issue39421.dart b/pkg/front_end/testcases/general/issue39421.dart
new file mode 100644
index 0000000..e83ee28
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue39421.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2019, 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.
+
+// This is a regression test for http://dartbug.com/39421.
+
+class A {}
+
+class A {}
+
+class B {
+  foo(List<Null> a) {}
+}
+
+class C extends B {
+  foo(List<A> a) {}
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/general/issue39421.dart.outline.expect b/pkg/front_end/testcases/general/issue39421.dart.outline.expect
new file mode 100644
index 0000000..1987156
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue39421.dart.outline.expect
@@ -0,0 +1,52 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/issue39421.dart:9:7: Error: 'A' is already declared in this scope.
+// class A {}
+//       ^
+// pkg/front_end/testcases/general/issue39421.dart:7:7: Context: Previous declaration of 'A'.
+// class A {}
+//       ^
+//
+// pkg/front_end/testcases/general/issue39421.dart:16:12: Error: 'A' isn't a type.
+//   foo(List<A> a) {}
+//            ^
+// pkg/front_end/testcases/general/issue39421.dart:16:12: Context: This isn't a type.
+//   foo(List<A> a) {}
+//            ^
+//
+// pkg/front_end/testcases/general/issue39421.dart:16:15: Error: The parameter 'a' of the method 'C.foo' has type 'List<invalid-type>', which does not match the corresponding type, 'List<Null>', in the overridden method, 'B.foo'.
+//  - 'List' is from 'dart:core'.
+// Change to a supertype of 'List<Null>', or, for a covariant parameter, a subtype.
+//   foo(List<A> a) {}
+//               ^
+// pkg/front_end/testcases/general/issue39421.dart:12:3: Context: This is the overridden method ('foo').
+//   foo(List<Null> a) {}
+//   ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A#1 extends core::Object {
+  synthetic constructor •() → self::A#1*
+    ;
+}
+class A extends core::Object {
+  synthetic constructor •() → self::A*
+    ;
+}
+class B extends core::Object {
+  synthetic constructor •() → self::B*
+    ;
+  method foo(core::List<core::Null?>* a) → dynamic
+    ;
+}
+class C extends self::B {
+  synthetic constructor •() → self::C*
+    ;
+  method foo(core::List<invalid-type>* a) → dynamic
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/general/issue39421.dart.strong.expect b/pkg/front_end/testcases/general/issue39421.dart.strong.expect
new file mode 100644
index 0000000..6103be6
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue39421.dart.strong.expect
@@ -0,0 +1,57 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/issue39421.dart:9:7: Error: 'A' is already declared in this scope.
+// class A {}
+//       ^
+// pkg/front_end/testcases/general/issue39421.dart:7:7: Context: Previous declaration of 'A'.
+// class A {}
+//       ^
+//
+// pkg/front_end/testcases/general/issue39421.dart:16:12: Error: 'A' isn't a type.
+//   foo(List<A> a) {}
+//            ^
+// pkg/front_end/testcases/general/issue39421.dart:16:12: Context: This isn't a type.
+//   foo(List<A> a) {}
+//            ^
+//
+// pkg/front_end/testcases/general/issue39421.dart:16:15: Error: The parameter 'a' of the method 'C.foo' has type 'List<invalid-type>', which does not match the corresponding type, 'List<Null>', in the overridden method, 'B.foo'.
+//  - 'List' is from 'dart:core'.
+// Change to a supertype of 'List<Null>', or, for a covariant parameter, a subtype.
+//   foo(List<A> a) {}
+//               ^
+// pkg/front_end/testcases/general/issue39421.dart:12:3: Context: This is the overridden method ('foo').
+//   foo(List<Null> a) {}
+//   ^
+//
+// pkg/front_end/testcases/general/issue39421.dart:16:12: Error: Can't use 'A' because it is declared more than once.
+//   foo(List<A> a) {}
+//            ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A#1 extends core::Object {
+  synthetic constructor •() → self::A#1*
+    : super core::Object::•()
+    ;
+}
+class A extends core::Object {
+  synthetic constructor •() → self::A*
+    : super core::Object::•()
+    ;
+}
+class B extends core::Object {
+  synthetic constructor •() → self::B*
+    : super core::Object::•()
+    ;
+  method foo(core::List<core::Null?>* a) → dynamic {}
+}
+class C extends self::B {
+  synthetic constructor •() → self::C*
+    : super self::B::•()
+    ;
+  method foo(core::List<invalid-type>* a) → dynamic {}
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/general/issue39421.dart.strong.transformed.expect b/pkg/front_end/testcases/general/issue39421.dart.strong.transformed.expect
new file mode 100644
index 0000000..6103be6
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue39421.dart.strong.transformed.expect
@@ -0,0 +1,57 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/issue39421.dart:9:7: Error: 'A' is already declared in this scope.
+// class A {}
+//       ^
+// pkg/front_end/testcases/general/issue39421.dart:7:7: Context: Previous declaration of 'A'.
+// class A {}
+//       ^
+//
+// pkg/front_end/testcases/general/issue39421.dart:16:12: Error: 'A' isn't a type.
+//   foo(List<A> a) {}
+//            ^
+// pkg/front_end/testcases/general/issue39421.dart:16:12: Context: This isn't a type.
+//   foo(List<A> a) {}
+//            ^
+//
+// pkg/front_end/testcases/general/issue39421.dart:16:15: Error: The parameter 'a' of the method 'C.foo' has type 'List<invalid-type>', which does not match the corresponding type, 'List<Null>', in the overridden method, 'B.foo'.
+//  - 'List' is from 'dart:core'.
+// Change to a supertype of 'List<Null>', or, for a covariant parameter, a subtype.
+//   foo(List<A> a) {}
+//               ^
+// pkg/front_end/testcases/general/issue39421.dart:12:3: Context: This is the overridden method ('foo').
+//   foo(List<Null> a) {}
+//   ^
+//
+// pkg/front_end/testcases/general/issue39421.dart:16:12: Error: Can't use 'A' because it is declared more than once.
+//   foo(List<A> a) {}
+//            ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A#1 extends core::Object {
+  synthetic constructor •() → self::A#1*
+    : super core::Object::•()
+    ;
+}
+class A extends core::Object {
+  synthetic constructor •() → self::A*
+    : super core::Object::•()
+    ;
+}
+class B extends core::Object {
+  synthetic constructor •() → self::B*
+    : super core::Object::•()
+    ;
+  method foo(core::List<core::Null?>* a) → dynamic {}
+}
+class C extends self::B {
+  synthetic constructor •() → self::C*
+    : super self::B::•()
+    ;
+  method foo(core::List<invalid-type>* a) → dynamic {}
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/general/operator_method_not_found.dart.strong.expect b/pkg/front_end/testcases/general/operator_method_not_found.dart.strong.expect
index 3c5f989..4bcc6e9 100644
--- a/pkg/front_end/testcases/general/operator_method_not_found.dart.strong.expect
+++ b/pkg/front_end/testcases/general/operator_method_not_found.dart.strong.expect
@@ -175,7 +175,7 @@
 //  - 'Foo' is from 'pkg/front_end/testcases/general/operator_method_not_found.dart'.
 // Try correcting the name to the name of an existing method, or defining a method named '[]'.
 //   print(foo[2]);
-//            ^^
+//            ^
 //
 // pkg/front_end/testcases/general/operator_method_not_found.dart:31:9: Error: The method '~' isn't defined for the class 'Foo'.
 //  - 'Foo' is from 'pkg/front_end/testcases/general/operator_method_not_found.dart'.
@@ -284,7 +284,7 @@
  - 'Foo' is from 'pkg/front_end/testcases/general/operator_method_not_found.dart'.
 Try correcting the name to the name of an existing method, or defining a method named '[]'.
   print(foo[2]);
-           ^^");
+           ^");
   core::print(invalid-expression "pkg/front_end/testcases/general/operator_method_not_found.dart:31:9: Error: The method '~' isn't defined for the class 'Foo'.
  - 'Foo' is from 'pkg/front_end/testcases/general/operator_method_not_found.dart'.
 Try correcting the name to the name of an existing method, or defining a method named '~'.
diff --git a/pkg/front_end/testcases/general/operator_method_not_found.dart.strong.transformed.expect b/pkg/front_end/testcases/general/operator_method_not_found.dart.strong.transformed.expect
index 3c5f989..4bcc6e9 100644
--- a/pkg/front_end/testcases/general/operator_method_not_found.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/operator_method_not_found.dart.strong.transformed.expect
@@ -175,7 +175,7 @@
 //  - 'Foo' is from 'pkg/front_end/testcases/general/operator_method_not_found.dart'.
 // Try correcting the name to the name of an existing method, or defining a method named '[]'.
 //   print(foo[2]);
-//            ^^
+//            ^
 //
 // pkg/front_end/testcases/general/operator_method_not_found.dart:31:9: Error: The method '~' isn't defined for the class 'Foo'.
 //  - 'Foo' is from 'pkg/front_end/testcases/general/operator_method_not_found.dart'.
@@ -284,7 +284,7 @@
  - 'Foo' is from 'pkg/front_end/testcases/general/operator_method_not_found.dart'.
 Try correcting the name to the name of an existing method, or defining a method named '[]'.
   print(foo[2]);
-           ^^");
+           ^");
   core::print(invalid-expression "pkg/front_end/testcases/general/operator_method_not_found.dart:31:9: Error: The method '~' isn't defined for the class 'Foo'.
  - 'Foo' is from 'pkg/front_end/testcases/general/operator_method_not_found.dart'.
 Try correcting the name to the name of an existing method, or defining a method named '~'.
diff --git a/pkg/front_end/testcases/general/sdk_diagnostic.dart.outline.expect b/pkg/front_end/testcases/general/sdk_diagnostic.dart.outline.expect
index 50a933c..3f5874b 100644
--- a/pkg/front_end/testcases/general/sdk_diagnostic.dart.outline.expect
+++ b/pkg/front_end/testcases/general/sdk_diagnostic.dart.outline.expect
@@ -12,7 +12,7 @@
 //
 // class C extends Iterable<Object> {
 //       ^
-// sdk/lib/core/iterable.dart:154:19: Context: 'Iterable.iterator' is defined here.
+// sdk/lib/core/iterable.dart:156:19: Context: 'Iterable.iterator' is defined here.
 //   Iterator<E> get iterator;
 //                   ^^^^^^^^
 //
diff --git a/pkg/front_end/testcases/general/sdk_diagnostic.dart.strong.expect b/pkg/front_end/testcases/general/sdk_diagnostic.dart.strong.expect
index edca57d..80fbfff 100644
--- a/pkg/front_end/testcases/general/sdk_diagnostic.dart.strong.expect
+++ b/pkg/front_end/testcases/general/sdk_diagnostic.dart.strong.expect
@@ -12,14 +12,14 @@
 //
 // class C extends Iterable<Object> {
 //       ^
-// sdk/lib/core/iterable.dart:154:19: Context: 'Iterable.iterator' is defined here.
+// sdk/lib/core/iterable.dart:156:19: Context: 'Iterable.iterator' is defined here.
 //   Iterator<E> get iterator;
 //                   ^^^^^^^^
 //
 // pkg/front_end/testcases/general/sdk_diagnostic.dart:12:8: Error: Too few positional arguments: 1 required, 0 given.
 //   print(incorrectArgument: "fisk");
 //        ^
-// sdk/lib/core/print.dart:8:6: Context: Found this candidate, but the arguments don't match.
+// sdk/lib/core/print.dart:10:6: Context: Found this candidate, but the arguments don't match.
 // void print(Object object) {
 //      ^^^^^
 //
diff --git a/pkg/front_end/testcases/general/sdk_diagnostic.dart.strong.transformed.expect b/pkg/front_end/testcases/general/sdk_diagnostic.dart.strong.transformed.expect
index edca57d..80fbfff 100644
--- a/pkg/front_end/testcases/general/sdk_diagnostic.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/sdk_diagnostic.dart.strong.transformed.expect
@@ -12,14 +12,14 @@
 //
 // class C extends Iterable<Object> {
 //       ^
-// sdk/lib/core/iterable.dart:154:19: Context: 'Iterable.iterator' is defined here.
+// sdk/lib/core/iterable.dart:156:19: Context: 'Iterable.iterator' is defined here.
 //   Iterator<E> get iterator;
 //                   ^^^^^^^^
 //
 // pkg/front_end/testcases/general/sdk_diagnostic.dart:12:8: Error: Too few positional arguments: 1 required, 0 given.
 //   print(incorrectArgument: "fisk");
 //        ^
-// sdk/lib/core/print.dart:8:6: Context: Found this candidate, but the arguments don't match.
+// sdk/lib/core/print.dart:10:6: Context: Found this candidate, but the arguments don't match.
 // void print(Object object) {
 //      ^^^^^
 //
diff --git a/pkg/front_end/testcases/general/unsound_promotion.dart.strong.expect b/pkg/front_end/testcases/general/unsound_promotion.dart.strong.expect
index 7251f88..cb3e61b 100644
--- a/pkg/front_end/testcases/general/unsound_promotion.dart.strong.expect
+++ b/pkg/front_end/testcases/general/unsound_promotion.dart.strong.expect
@@ -2,11 +2,14 @@
 //
 // Problems in library:
 //
-// pkg/front_end/testcases/general/unsound_promotion.dart:21:16: Error: Can't infer a type for 'T', it can be either 'S' or 'A'.
+// pkg/front_end/testcases/general/unsound_promotion.dart:21:16: Error: Inferred type argument 'S' doesn't conform to the bound 'A' of the type variable 'T' on 'g'.
 //  - 'A' is from 'pkg/front_end/testcases/general/unsound_promotion.dart'.
-// Try adding a type argument selecting one of the options.
+// Try specifying type arguments explicitly so that they conform to the bounds.
 //     var list = g(s);
 //                ^
+// pkg/front_end/testcases/general/unsound_promotion.dart:13:11: Context: This is the type variable whose bound isn't conformed to.
+// List<T> g<T extends A>(T t) {
+//           ^
 //
 import self as self;
 import "dart:core" as core;
@@ -34,7 +37,7 @@
 }
 static method f<S extends core::Object* = dynamic>(self::f::S* s) → core::List<self::f::S*>* {
   if(s is self::A*) {
-    core::List<self::f::S* & self::A* /* '*' & '*' = '*' */>* list = self::g<self::f::S* & self::A* /* '*' & '*' = '*' */>(s{self::f::S* & self::A* /* '*' & '*' = '*' */});
+    core::List<self::f::S*>* list = self::g<self::f::S*>(s{self::f::S* & self::A* /* '*' & '*' = '*' */});
     return list;
   }
   return null;
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/crash_test_1.yaml.world.1.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/crash_test_1.yaml.world.1.expect
index 69ca563..10227fc 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/crash_test_1.yaml.world.1.expect
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/crash_test_1.yaml.world.1.expect
@@ -35,7 +35,7 @@
       dynamic :async_stack_trace;
       dynamic :async_op_then;
       dynamic :async_op_error;
-      dynamic :await_jump_var = 0;
+      dart.core::int* :await_jump_var = 0;
       dynamic :await_ctx_var;
       function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
         try {
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_1.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_1.yaml
index d3fe395..0c6b1b9 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_1.yaml
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_1.yaml
@@ -7,6 +7,7 @@
 type: newworld
 worlds:
   - entry: actualMain.dart
+    useExperimentalInvalidation: true
     sources:
       actualMain.dart: |
         import 'main.dart' as m;
@@ -36,6 +37,7 @@
         }
     expectedLibraryCount: 4
   - entry: actualMain.dart
+    useExperimentalInvalidation: true
     worldType: updated
     expectInitializeFromDill: false
     invalidate:
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_2.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_2.yaml
index e9a82b1..a8367f4 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_2.yaml
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_2.yaml
@@ -7,6 +7,7 @@
 type: newworld
 worlds:
   - entry: main.dart
+    useExperimentalInvalidation: true
     sources:
       main.dart: |
         import 'libA.dart';
@@ -33,6 +34,7 @@
         }
     expectedLibraryCount: 2
   - entry: main.dart
+    useExperimentalInvalidation: true
     worldType: updated
     expectInitializeFromDill: false
     invalidate:
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_3.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_3.yaml
index 4ba8586..4465423 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_3.yaml
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_3.yaml
@@ -7,6 +7,7 @@
 type: newworld
 worlds:
   - entry: main.dart
+    useExperimentalInvalidation: true
     sources:
       main.dart: |
         import 'libA.dart';
@@ -28,6 +29,7 @@
         }
     expectedLibraryCount: 2
   - entry: main.dart
+    useExperimentalInvalidation: true
     worldType: updated
     expectInitializeFromDill: false
     invalidate:
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_3.yaml.world.1.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_3.yaml.world.1.expect
index 7a4295d..91e8487 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_3.yaml.world.1.expect
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_3.yaml.world.1.expect
@@ -7,7 +7,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    dart.core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
@@ -15,7 +15,7 @@
         #L1:
         {
           [yield] let dynamic #t1 = dart.async::_awaitHelper(null, :async_op_then, :async_op_error, :async_op) in null;
-          :result;
+          dart._internal::unsafeCast<dart.core::Null?>(:result);
           :return_value = "hello";
           break #L1;
         }
@@ -50,7 +50,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    dart.core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_3.yaml.world.2.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_3.yaml.world.2.expect
index 42e02f0..b5437cc 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_3.yaml.world.2.expect
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_3.yaml.world.2.expect
@@ -7,7 +7,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    dart.core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
@@ -15,7 +15,7 @@
         #L1:
         {
           [yield] let dynamic #t1 = dart.async::_awaitHelper(null, :async_op_then, :async_op_error, :async_op) in null;
-          :result;
+          dart._internal::unsafeCast<dart.core::Null?>(:result);
           :return_value = "hello";
           break #L1;
         }
@@ -50,7 +50,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    dart.core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_4.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_4.yaml
index 554f242..4c12698 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_4.yaml
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_4.yaml
@@ -8,6 +8,7 @@
 type: newworld
 worlds:
   - entry: main.dart
+    useExperimentalInvalidation: true
     sources:
       main.dart: |
         import 'libA.dart';
@@ -27,6 +28,7 @@
         }
     expectedLibraryCount: 2
   - entry: main.dart
+    useExperimentalInvalidation: true
     worldType: updated
     expectInitializeFromDill: false
     invalidate:
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_5.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_5.yaml
new file mode 100644
index 0000000..02c6454
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_5.yaml
@@ -0,0 +1,47 @@
+# Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE.md file.
+
+# Compile an application with a part, change a file,
+# but don't change the outline.
+
+type: newworld
+worlds:
+  - entry: main.dart
+    useExperimentalInvalidation: true
+    sources:
+      main.dart: |
+        part 'myPart.dart';
+
+        class Foo {
+          const Foo();
+          @override
+          toString() => 'Foo!';
+        }
+
+        main() async {
+          await whatever();
+          print(const Foo());
+        }
+      myPart.dart: |
+        part of 'main.dart';
+        whatever() async {
+          await null;
+          return "hello";
+        }
+    expectedLibraryCount: 1
+  - entry: main.dart
+    useExperimentalInvalidation: true
+    worldType: updated
+    expectInitializeFromDill: false
+    invalidate:
+      - myPart.dart
+    sources:
+      myPart.dart: |
+        part of 'main.dart';
+        whatever() async {
+          await null;
+          return "hello!!!";
+        }
+    expectedLibraryCount: 1
+    expectsRebuildBodiesOnly: true
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_5.yaml.world.1.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_5.yaml.world.1.expect
new file mode 100644
index 0000000..164275c
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_5.yaml.world.1.expect
@@ -0,0 +1,76 @@
+main = <No Member>;
+library from "org-dartlang-test:///main.dart" as main {
+
+  part myPart.dart;
+  class Foo extends dart.core::Object {
+    const constructor •() → main::Foo*
+      : super dart.core::Object::•()
+      ;
+    @#C1
+    method toString() → dart.core::String*
+      return "Foo!";
+  }
+  static method main() → dynamic /* originally async */ {
+    final dart.async::_AsyncAwaitCompleter<dynamic>* :async_completer = new dart.async::_AsyncAwaitCompleter::•<dynamic>();
+    dart.async::FutureOr<dynamic>* :return_value;
+    dynamic :async_stack_trace;
+    dynamic :async_op_then;
+    dynamic :async_op_error;
+    dart.core::int* :await_jump_var = 0;
+    dynamic :await_ctx_var;
+    dynamic :saved_try_context_var0;
+    function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
+      try {
+        #L1:
+        {
+          [yield] let dynamic #t1 = dart.async::_awaitHelper(main::whatever(), :async_op_then, :async_op_error, :async_op) in null;
+          :result;
+          dart.core::print(#C2);
+        }
+        dart.async::_completeOnAsyncReturn(:async_completer, :return_value);
+        return;
+      }
+      on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+        :async_completer.{dart.async::Completer::completeError}(:exception, :stack_trace);
+      }
+    :async_stack_trace = dart.async::_asyncStackTraceHelper(:async_op);
+    :async_op_then = dart.async::_asyncThenWrapperHelper(:async_op);
+    :async_op_error = dart.async::_asyncErrorWrapperHelper(:async_op);
+    :async_completer.start(:async_op);
+    return :async_completer.{dart.async::Completer::future};
+  }
+  static method /* from org-dartlang-test:///myPart.dart */ whatever() → dynamic /* originally async */ {
+    final dart.async::_AsyncAwaitCompleter<dynamic>* :async_completer = new dart.async::_AsyncAwaitCompleter::•<dynamic>();
+    dart.async::FutureOr<dynamic>* :return_value;
+    dynamic :async_stack_trace;
+    dynamic :async_op_then;
+    dynamic :async_op_error;
+    dart.core::int* :await_jump_var = 0;
+    dynamic :await_ctx_var;
+    dynamic :saved_try_context_var0;
+    function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
+      try {
+        #L2:
+        {
+          [yield] let dynamic #t2 = dart.async::_awaitHelper(null, :async_op_then, :async_op_error, :async_op) in null;
+          dart._internal::unsafeCast<dart.core::Null?>(:result);
+          :return_value = "hello";
+          break #L2;
+        }
+        dart.async::_completeOnAsyncReturn(:async_completer, :return_value);
+        return;
+      }
+      on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+        :async_completer.{dart.async::Completer::completeError}(:exception, :stack_trace);
+      }
+    :async_stack_trace = dart.async::_asyncStackTraceHelper(:async_op);
+    :async_op_then = dart.async::_asyncThenWrapperHelper(:async_op);
+    :async_op_error = dart.async::_asyncErrorWrapperHelper(:async_op);
+    :async_completer.start(:async_op);
+    return :async_completer.{dart.async::Completer::future};
+  }
+}
+constants  {
+  #C1 = dart.core::_Override {}
+  #C2 = main::Foo {}
+}
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_5.yaml.world.2.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_5.yaml.world.2.expect
new file mode 100644
index 0000000..eda5685
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_5.yaml.world.2.expect
@@ -0,0 +1,76 @@
+main = <No Member>;
+library from "org-dartlang-test:///main.dart" as main {
+
+  part myPart.dart;
+  class Foo extends dart.core::Object {
+    const constructor •() → main::Foo*
+      : super dart.core::Object::•()
+      ;
+    @#C1
+    method toString() → dart.core::String*
+      return "Foo!";
+  }
+  static method main() → dynamic /* originally async */ {
+    final dart.async::_AsyncAwaitCompleter<dynamic>* :async_completer = new dart.async::_AsyncAwaitCompleter::•<dynamic>();
+    dart.async::FutureOr<dynamic>* :return_value;
+    dynamic :async_stack_trace;
+    dynamic :async_op_then;
+    dynamic :async_op_error;
+    dart.core::int* :await_jump_var = 0;
+    dynamic :await_ctx_var;
+    dynamic :saved_try_context_var0;
+    function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
+      try {
+        #L1:
+        {
+          [yield] let dynamic #t1 = dart.async::_awaitHelper(main::whatever(), :async_op_then, :async_op_error, :async_op) in null;
+          :result;
+          dart.core::print(#C2);
+        }
+        dart.async::_completeOnAsyncReturn(:async_completer, :return_value);
+        return;
+      }
+      on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+        :async_completer.{dart.async::Completer::completeError}(:exception, :stack_trace);
+      }
+    :async_stack_trace = dart.async::_asyncStackTraceHelper(:async_op);
+    :async_op_then = dart.async::_asyncThenWrapperHelper(:async_op);
+    :async_op_error = dart.async::_asyncErrorWrapperHelper(:async_op);
+    :async_completer.start(:async_op);
+    return :async_completer.{dart.async::Completer::future};
+  }
+  static method /* from org-dartlang-test:///myPart.dart */ whatever() → dynamic /* originally async */ {
+    final dart.async::_AsyncAwaitCompleter<dynamic>* :async_completer = new dart.async::_AsyncAwaitCompleter::•<dynamic>();
+    dart.async::FutureOr<dynamic>* :return_value;
+    dynamic :async_stack_trace;
+    dynamic :async_op_then;
+    dynamic :async_op_error;
+    dart.core::int* :await_jump_var = 0;
+    dynamic :await_ctx_var;
+    dynamic :saved_try_context_var0;
+    function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
+      try {
+        #L2:
+        {
+          [yield] let dynamic #t2 = dart.async::_awaitHelper(null, :async_op_then, :async_op_error, :async_op) in null;
+          dart._internal::unsafeCast<dart.core::Null?>(:result);
+          :return_value = "hello!!!";
+          break #L2;
+        }
+        dart.async::_completeOnAsyncReturn(:async_completer, :return_value);
+        return;
+      }
+      on dynamic catch(dynamic :exception, dynamic :stack_trace) {
+        :async_completer.{dart.async::Completer::completeError}(:exception, :stack_trace);
+      }
+    :async_stack_trace = dart.async::_asyncStackTraceHelper(:async_op);
+    :async_op_then = dart.async::_asyncThenWrapperHelper(:async_op);
+    :async_op_error = dart.async::_asyncErrorWrapperHelper(:async_op);
+    :async_completer.start(:async_op);
+    return :async_completer.{dart.async::Completer::future};
+  }
+}
+constants  {
+  #C1 = dart.core::_Override {}
+  #C2 = main::Foo {}
+}
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_6.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_6.yaml
new file mode 100644
index 0000000..8aa50fc
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_6.yaml
@@ -0,0 +1,91 @@
+# Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE.md file.
+
+# Compile an application, change a file, but don't change the outline.
+
+type: newworld
+worlds:
+  - entry: main.dart
+    useExperimentalInvalidation: true
+    errors: true
+    sources:
+      main.dart: |
+        import 'libA.dart';
+
+        class Foo {
+          final message;
+          Foo(this.message);
+          @override
+          toString() { return '$message' } // missing ;
+        }
+
+        main() {
+          Foo foo = new Foo("hello");
+          whatever(foo);
+          CompilationStrategy compilationStrategy = CompilationStrategy.direct;
+          print(compilationStrategy);
+        }
+
+        enum CompilationStrategy { direct, toKernel, toData, fromData }
+      libA.dart: |
+        import 'main.dart';
+        whatever(Foo foo) {
+          print(foo);
+        }
+    expectedLibraryCount: 2
+  - entry: main.dart
+    useExperimentalInvalidation: true
+    errors: true
+    worldType: updated
+    expectInitializeFromDill: false
+    invalidate:
+      - main.dart
+    sources:
+      main.dart: |
+        import 'libA.dart';
+
+        class Foo {
+          final message;
+          Foo(this.message);
+          @override
+          toString() { return '$message!!!' } // missing ; still
+        }
+
+        main() {
+          Foo foo = new Foo("hello");
+          whatever(foo);
+          CompilationStrategy compilationStrategy = CompilationStrategy.direct;
+          print(compilationStrategy);
+        }
+
+        enum CompilationStrategy { direct, toKernel, toData, fromData }
+    expectedLibraryCount: 2
+    expectsRebuildBodiesOnly: true
+  - entry: main.dart
+    useExperimentalInvalidation: true
+    worldType: updated
+    expectInitializeFromDill: false
+    invalidate:
+      - main.dart
+    sources:
+      main.dart: |
+        import 'libA.dart';
+
+        class Foo {
+          final message;
+          Foo(this.message);
+          @override
+          toString() { return '$message?!?'; } // fixed
+        }
+
+        main() {
+          Foo foo = new Foo("hello");
+          whatever(foo);
+          CompilationStrategy compilationStrategy = CompilationStrategy.direct;
+          print(compilationStrategy);
+        }
+
+        enum CompilationStrategy { direct, toKernel, toData, fromData }
+    expectedLibraryCount: 2
+    expectsRebuildBodiesOnly: true
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_6.yaml.world.1.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_6.yaml.world.1.expect
new file mode 100644
index 0000000..db672db
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_6.yaml.world.1.expect
@@ -0,0 +1,67 @@
+main = <No Member>;
+library from "org-dartlang-test:///libA.dart" as libA {
+
+  import "org-dartlang-test:///main.dart";
+
+  static method whatever(main::Foo* foo) → dynamic {
+    dart.core::print(foo);
+  }
+}
+library from "org-dartlang-test:///main.dart" as main {
+//
+// Problems in library:
+//
+// org-dartlang-test:///main.dart:7:32: Error: Expected ';' after this.
+//   toString() { return '$message' } // missing ;
+//                                ^
+//
+
+  import "org-dartlang-test:///libA.dart";
+
+  class Foo extends dart.core::Object {
+    final field dynamic message;
+    constructor •(dynamic message) → main::Foo*
+      : main::Foo::message = message, super dart.core::Object::•()
+      ;
+    @#C1
+    method toString() → dart.core::String* {
+      return "${this.{main::Foo::message}}";
+    }
+  }
+  class CompilationStrategy extends dart.core::Object {
+    final field dart.core::int* index;
+    final field dart.core::String* _name;
+    static const field dart.core::List<main::CompilationStrategy*>* values = #C14;
+    static const field main::CompilationStrategy* direct = #C4;
+    static const field main::CompilationStrategy* toKernel = #C7;
+    static const field main::CompilationStrategy* toData = #C10;
+    static const field main::CompilationStrategy* fromData = #C13;
+    const constructor •(dart.core::int* index, dart.core::String* _name) → main::CompilationStrategy*
+      : main::CompilationStrategy::index = index, main::CompilationStrategy::_name = _name, super dart.core::Object::•()
+      ;
+    method toString() → dart.core::String*
+      return this.{=main::CompilationStrategy::_name};
+  }
+  static method main() → dynamic {
+    main::Foo* foo = new main::Foo::•("hello");
+    libA::whatever(foo);
+    main::CompilationStrategy* compilationStrategy = #C4;
+    dart.core::print(compilationStrategy);
+  }
+}
+constants  {
+  #C1 = dart.core::_Override {}
+  #C2 = 0
+  #C3 = "CompilationStrategy.direct"
+  #C4 = main::CompilationStrategy {index:#C2, _name:#C3}
+  #C5 = 1
+  #C6 = "CompilationStrategy.toKernel"
+  #C7 = main::CompilationStrategy {index:#C5, _name:#C6}
+  #C8 = 2
+  #C9 = "CompilationStrategy.toData"
+  #C10 = main::CompilationStrategy {index:#C8, _name:#C9}
+  #C11 = 3
+  #C12 = "CompilationStrategy.fromData"
+  #C13 = main::CompilationStrategy {index:#C11, _name:#C12}
+  #C14 = <main::CompilationStrategy*>[#C4, #C7, #C10, #C13]
+}
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_6.yaml.world.2.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_6.yaml.world.2.expect
new file mode 100644
index 0000000..efb24e4
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_6.yaml.world.2.expect
@@ -0,0 +1,67 @@
+main = <No Member>;
+library from "org-dartlang-test:///libA.dart" as libA {
+
+  import "org-dartlang-test:///main.dart";
+
+  static method whatever(main::Foo* foo) → dynamic {
+    dart.core::print(foo);
+  }
+}
+library from "org-dartlang-test:///main.dart" as main {
+//
+// Problems in library:
+//
+// org-dartlang-test:///main.dart:7:32: Error: Expected ';' after this.
+//   toString() { return '$message!!!' } // missing ; still
+//                                ^^^^
+//
+
+  import "org-dartlang-test:///libA.dart";
+
+  class Foo extends dart.core::Object {
+    final field dynamic message;
+    constructor •(dynamic message) → main::Foo*
+      : main::Foo::message = message, super dart.core::Object::•()
+      ;
+    @#C1
+    method toString() → dart.core::String* {
+      return "${this.{main::Foo::message}}!!!";
+    }
+  }
+  class CompilationStrategy extends dart.core::Object {
+    final field dart.core::int* index;
+    final field dart.core::String* _name;
+    static const field dart.core::List<main::CompilationStrategy*>* values = #C14;
+    static const field main::CompilationStrategy* direct = #C4;
+    static const field main::CompilationStrategy* toKernel = #C7;
+    static const field main::CompilationStrategy* toData = #C10;
+    static const field main::CompilationStrategy* fromData = #C13;
+    const constructor •(dart.core::int* index, dart.core::String* _name) → main::CompilationStrategy*
+      : main::CompilationStrategy::index = index, main::CompilationStrategy::_name = _name, super dart.core::Object::•()
+      ;
+    method toString() → dart.core::String*
+      return this.{=main::CompilationStrategy::_name};
+  }
+  static method main() → dynamic {
+    main::Foo* foo = new main::Foo::•("hello");
+    libA::whatever(foo);
+    main::CompilationStrategy* compilationStrategy = #C4;
+    dart.core::print(compilationStrategy);
+  }
+}
+constants  {
+  #C1 = dart.core::_Override {}
+  #C2 = 0
+  #C3 = "CompilationStrategy.direct"
+  #C4 = main::CompilationStrategy {index:#C2, _name:#C3}
+  #C5 = 1
+  #C6 = "CompilationStrategy.toKernel"
+  #C7 = main::CompilationStrategy {index:#C5, _name:#C6}
+  #C8 = 2
+  #C9 = "CompilationStrategy.toData"
+  #C10 = main::CompilationStrategy {index:#C8, _name:#C9}
+  #C11 = 3
+  #C12 = "CompilationStrategy.fromData"
+  #C13 = main::CompilationStrategy {index:#C11, _name:#C12}
+  #C14 = <main::CompilationStrategy*>[#C4, #C7, #C10, #C13]
+}
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_6.yaml.world.3.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_6.yaml.world.3.expect
new file mode 100644
index 0000000..6872d26
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_6.yaml.world.3.expect
@@ -0,0 +1,60 @@
+main = <No Member>;
+library from "org-dartlang-test:///libA.dart" as libA {
+
+  import "org-dartlang-test:///main.dart";
+
+  static method whatever(main::Foo* foo) → dynamic {
+    dart.core::print(foo);
+  }
+}
+library from "org-dartlang-test:///main.dart" as main {
+
+  import "org-dartlang-test:///libA.dart";
+
+  class Foo extends dart.core::Object {
+    final field dynamic message;
+    constructor •(dynamic message) → main::Foo*
+      : main::Foo::message = message, super dart.core::Object::•()
+      ;
+    @#C1
+    method toString() → dart.core::String* {
+      return "${this.{main::Foo::message}}?!?";
+    }
+  }
+  class CompilationStrategy extends dart.core::Object {
+    final field dart.core::int* index;
+    final field dart.core::String* _name;
+    static const field dart.core::List<main::CompilationStrategy*>* values = #C14;
+    static const field main::CompilationStrategy* direct = #C4;
+    static const field main::CompilationStrategy* toKernel = #C7;
+    static const field main::CompilationStrategy* toData = #C10;
+    static const field main::CompilationStrategy* fromData = #C13;
+    const constructor •(dart.core::int* index, dart.core::String* _name) → main::CompilationStrategy*
+      : main::CompilationStrategy::index = index, main::CompilationStrategy::_name = _name, super dart.core::Object::•()
+      ;
+    method toString() → dart.core::String*
+      return this.{=main::CompilationStrategy::_name};
+  }
+  static method main() → dynamic {
+    main::Foo* foo = new main::Foo::•("hello");
+    libA::whatever(foo);
+    main::CompilationStrategy* compilationStrategy = #C4;
+    dart.core::print(compilationStrategy);
+  }
+}
+constants  {
+  #C1 = dart.core::_Override {}
+  #C2 = 0
+  #C3 = "CompilationStrategy.direct"
+  #C4 = main::CompilationStrategy {index:#C2, _name:#C3}
+  #C5 = 1
+  #C6 = "CompilationStrategy.toKernel"
+  #C7 = main::CompilationStrategy {index:#C5, _name:#C6}
+  #C8 = 2
+  #C9 = "CompilationStrategy.toData"
+  #C10 = main::CompilationStrategy {index:#C8, _name:#C9}
+  #C11 = 3
+  #C12 = "CompilationStrategy.fromData"
+  #C13 = main::CompilationStrategy {index:#C11, _name:#C12}
+  #C14 = <main::CompilationStrategy*>[#C4, #C7, #C10, #C13]
+}
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_7.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_7.yaml
new file mode 100644
index 0000000..701c6a7
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_7.yaml
@@ -0,0 +1,93 @@
+# Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE.md file.
+
+# Compile an application, change a file, but don't change the outline.
+
+type: newworld
+worlds:
+  - entry: main.dart
+    useExperimentalInvalidation: true
+    sources:
+      main.dart: |
+        import 'libA.dart';
+
+        const String useMeAsAnnotation = "hello";
+
+        @useMeAsAnnotation
+        class Bar {
+          @useMeAsAnnotation
+          Bar(@useMeAsAnnotation int x) {}
+        }
+
+        @useMeAsAnnotation
+        class Foo extends Bar {
+          @useMeAsAnnotation
+          final message;
+          @useMeAsAnnotation
+          Foo(@useMeAsAnnotation this.message) : super(42);
+          @override
+          toString() { return '$message'; }
+        }
+
+        @useMeAsAnnotation
+        main() {
+          @useMeAsAnnotation
+          Foo foo = new Foo("hello");
+          whatever(foo);
+          @useMeAsAnnotation
+          CompilationStrategy compilationStrategy = CompilationStrategy.direct;
+          print(compilationStrategy);
+        }
+
+        @useMeAsAnnotation
+        enum CompilationStrategy { @useMeAsAnnotation direct, @useMeAsAnnotation toKernel, @useMeAsAnnotation toData, @useMeAsAnnotation fromData }
+      libA.dart: |
+        import 'main.dart';
+        @useMeAsAnnotation
+        whatever(Foo foo) {
+          print(foo);
+        }
+    expectedLibraryCount: 2
+  - entry: main.dart
+    useExperimentalInvalidation: true
+    worldType: updated
+    expectInitializeFromDill: false
+    invalidate:
+      - main.dart
+    sources:
+      main.dart: |
+        import 'libA.dart';
+
+        const String useMeAsAnnotation = "hello";
+
+        @useMeAsAnnotation
+        class Bar {
+          @useMeAsAnnotation
+          Bar(@useMeAsAnnotation int x) {}
+        }
+
+        @useMeAsAnnotation
+        class Foo extends Bar {
+          @useMeAsAnnotation
+          final message;
+          @useMeAsAnnotation
+          Foo(@useMeAsAnnotation this.message) : super(42);
+          @override
+          toString() { return '$message'; }
+        }
+
+        @useMeAsAnnotation
+        main() {
+          @useMeAsAnnotation
+          Foo foo = new Foo("hello");
+          whatever(foo);
+          @useMeAsAnnotation
+          CompilationStrategy compilationStrategy = CompilationStrategy.direct;
+          print(compilationStrategy);
+        }
+
+        @useMeAsAnnotation
+        enum CompilationStrategy { @useMeAsAnnotation direct, @useMeAsAnnotation toKernel, @useMeAsAnnotation toData, @useMeAsAnnotation fromData }
+    expectedLibraryCount: 2
+    expectsRebuildBodiesOnly: true
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_7.yaml.world.1.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_7.yaml.world.1.expect
new file mode 100644
index 0000000..05b87bb
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_7.yaml.world.1.expect
@@ -0,0 +1,78 @@
+main = <No Member>;
+library from "org-dartlang-test:///libA.dart" as libA {
+
+  import "org-dartlang-test:///main.dart";
+
+  @#C1
+  static method whatever(main::Foo* foo) → dynamic {
+    dart.core::print(foo);
+  }
+}
+library from "org-dartlang-test:///main.dart" as main {
+
+  import "org-dartlang-test:///libA.dart";
+
+  @#C1
+  class Bar extends dart.core::Object {
+    @#C1
+    constructor •(@#C1 dart.core::int* x) → main::Bar*
+      : super dart.core::Object::•() {}
+  }
+  @#C1
+  class Foo extends main::Bar {
+    @#C1
+    final field dynamic message;
+    @#C1
+    constructor •(@#C1 dynamic message) → main::Foo*
+      : main::Foo::message = message, super main::Bar::•(42)
+      ;
+    @#C2
+    method toString() → dart.core::String* {
+      return "${this.{main::Foo::message}}";
+    }
+  }
+  @#C1
+  class CompilationStrategy extends dart.core::Object {
+    final field dart.core::int* index;
+    final field dart.core::String* _name;
+    static const field dart.core::List<main::CompilationStrategy*>* values = #C15;
+    @#C1
+    static const field main::CompilationStrategy* direct = #C5;
+    @#C1
+    static const field main::CompilationStrategy* toKernel = #C8;
+    @#C1
+    static const field main::CompilationStrategy* toData = #C11;
+    @#C1
+    static const field main::CompilationStrategy* fromData = #C14;
+    const constructor •(dart.core::int* index, dart.core::String* _name) → main::CompilationStrategy*
+      : main::CompilationStrategy::index = index, main::CompilationStrategy::_name = _name, super dart.core::Object::•()
+      ;
+    method toString() → dart.core::String*
+      return this.{=main::CompilationStrategy::_name};
+  }
+  static const field dart.core::String* useMeAsAnnotation = #C1;
+  @#C1
+  static method main() → dynamic {
+    @#C1 main::Foo* foo = new main::Foo::•("hello");
+    libA::whatever(foo);
+    @#C1 main::CompilationStrategy* compilationStrategy = #C5;
+    dart.core::print(compilationStrategy);
+  }
+}
+constants  {
+  #C1 = "hello"
+  #C2 = dart.core::_Override {}
+  #C3 = 0
+  #C4 = "CompilationStrategy.direct"
+  #C5 = main::CompilationStrategy {index:#C3, _name:#C4}
+  #C6 = 1
+  #C7 = "CompilationStrategy.toKernel"
+  #C8 = main::CompilationStrategy {index:#C6, _name:#C7}
+  #C9 = 2
+  #C10 = "CompilationStrategy.toData"
+  #C11 = main::CompilationStrategy {index:#C9, _name:#C10}
+  #C12 = 3
+  #C13 = "CompilationStrategy.fromData"
+  #C14 = main::CompilationStrategy {index:#C12, _name:#C13}
+  #C15 = <main::CompilationStrategy*>[#C5, #C8, #C11, #C14]
+}
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_7.yaml.world.2.expect b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_7.yaml.world.2.expect
new file mode 100644
index 0000000..05b87bb
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/no_outline_change_7.yaml.world.2.expect
@@ -0,0 +1,78 @@
+main = <No Member>;
+library from "org-dartlang-test:///libA.dart" as libA {
+
+  import "org-dartlang-test:///main.dart";
+
+  @#C1
+  static method whatever(main::Foo* foo) → dynamic {
+    dart.core::print(foo);
+  }
+}
+library from "org-dartlang-test:///main.dart" as main {
+
+  import "org-dartlang-test:///libA.dart";
+
+  @#C1
+  class Bar extends dart.core::Object {
+    @#C1
+    constructor •(@#C1 dart.core::int* x) → main::Bar*
+      : super dart.core::Object::•() {}
+  }
+  @#C1
+  class Foo extends main::Bar {
+    @#C1
+    final field dynamic message;
+    @#C1
+    constructor •(@#C1 dynamic message) → main::Foo*
+      : main::Foo::message = message, super main::Bar::•(42)
+      ;
+    @#C2
+    method toString() → dart.core::String* {
+      return "${this.{main::Foo::message}}";
+    }
+  }
+  @#C1
+  class CompilationStrategy extends dart.core::Object {
+    final field dart.core::int* index;
+    final field dart.core::String* _name;
+    static const field dart.core::List<main::CompilationStrategy*>* values = #C15;
+    @#C1
+    static const field main::CompilationStrategy* direct = #C5;
+    @#C1
+    static const field main::CompilationStrategy* toKernel = #C8;
+    @#C1
+    static const field main::CompilationStrategy* toData = #C11;
+    @#C1
+    static const field main::CompilationStrategy* fromData = #C14;
+    const constructor •(dart.core::int* index, dart.core::String* _name) → main::CompilationStrategy*
+      : main::CompilationStrategy::index = index, main::CompilationStrategy::_name = _name, super dart.core::Object::•()
+      ;
+    method toString() → dart.core::String*
+      return this.{=main::CompilationStrategy::_name};
+  }
+  static const field dart.core::String* useMeAsAnnotation = #C1;
+  @#C1
+  static method main() → dynamic {
+    @#C1 main::Foo* foo = new main::Foo::•("hello");
+    libA::whatever(foo);
+    @#C1 main::CompilationStrategy* compilationStrategy = #C5;
+    dart.core::print(compilationStrategy);
+  }
+}
+constants  {
+  #C1 = "hello"
+  #C2 = dart.core::_Override {}
+  #C3 = 0
+  #C4 = "CompilationStrategy.direct"
+  #C5 = main::CompilationStrategy {index:#C3, _name:#C4}
+  #C6 = 1
+  #C7 = "CompilationStrategy.toKernel"
+  #C8 = main::CompilationStrategy {index:#C6, _name:#C7}
+  #C9 = 2
+  #C10 = "CompilationStrategy.toData"
+  #C11 = main::CompilationStrategy {index:#C9, _name:#C10}
+  #C12 = 3
+  #C13 = "CompilationStrategy.fromData"
+  #C14 = main::CompilationStrategy {index:#C12, _name:#C13}
+  #C15 = <main::CompilationStrategy*>[#C5, #C8, #C11, #C14]
+}
diff --git a/pkg/front_end/testcases/inference/async_await.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/async_await.dart.strong.transformed.expect
index 07361ac..ecb9078 100644
--- a/pkg/front_end/testcases/inference/async_await.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/async_await.dart.strong.transformed.expect
@@ -2,6 +2,7 @@
 import self as self;
 import "dart:core" as core;
 import "dart:async" as asy;
+import "dart:_internal" as _in;
 
 import "dart:async";
 
@@ -16,7 +17,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   dynamic :saved_try_context_var0;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
@@ -39,7 +40,7 @@
           dynamic :async_stack_trace;
           dynamic :async_op_then;
           dynamic :async_op_error;
-          dynamic :await_jump_var = 0;
+          core::int* :await_jump_var = 0;
           dynamic :await_ctx_var;
           function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
             try {
@@ -66,7 +67,7 @@
           dynamic :async_stack_trace;
           dynamic :async_op_then;
           dynamic :async_op_error;
-          dynamic :await_jump_var = 0;
+          core::int* :await_jump_var = 0;
           dynamic :await_ctx_var;
           function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
             try {
@@ -93,7 +94,7 @@
           dynamic :async_stack_trace;
           dynamic :async_op_then;
           dynamic :async_op_error;
-          dynamic :await_jump_var = 0;
+          core::int* :await_jump_var = 0;
           dynamic :await_ctx_var;
           function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
             try {
@@ -120,7 +121,7 @@
           dynamic :async_stack_trace;
           dynamic :async_op_then;
           dynamic :async_op_error;
-          dynamic :await_jump_var = 0;
+          core::int* :await_jump_var = 0;
           dynamic :await_ctx_var;
           function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
             try {
@@ -147,7 +148,7 @@
           dynamic :async_stack_trace;
           dynamic :async_op_then;
           dynamic :async_op_error;
-          dynamic :await_jump_var = 0;
+          core::int* :await_jump_var = 0;
           dynamic :await_ctx_var;
           function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
             try {
@@ -174,7 +175,7 @@
           dynamic :async_stack_trace;
           dynamic :async_op_then;
           dynamic :async_op_error;
-          dynamic :await_jump_var = 0;
+          core::int* :await_jump_var = 0;
           dynamic :await_ctx_var;
           function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
             try {
@@ -201,7 +202,7 @@
           dynamic :async_stack_trace;
           dynamic :async_op_then;
           dynamic :async_op_error;
-          dynamic :await_jump_var = 0;
+          core::int* :await_jump_var = 0;
           dynamic :await_ctx_var;
           function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
             try {
@@ -228,7 +229,7 @@
           dynamic :async_stack_trace;
           dynamic :async_op_then;
           dynamic :async_op_error;
-          dynamic :await_jump_var = 0;
+          core::int* :await_jump_var = 0;
           dynamic :await_ctx_var;
           function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
             try {
@@ -255,7 +256,7 @@
           dynamic :async_stack_trace;
           dynamic :async_op_then;
           dynamic :async_op_error;
-          dynamic :await_jump_var = 0;
+          core::int* :await_jump_var = 0;
           dynamic :await_ctx_var;
           function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
             try {
@@ -282,7 +283,7 @@
           dynamic :async_stack_trace;
           dynamic :async_op_then;
           dynamic :async_op_error;
-          dynamic :await_jump_var = 0;
+          core::int* :await_jump_var = 0;
           dynamic :await_ctx_var;
           function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
             try {
@@ -304,25 +305,25 @@
           return :async_completer.{asy::Completer::future};
         }
         [yield] let dynamic #t1 = asy::_awaitHelper(x0, :async_op_then, :async_op_error, :async_op) in null;
-        core::int* y0 = :result;
+        core::int* y0 = _in::unsafeCast<core::int*>(:result);
         [yield] let dynamic #t2 = asy::_awaitHelper(x1, :async_op_then, :async_op_error, :async_op) in null;
-        core::int* y1 = :result;
+        core::int* y1 = _in::unsafeCast<core::int*>(:result);
         [yield] let dynamic #t3 = asy::_awaitHelper(x2, :async_op_then, :async_op_error, :async_op) in null;
-        asy::Future<core::int*>* y2 = :result;
+        asy::Future<core::int*>* y2 = _in::unsafeCast<asy::Future<core::int*>*>(:result);
         [yield] let dynamic #t4 = asy::_awaitHelper(x3, :async_op_then, :async_op_error, :async_op) in null;
-        asy::FutureOr<core::int*>* y3 = :result;
+        asy::FutureOr<core::int*>* y3 = _in::unsafeCast<asy::FutureOr<core::int*>*>(:result);
         [yield] let dynamic #t5 = asy::_awaitHelper(x4, :async_op_then, :async_op_error, :async_op) in null;
-        self::MyFuture* y4 = :result;
+        self::MyFuture* y4 = _in::unsafeCast<self::MyFuture*>(:result);
         [yield] let dynamic #t6 = asy::_awaitHelper(x5, :async_op_then, :async_op_error, :async_op) in null;
-        core::int* y5 = :result;
+        core::int* y5 = _in::unsafeCast<core::int*>(:result);
         [yield] let dynamic #t7 = asy::_awaitHelper(x6, :async_op_then, :async_op_error, :async_op) in null;
-        asy::Future<core::int*>* y6 = :result;
+        asy::Future<core::int*>* y6 = _in::unsafeCast<asy::Future<core::int*>*>(:result);
         [yield] let dynamic #t8 = asy::_awaitHelper(x7, :async_op_then, :async_op_error, :async_op) in null;
-        asy::FutureOr<core::int*>* y7 = :result;
+        asy::FutureOr<core::int*>* y7 = _in::unsafeCast<asy::FutureOr<core::int*>*>(:result);
         [yield] let dynamic #t9 = asy::_awaitHelper(x8, :async_op_then, :async_op_error, :async_op) in null;
-        self::MyFuture* y8 = :result;
+        self::MyFuture* y8 = _in::unsafeCast<self::MyFuture*>(:result);
         [yield] let dynamic #t10 = asy::_awaitHelper(x9, :async_op_then, :async_op_error, :async_op) in null;
-        core::int* y9 = :result;
+        core::int* y9 = _in::unsafeCast<core::int*>(:result);
       }
       asy::_completeOnAsyncReturn(:async_completer, :return_value);
       return;
diff --git a/pkg/front_end/testcases/inference/async_closure_return_type_flatten.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/async_closure_return_type_flatten.dart.strong.transformed.expect
index 2345aff..c587b4b 100644
--- a/pkg/front_end/testcases/inference/async_closure_return_type_flatten.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/async_closure_return_type_flatten.dart.strong.transformed.expect
@@ -13,7 +13,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
     try {
diff --git a/pkg/front_end/testcases/inference/async_closure_return_type_future.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/async_closure_return_type_future.dart.strong.transformed.expect
index 63abde7..69a4666 100644
--- a/pkg/front_end/testcases/inference/async_closure_return_type_future.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/async_closure_return_type_future.dart.strong.transformed.expect
@@ -9,7 +9,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
     try {
diff --git a/pkg/front_end/testcases/inference/async_closure_return_type_future_or.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/async_closure_return_type_future_or.dart.strong.transformed.expect
index 18510a2..13ab2d2 100644
--- a/pkg/front_end/testcases/inference/async_closure_return_type_future_or.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/async_closure_return_type_future_or.dart.strong.transformed.expect
@@ -13,7 +13,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
     try {
diff --git a/pkg/front_end/testcases/inference/block_bodied_lambdas_async_all_returns_are_futures.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/block_bodied_lambdas_async_all_returns_are_futures.dart.strong.transformed.expect
index 0ee4ee6..461478b 100644
--- a/pkg/front_end/testcases/inference/block_bodied_lambdas_async_all_returns_are_futures.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/block_bodied_lambdas_async_all_returns_are_futures.dart.strong.transformed.expect
@@ -14,7 +14,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
diff --git a/pkg/front_end/testcases/inference/block_bodied_lambdas_async_all_returns_are_values.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/block_bodied_lambdas_async_all_returns_are_values.dart.strong.transformed.expect
index 4c207d0..6675875 100644
--- a/pkg/front_end/testcases/inference/block_bodied_lambdas_async_all_returns_are_values.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/block_bodied_lambdas_async_all_returns_are_values.dart.strong.transformed.expect
@@ -14,7 +14,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
diff --git a/pkg/front_end/testcases/inference/block_bodied_lambdas_async_mix_of_values_and_futures.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/block_bodied_lambdas_async_mix_of_values_and_futures.dart.strong.transformed.expect
index 456e45d..83d4912 100644
--- a/pkg/front_end/testcases/inference/block_bodied_lambdas_async_mix_of_values_and_futures.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/block_bodied_lambdas_async_mix_of_values_and_futures.dart.strong.transformed.expect
@@ -14,7 +14,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
diff --git a/pkg/front_end/testcases/inference/block_bodied_lambdas_async_star.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/block_bodied_lambdas_async_star.dart.strong.transformed.expect
index 360b2cd..c640de2 100644
--- a/pkg/front_end/testcases/inference/block_bodied_lambdas_async_star.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/block_bodied_lambdas_async_star.dart.strong.transformed.expect
@@ -12,7 +12,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
     dynamic :saved_try_context_var1;
diff --git a/pkg/front_end/testcases/inference/block_bodied_lambdas_infer_bottom_async.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/block_bodied_lambdas_infer_bottom_async.dart.strong.transformed.expect
index e8faa37..72c0762 100644
--- a/pkg/front_end/testcases/inference/block_bodied_lambdas_infer_bottom_async.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/block_bodied_lambdas_infer_bottom_async.dart.strong.transformed.expect
@@ -2,6 +2,7 @@
 import self as self;
 import "dart:async" as asy;
 import "dart:core" as core;
+import "dart:_internal" as _in;
 
 import "dart:async";
 
@@ -11,7 +12,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   dynamic :saved_try_context_var0;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
@@ -24,7 +25,7 @@
           dynamic :async_stack_trace;
           dynamic :async_op_then;
           dynamic :async_op_error;
-          dynamic :await_jump_var = 0;
+          core::int* :await_jump_var = 0;
           dynamic :await_ctx_var;
           function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
             try {
@@ -48,7 +49,7 @@
         asy::Future<dynamic>* y = f.call();
         asy::Future<core::String*>* z = f.call();
         [yield] let dynamic #t1 = asy::_awaitHelper(f.call(), :async_op_then, :async_op_error, :async_op) in null;
-        core::String* s = :result;
+        core::String* s = _in::unsafeCast<core::Null?>(:result);
       }
       asy::_completeOnAsyncReturn(:async_completer, :return_value);
       return;
diff --git a/pkg/front_end/testcases/inference/block_bodied_lambdas_infer_bottom_async_star.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/block_bodied_lambdas_infer_bottom_async_star.dart.strong.transformed.expect
index ae912fe..c810580 100644
--- a/pkg/front_end/testcases/inference/block_bodied_lambdas_infer_bottom_async_star.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/block_bodied_lambdas_infer_bottom_async_star.dart.strong.transformed.expect
@@ -2,6 +2,7 @@
 import self as self;
 import "dart:async" as asy;
 import "dart:core" as core;
+import "dart:_internal" as _in;
 
 import "dart:async";
 
@@ -11,7 +12,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   dynamic :saved_try_context_var0;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
@@ -24,7 +25,7 @@
           dynamic :async_stack_trace;
           dynamic :async_op_then;
           dynamic :async_op_error;
-          dynamic :await_jump_var = 0;
+          core::int* :await_jump_var = 0;
           dynamic :await_ctx_var;
           dynamic :saved_try_context_var0;
           dynamic :saved_try_context_var1;
@@ -56,7 +57,7 @@
         asy::Stream<dynamic>* y = f.call();
         asy::Stream<core::String*>* z = f.call();
         [yield] let dynamic #t1 = asy::_awaitHelper(f.call().{asy::Stream::first}, :async_op_then, :async_op_error, :async_op) in null;
-        core::String* s = :result;
+        core::String* s = _in::unsafeCast<core::Null?>(:result);
       }
       asy::_completeOnAsyncReturn(:async_completer, :return_value);
       return;
diff --git a/pkg/front_end/testcases/inference/block_bodied_lambdas_infer_bottom_sync_star.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/block_bodied_lambdas_infer_bottom_sync_star.dart.strong.transformed.expect
index f94cf54..9a2c1650 100644
--- a/pkg/front_end/testcases/inference/block_bodied_lambdas_infer_bottom_sync_star.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/block_bodied_lambdas_infer_bottom_sync_star.dart.strong.transformed.expect
@@ -4,7 +4,7 @@
 
 static method main() → dynamic {
   () →* core::Iterable<core::Null?>* f = () → core::Iterable<core::Null?>* /* originally sync* */ {
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     function :sync_op(core::_SyncIterator<core::Null?>* :iterator) → core::bool* yielding {
       {
diff --git a/pkg/front_end/testcases/inference/block_bodied_lambdas_sync_star.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/block_bodied_lambdas_sync_star.dart.strong.transformed.expect
index f8df559..90b9e1e 100644
--- a/pkg/front_end/testcases/inference/block_bodied_lambdas_sync_star.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/block_bodied_lambdas_sync_star.dart.strong.transformed.expect
@@ -4,7 +4,7 @@
 
 static method test() → dynamic {
   () →* core::Iterable<core::num*>* f = () → core::Iterable<core::num*>* /* originally sync* */ {
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     function :sync_op(core::_SyncIterator<core::num*>* :iterator) → core::bool* yielding {
       {
diff --git a/pkg/front_end/testcases/inference/call_corner_cases.dart.strong.expect b/pkg/front_end/testcases/inference/call_corner_cases.dart.strong.expect
index c3a99bc..f5dbe06 100644
--- a/pkg/front_end/testcases/inference/call_corner_cases.dart.strong.expect
+++ b/pkg/front_end/testcases/inference/call_corner_cases.dart.strong.expect
@@ -42,11 +42,11 @@
   core::int* callA = new self::A::•().{self::A::call}();
   core::int* callFieldA = new self::D::•().{self::D::fieldA}();
   core::int* callGetA = new self::D::•().{self::D::getA}();
-  dynamic callFieldB = let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/inference/call_corner_cases.dart:27:71: Error: 'fieldB' isn't a function or method and can't be invoked.
+  dynamic callFieldB = invalid-expression "pkg/front_end/testcases/inference/call_corner_cases.dart:27:71: Error: 'fieldB' isn't a function or method and can't be invoked.
   var /*@ type=dynamic */ callFieldB = new D(). /*@target=D::fieldB*/ fieldB();
-                                                                      ^" in new self::D::•().{self::D::fieldB}();
-  dynamic callGetB = let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/inference/call_corner_cases.dart:28:67: Error: 'getB' isn't a function or method and can't be invoked.
+                                                                      ^";
+  dynamic callGetB = invalid-expression "pkg/front_end/testcases/inference/call_corner_cases.dart:28:67: Error: 'getB' isn't a function or method and can't be invoked.
   var /*@ type=dynamic */ callGetB = new D(). /*@target=D::getB*/ getB();
-                                                                  ^" in new self::D::•().{self::D::getB}();
+                                                                  ^";
 }
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/inference/call_corner_cases.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/call_corner_cases.dart.strong.transformed.expect
index c3a99bc..f5dbe06 100644
--- a/pkg/front_end/testcases/inference/call_corner_cases.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/call_corner_cases.dart.strong.transformed.expect
@@ -42,11 +42,11 @@
   core::int* callA = new self::A::•().{self::A::call}();
   core::int* callFieldA = new self::D::•().{self::D::fieldA}();
   core::int* callGetA = new self::D::•().{self::D::getA}();
-  dynamic callFieldB = let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/inference/call_corner_cases.dart:27:71: Error: 'fieldB' isn't a function or method and can't be invoked.
+  dynamic callFieldB = invalid-expression "pkg/front_end/testcases/inference/call_corner_cases.dart:27:71: Error: 'fieldB' isn't a function or method and can't be invoked.
   var /*@ type=dynamic */ callFieldB = new D(). /*@target=D::fieldB*/ fieldB();
-                                                                      ^" in new self::D::•().{self::D::fieldB}();
-  dynamic callGetB = let final<BottomType> #t2 = invalid-expression "pkg/front_end/testcases/inference/call_corner_cases.dart:28:67: Error: 'getB' isn't a function or method and can't be invoked.
+                                                                      ^";
+  dynamic callGetB = invalid-expression "pkg/front_end/testcases/inference/call_corner_cases.dart:28:67: Error: 'getB' isn't a function or method and can't be invoked.
   var /*@ type=dynamic */ callGetB = new D(). /*@target=D::getB*/ getB();
-                                                                  ^" in new self::D::•().{self::D::getB}();
+                                                                  ^";
 }
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/inference/downwards_inference_async_await.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/downwards_inference_async_await.dart.strong.transformed.expect
index bc89d37..947d113 100644
--- a/pkg/front_end/testcases/inference/downwards_inference_async_await.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/downwards_inference_async_await.dart.strong.transformed.expect
@@ -2,6 +2,7 @@
 import self as self;
 import "dart:async" as asy;
 import "dart:core" as core;
+import "dart:_internal" as _in;
 
 import "dart:async";
 
@@ -11,7 +12,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   dynamic :saved_try_context_var0;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
@@ -20,9 +21,9 @@
       {
         dynamic d;
         [yield] let dynamic #t1 = asy::_awaitHelper(<core::int*>[d as{TypeError} core::int*], :async_op_then, :async_op_error, :async_op) in null;
-        core::List<core::int*>* l0 = :result;
+        core::List<core::int*>* l0 = _in::unsafeCast<core::List<core::int*>*>(:result);
         [yield] let dynamic #t2 = asy::_awaitHelper(asy::Future::value<core::List<core::int*>*>(<core::int*>[d as{TypeError} core::int*]), :async_op_then, :async_op_error, :async_op) in null;
-        core::List<core::int*>* l1 = :result;
+        core::List<core::int*>* l1 = _in::unsafeCast<core::List<core::int*>*>(:result);
       }
       asy::_completeOnAsyncReturn(:async_completer, :return_value);
       return;
diff --git a/pkg/front_end/testcases/inference/downwards_inference_for_each.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/downwards_inference_for_each.dart.strong.transformed.expect
index c9450cf..95bdb47 100644
--- a/pkg/front_end/testcases/inference/downwards_inference_for_each.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/downwards_inference_for_each.dart.strong.transformed.expect
@@ -2,6 +2,7 @@
 import self as self;
 import "dart:core" as core;
 import "dart:async" as asy;
+import "dart:_internal" as _in;
 
 import "dart:async";
 
@@ -17,7 +18,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   dynamic :saved_try_context_var0;
   dynamic :saved_try_context_var1;
@@ -50,7 +51,7 @@
             while (true) {
               dynamic #t3 = asy::_asyncStarMoveNextHelper(:stream);
               [yield] let dynamic #t4 = asy::_awaitHelper(:for-iterator.{asy::_StreamIterator::moveNext}(), :async_op_then, :async_op_error, :async_op) in null;
-              if(:result) {
+              if(_in::unsafeCast<core::bool*>(:result)) {
                 dynamic x = :for-iterator.{asy::_StreamIterator::current};
                 {}
               }
@@ -72,7 +73,7 @@
             while (true) {
               dynamic #t6 = asy::_asyncStarMoveNextHelper(:stream);
               [yield] let dynamic #t7 = asy::_awaitHelper(:for-iterator.{asy::_StreamIterator::moveNext}(), :async_op_then, :async_op_error, :async_op) in null;
-              if(:result) {
+              if(_in::unsafeCast<core::bool*>(:result)) {
                 dynamic x = :for-iterator.{asy::_StreamIterator::current};
                 {}
               }
@@ -94,7 +95,7 @@
             while (true) {
               dynamic #t9 = asy::_asyncStarMoveNextHelper(:stream);
               [yield] let dynamic #t10 = asy::_awaitHelper(:for-iterator.{asy::_StreamIterator::moveNext}(), :async_op_then, :async_op_error, :async_op) in null;
-              if(:result) {
+              if(_in::unsafeCast<core::bool*>(:result)) {
                 core::Object* x = :for-iterator.{asy::_StreamIterator::current};
                 {}
               }
@@ -116,7 +117,7 @@
             while (true) {
               dynamic #t12 = asy::_asyncStarMoveNextHelper(:stream);
               [yield] let dynamic #t13 = asy::_awaitHelper(:for-iterator.{asy::_StreamIterator::moveNext}(), :async_op_then, :async_op_error, :async_op) in null;
-              if(:result) {
+              if(_in::unsafeCast<core::bool*>(:result)) {
                 final dynamic #t14 = :for-iterator.{asy::_StreamIterator::current};
                 {
                   d = #t14;
@@ -140,7 +141,7 @@
             while (true) {
               dynamic #t16 = asy::_asyncStarMoveNextHelper(:stream);
               [yield] let dynamic #t17 = asy::_awaitHelper(:for-iterator.{asy::_StreamIterator::moveNext}(), :async_op_then, :async_op_error, :async_op) in null;
-              if(:result) {
+              if(_in::unsafeCast<core::bool*>(:result)) {
                 final core::Object* #t18 = :for-iterator.{asy::_StreamIterator::current};
                 {
                   o = #t18;
@@ -174,7 +175,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   dynamic :saved_try_context_var0;
   dynamic :saved_try_context_var1;
@@ -199,7 +200,7 @@
             while (true) {
               dynamic #t20 = asy::_asyncStarMoveNextHelper(:stream);
               [yield] let dynamic #t21 = asy::_awaitHelper(:for-iterator.{asy::_StreamIterator::moveNext}(), :async_op_then, :async_op_error, :async_op) in null;
-              if(:result) {
+              if(_in::unsafeCast<core::bool*>(:result)) {
                 core::int* x = :for-iterator.{asy::_StreamIterator::current};
                 {}
               }
@@ -221,7 +222,7 @@
             while (true) {
               dynamic #t23 = asy::_asyncStarMoveNextHelper(:stream);
               [yield] let dynamic #t24 = asy::_awaitHelper(:for-iterator.{asy::_StreamIterator::moveNext}(), :async_op_then, :async_op_error, :async_op) in null;
-              if(:result) {
+              if(_in::unsafeCast<core::bool*>(:result)) {
                 core::int* x = :for-iterator.{asy::_StreamIterator::current};
                 {}
               }
diff --git a/pkg/front_end/testcases/inference/downwards_inference_on_list_literals_infer_if_value_types_match_context.dart.outline.expect b/pkg/front_end/testcases/inference/downwards_inference_on_list_literals_infer_if_value_types_match_context.dart.outline.expect
index 2fc00f4..ab7413c 100644
--- a/pkg/front_end/testcases/inference/downwards_inference_on_list_literals_infer_if_value_types_match_context.dart.outline.expect
+++ b/pkg/front_end/testcases/inference/downwards_inference_on_list_literals_infer_if_value_types_match_context.dart.outline.expect
@@ -3,7 +3,7 @@
 import "dart:core" as core;
 
 typedef Asserter<contravariant T extends core::Object* = dynamic> = (T*) →* void;
-typedef AsserterBuilder<contravariant S extends core::Object* = dynamic, unrelated T extends core::Object* = dynamic> = (S*) →* (T*) →* void;
+typedef AsserterBuilder<contravariant S extends core::Object* = dynamic, contravariant T extends core::Object* = dynamic> = (S*) →* (T*) →* void;
 class DartType extends core::Object {
   synthetic constructor •() → self::DartType*
     ;
diff --git a/pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart.strong.transformed.expect
index 0f46239..b784630 100644
--- a/pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/downwards_inference_yield_yield_star.dart.strong.transformed.expect
@@ -42,7 +42,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   dynamic :saved_try_context_var0;
   dynamic :saved_try_context_var1;
@@ -92,7 +92,7 @@
   return :controller_stream;
 }
 static method bar() → core::Iterable<core::Map<core::int*, core::int*>*>* /* originally sync* */ {
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   function :sync_op(core::_SyncIterator<core::Map<core::int*, core::int*>*>* :iterator) → core::bool* yielding {
     {
diff --git a/pkg/front_end/testcases/inference/dynamic_methods.dart.strong.expect b/pkg/front_end/testcases/inference/dynamic_methods.dart.strong.expect
index d2367f2..4ae05470 100644
--- a/pkg/front_end/testcases/inference/dynamic_methods.dart.strong.expect
+++ b/pkg/front_end/testcases/inference/dynamic_methods.dart.strong.expect
@@ -19,9 +19,9 @@
 static method test() → dynamic {
   dynamic d = new self::Foo::•();
   core::int* get_hashCode = d.{core::Object::hashCode};
-  dynamic call_hashCode = let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/inference/dynamic_methods.dart:16:39: Error: 'hashCode' isn't a function or method and can't be invoked.
+  dynamic call_hashCode = invalid-expression "pkg/front_end/testcases/inference/dynamic_methods.dart:16:39: Error: 'hashCode' isn't a function or method and can't be invoked.
       d. /*@target=Object::hashCode*/ hashCode();
-                                      ^" in d.{core::Object::hashCode}();
+                                      ^";
   core::String* call_toString = d.{core::Object::toString}();
   dynamic call_toStringArg = d.toString(color: "pink");
   dynamic call_foo0 = d.foo();
diff --git a/pkg/front_end/testcases/inference/dynamic_methods.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/dynamic_methods.dart.strong.transformed.expect
index d2367f2..4ae05470 100644
--- a/pkg/front_end/testcases/inference/dynamic_methods.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/dynamic_methods.dart.strong.transformed.expect
@@ -19,9 +19,9 @@
 static method test() → dynamic {
   dynamic d = new self::Foo::•();
   core::int* get_hashCode = d.{core::Object::hashCode};
-  dynamic call_hashCode = let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/inference/dynamic_methods.dart:16:39: Error: 'hashCode' isn't a function or method and can't be invoked.
+  dynamic call_hashCode = invalid-expression "pkg/front_end/testcases/inference/dynamic_methods.dart:16:39: Error: 'hashCode' isn't a function or method and can't be invoked.
       d. /*@target=Object::hashCode*/ hashCode();
-                                      ^" in d.{core::Object::hashCode}();
+                                      ^";
   core::String* call_toString = d.{core::Object::toString}();
   dynamic call_toStringArg = d.toString(color: "pink");
   dynamic call_foo0 = d.foo();
diff --git a/pkg/front_end/testcases/inference/for_each_downcast_iterable.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/for_each_downcast_iterable.dart.strong.transformed.expect
index fb79f44..1e3cd61 100644
--- a/pkg/front_end/testcases/inference/for_each_downcast_iterable.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/for_each_downcast_iterable.dart.strong.transformed.expect
@@ -2,6 +2,7 @@
 import self as self;
 import "dart:async" as asy;
 import "dart:core" as core;
+import "dart:_internal" as _in;
 
 static method test() → dynamic /* originally async */ {
   final asy::_AsyncAwaitCompleter<dynamic>* :async_completer = new asy::_AsyncAwaitCompleter::•<dynamic>();
@@ -9,7 +10,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   dynamic :saved_try_context_var0;
   dynamic :saved_try_context_var1;
@@ -31,7 +32,7 @@
             while (true) {
               dynamic #t1 = asy::_asyncStarMoveNextHelper(:stream);
               [yield] let dynamic #t2 = asy::_awaitHelper(:for-iterator.{asy::_StreamIterator::moveNext}(), :async_op_then, :async_op_error, :async_op) in null;
-              if(:result) {
+              if(_in::unsafeCast<core::bool*>(:result)) {
                 dynamic x = :for-iterator.{asy::_StreamIterator::current};
                 {}
               }
@@ -57,7 +58,7 @@
             while (true) {
               dynamic #t5 = asy::_asyncStarMoveNextHelper(:stream);
               [yield] let dynamic #t6 = asy::_awaitHelper(:for-iterator.{asy::_StreamIterator::moveNext}(), :async_op_then, :async_op_error, :async_op) in null;
-              if(:result) {
+              if(_in::unsafeCast<core::bool*>(:result)) {
                 final dynamic #t7 = :for-iterator.{asy::_StreamIterator::current};
                 {
                   y = #t7 as{TypeError} core::int*;
diff --git a/pkg/front_end/testcases/inference/future_then.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/future_then.dart.strong.transformed.expect
index f53682d..8aa7e82 100644
--- a/pkg/front_end/testcases/inference/future_then.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/future_then.dart.strong.transformed.expect
@@ -2,6 +2,7 @@
 import self as self;
 import "dart:core" as core;
 import "dart:async" as asy;
+import "dart:_internal" as _in;
 
 import "dart:async";
 
@@ -31,7 +32,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
@@ -39,7 +40,7 @@
         #L1:
         {
           [yield] let dynamic #t1 = asy::_awaitHelper(asy::Future::value<core::int*>(3), :async_op_then, :async_op_error, :async_op) in null;
-          :return_value = :result;
+          :return_value = _in::unsafeCast<core::int*>(:result);
           break #L1;
         }
         asy::_completeOnAsyncReturn(:async_completer, :return_value);
@@ -60,7 +61,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
@@ -68,7 +69,7 @@
         #L2:
         {
           [yield] let dynamic #t2 = asy::_awaitHelper(asy::Future::value<core::int*>(3), :async_op_then, :async_op_error, :async_op) in null;
-          :return_value = :result;
+          :return_value = _in::unsafeCast<core::int*>(:result);
           break #L2;
         }
         asy::_completeOnAsyncReturn(:async_completer, :return_value);
@@ -89,7 +90,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
@@ -116,7 +117,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
@@ -147,7 +148,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
@@ -174,7 +175,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
diff --git a/pkg/front_end/testcases/inference/future_then_2.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/future_then_2.dart.strong.transformed.expect
index b43b873..1e87f8a 100644
--- a/pkg/front_end/testcases/inference/future_then_2.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/future_then_2.dart.strong.transformed.expect
@@ -2,6 +2,7 @@
 import self as self;
 import "dart:core" as core;
 import "dart:async" as asy;
+import "dart:_internal" as _in;
 
 import "dart:async";
 
@@ -31,7 +32,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
@@ -39,7 +40,7 @@
         #L1:
         {
           [yield] let dynamic #t1 = asy::_awaitHelper(new self::MyFuture::value<core::int*>(3), :async_op_then, :async_op_error, :async_op) in null;
-          :return_value = :result;
+          :return_value = _in::unsafeCast<core::int*>(:result);
           break #L1;
         }
         asy::_completeOnAsyncReturn(:async_completer, :return_value);
@@ -60,7 +61,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
@@ -68,7 +69,7 @@
         #L2:
         {
           [yield] let dynamic #t2 = asy::_awaitHelper(new self::MyFuture::value<core::int*>(3), :async_op_then, :async_op_error, :async_op) in null;
-          :return_value = :result;
+          :return_value = _in::unsafeCast<core::int*>(:result);
           break #L2;
         }
         asy::_completeOnAsyncReturn(:async_completer, :return_value);
@@ -89,7 +90,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
@@ -116,7 +117,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
@@ -147,7 +148,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
@@ -174,7 +175,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
diff --git a/pkg/front_end/testcases/inference/future_then_3.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/future_then_3.dart.strong.transformed.expect
index 60990e7..df9aa51 100644
--- a/pkg/front_end/testcases/inference/future_then_3.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/future_then_3.dart.strong.transformed.expect
@@ -2,6 +2,7 @@
 import self as self;
 import "dart:core" as core;
 import "dart:async" as asy;
+import "dart:_internal" as _in;
 
 import "dart:async";
 
@@ -31,7 +32,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
@@ -39,7 +40,7 @@
         #L1:
         {
           [yield] let dynamic #t1 = asy::_awaitHelper(asy::Future::value<core::int*>(3), :async_op_then, :async_op_error, :async_op) in null;
-          :return_value = :result;
+          :return_value = _in::unsafeCast<core::int*>(:result);
           break #L1;
         }
         asy::_completeOnAsyncReturn(:async_completer, :return_value);
@@ -60,7 +61,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
@@ -68,7 +69,7 @@
         #L2:
         {
           [yield] let dynamic #t2 = asy::_awaitHelper(asy::Future::value<core::int*>(3), :async_op_then, :async_op_error, :async_op) in null;
-          :return_value = :result;
+          :return_value = _in::unsafeCast<core::int*>(:result);
           break #L2;
         }
         asy::_completeOnAsyncReturn(:async_completer, :return_value);
@@ -89,7 +90,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
@@ -116,7 +117,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
@@ -147,7 +148,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
@@ -174,7 +175,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
diff --git a/pkg/front_end/testcases/inference/future_then_4.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/future_then_4.dart.strong.transformed.expect
index 8125700..c349f97 100644
--- a/pkg/front_end/testcases/inference/future_then_4.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/future_then_4.dart.strong.transformed.expect
@@ -2,6 +2,7 @@
 import self as self;
 import "dart:core" as core;
 import "dart:async" as asy;
+import "dart:_internal" as _in;
 
 import "dart:async";
 
@@ -31,7 +32,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
@@ -39,7 +40,7 @@
         #L1:
         {
           [yield] let dynamic #t1 = asy::_awaitHelper(new self::MyFuture::value<core::int*>(3), :async_op_then, :async_op_error, :async_op) in null;
-          :return_value = :result;
+          :return_value = _in::unsafeCast<core::int*>(:result);
           break #L1;
         }
         asy::_completeOnAsyncReturn(:async_completer, :return_value);
@@ -60,7 +61,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
@@ -68,7 +69,7 @@
         #L2:
         {
           [yield] let dynamic #t2 = asy::_awaitHelper(new self::MyFuture::value<core::int*>(3), :async_op_then, :async_op_error, :async_op) in null;
-          :return_value = :result;
+          :return_value = _in::unsafeCast<core::int*>(:result);
           break #L2;
         }
         asy::_completeOnAsyncReturn(:async_completer, :return_value);
@@ -89,7 +90,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
@@ -116,7 +117,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
@@ -147,7 +148,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
@@ -174,7 +175,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
diff --git a/pkg/front_end/testcases/inference/future_then_5.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/future_then_5.dart.strong.transformed.expect
index 6e1684b..1afc871 100644
--- a/pkg/front_end/testcases/inference/future_then_5.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/future_then_5.dart.strong.transformed.expect
@@ -2,6 +2,7 @@
 import self as self;
 import "dart:core" as core;
 import "dart:async" as asy;
+import "dart:_internal" as _in;
 
 import "dart:async";
 
@@ -31,7 +32,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
@@ -39,7 +40,7 @@
         #L1:
         {
           [yield] let dynamic #t1 = asy::_awaitHelper(new self::MyFuture::value<core::int*>(3), :async_op_then, :async_op_error, :async_op) in null;
-          :return_value = :result;
+          :return_value = _in::unsafeCast<core::int*>(:result);
           break #L1;
         }
         asy::_completeOnAsyncReturn(:async_completer, :return_value);
@@ -60,7 +61,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
@@ -68,7 +69,7 @@
         #L2:
         {
           [yield] let dynamic #t2 = asy::_awaitHelper(new self::MyFuture::value<core::int*>(3), :async_op_then, :async_op_error, :async_op) in null;
-          :return_value = :result;
+          :return_value = _in::unsafeCast<core::int*>(:result);
           break #L2;
         }
         asy::_completeOnAsyncReturn(:async_completer, :return_value);
@@ -89,7 +90,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
@@ -116,7 +117,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
@@ -147,7 +148,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
@@ -174,7 +175,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
diff --git a/pkg/front_end/testcases/inference/future_then_6.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/future_then_6.dart.strong.transformed.expect
index 5a87ad0..9731f3b 100644
--- a/pkg/front_end/testcases/inference/future_then_6.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/future_then_6.dart.strong.transformed.expect
@@ -2,6 +2,7 @@
 import self as self;
 import "dart:core" as core;
 import "dart:async" as asy;
+import "dart:_internal" as _in;
 
 import "dart:async";
 
@@ -31,7 +32,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
@@ -39,7 +40,7 @@
         #L1:
         {
           [yield] let dynamic #t1 = asy::_awaitHelper(asy::Future::value<core::int*>(3), :async_op_then, :async_op_error, :async_op) in null;
-          :return_value = :result;
+          :return_value = _in::unsafeCast<core::int*>(:result);
           break #L1;
         }
         asy::_completeOnAsyncReturn(:async_completer, :return_value);
@@ -60,7 +61,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
@@ -68,7 +69,7 @@
         #L2:
         {
           [yield] let dynamic #t2 = asy::_awaitHelper(asy::Future::value<core::int*>(3), :async_op_then, :async_op_error, :async_op) in null;
-          :return_value = :result;
+          :return_value = _in::unsafeCast<core::int*>(:result);
           break #L2;
         }
         asy::_completeOnAsyncReturn(:async_completer, :return_value);
@@ -89,7 +90,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
@@ -116,7 +117,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
@@ -147,7 +148,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
@@ -174,7 +175,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
diff --git a/pkg/front_end/testcases/inference/future_then_conditional.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/future_then_conditional.dart.strong.transformed.expect
index c15d6b6..5abd329 100644
--- a/pkg/front_end/testcases/inference/future_then_conditional.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/future_then_conditional.dart.strong.transformed.expect
@@ -2,6 +2,7 @@
 import self as self;
 import "dart:core" as core;
 import "dart:async" as asy;
+import "dart:_internal" as _in;
 
 import "dart:async";
 
@@ -31,10 +32,10 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
-    dynamic :async_temporary_0;
+    core::int* :async_temporary_0;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
         #L1:
@@ -44,7 +45,7 @@
           }
           else {
             [yield] let dynamic #t1 = asy::_awaitHelper(asy::Future::value<core::int*>(3), :async_op_then, :async_op_error, :async_op) in null;
-            :async_temporary_0 = :result;
+            :async_temporary_0 = _in::unsafeCast<core::int*>(:result);
           }
           :return_value = :async_temporary_0;
           break #L1;
@@ -67,7 +68,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
@@ -75,7 +76,7 @@
         #L2:
         {
           [yield] let dynamic #t2 = asy::_awaitHelper(x, :async_op_then, :async_op_error, :async_op) in null;
-          :return_value = (:result ?{core::Object*} 2 : asy::Future::value<core::int*>(3)) as{TypeError} asy::FutureOr<core::int*>*;
+          :return_value = (_in::unsafeCast<core::bool*>(:result) ?{core::Object*} 2 : asy::Future::value<core::int*>(3)) as{TypeError} asy::FutureOr<core::int*>*;
           break #L2;
         }
         asy::_completeOnAsyncReturn(:async_completer, :return_value);
diff --git a/pkg/front_end/testcases/inference/future_then_conditional_2.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/future_then_conditional_2.dart.strong.transformed.expect
index c3baf4e..852ab83 100644
--- a/pkg/front_end/testcases/inference/future_then_conditional_2.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/future_then_conditional_2.dart.strong.transformed.expect
@@ -2,6 +2,7 @@
 import self as self;
 import "dart:core" as core;
 import "dart:async" as asy;
+import "dart:_internal" as _in;
 
 import "dart:async";
 
@@ -31,10 +32,10 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
-    dynamic :async_temporary_0;
+    core::int* :async_temporary_0;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
         #L1:
@@ -44,7 +45,7 @@
           }
           else {
             [yield] let dynamic #t1 = asy::_awaitHelper(new self::MyFuture::value<core::int*>(3), :async_op_then, :async_op_error, :async_op) in null;
-            :async_temporary_0 = :result;
+            :async_temporary_0 = _in::unsafeCast<core::int*>(:result);
           }
           :return_value = :async_temporary_0;
           break #L1;
@@ -67,7 +68,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
@@ -75,7 +76,7 @@
         #L2:
         {
           [yield] let dynamic #t2 = asy::_awaitHelper(x, :async_op_then, :async_op_error, :async_op) in null;
-          :return_value = (:result ?{core::Object*} 2 : new self::MyFuture::value<core::int*>(3)) as{TypeError} asy::FutureOr<core::int*>*;
+          :return_value = (_in::unsafeCast<core::bool*>(:result) ?{core::Object*} 2 : new self::MyFuture::value<core::int*>(3)) as{TypeError} asy::FutureOr<core::int*>*;
           break #L2;
         }
         asy::_completeOnAsyncReturn(:async_completer, :return_value);
diff --git a/pkg/front_end/testcases/inference/future_then_conditional_3.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/future_then_conditional_3.dart.strong.transformed.expect
index a1e0911..56e7a58 100644
--- a/pkg/front_end/testcases/inference/future_then_conditional_3.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/future_then_conditional_3.dart.strong.transformed.expect
@@ -2,6 +2,7 @@
 import self as self;
 import "dart:core" as core;
 import "dart:async" as asy;
+import "dart:_internal" as _in;
 
 import "dart:async";
 
@@ -31,10 +32,10 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
-    dynamic :async_temporary_0;
+    core::int* :async_temporary_0;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
         #L1:
@@ -44,7 +45,7 @@
           }
           else {
             [yield] let dynamic #t1 = asy::_awaitHelper(asy::Future::value<core::int*>(3), :async_op_then, :async_op_error, :async_op) in null;
-            :async_temporary_0 = :result;
+            :async_temporary_0 = _in::unsafeCast<core::int*>(:result);
           }
           :return_value = :async_temporary_0;
           break #L1;
@@ -67,7 +68,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
@@ -75,7 +76,7 @@
         #L2:
         {
           [yield] let dynamic #t2 = asy::_awaitHelper(x, :async_op_then, :async_op_error, :async_op) in null;
-          :return_value = (:result ?{core::Object*} 2 : asy::Future::value<core::int*>(3)) as{TypeError} asy::FutureOr<core::int*>*;
+          :return_value = (_in::unsafeCast<core::bool*>(:result) ?{core::Object*} 2 : asy::Future::value<core::int*>(3)) as{TypeError} asy::FutureOr<core::int*>*;
           break #L2;
         }
         asy::_completeOnAsyncReturn(:async_completer, :return_value);
diff --git a/pkg/front_end/testcases/inference/future_then_conditional_4.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/future_then_conditional_4.dart.strong.transformed.expect
index 0ee0ff4..8009681 100644
--- a/pkg/front_end/testcases/inference/future_then_conditional_4.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/future_then_conditional_4.dart.strong.transformed.expect
@@ -2,6 +2,7 @@
 import self as self;
 import "dart:core" as core;
 import "dart:async" as asy;
+import "dart:_internal" as _in;
 
 import "dart:async";
 
@@ -31,10 +32,10 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
-    dynamic :async_temporary_0;
+    core::int* :async_temporary_0;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
         #L1:
@@ -44,7 +45,7 @@
           }
           else {
             [yield] let dynamic #t1 = asy::_awaitHelper(new self::MyFuture::value<core::int*>(3), :async_op_then, :async_op_error, :async_op) in null;
-            :async_temporary_0 = :result;
+            :async_temporary_0 = _in::unsafeCast<core::int*>(:result);
           }
           :return_value = :async_temporary_0;
           break #L1;
@@ -67,7 +68,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
@@ -75,7 +76,7 @@
         #L2:
         {
           [yield] let dynamic #t2 = asy::_awaitHelper(x, :async_op_then, :async_op_error, :async_op) in null;
-          :return_value = (:result ?{core::Object*} 2 : new self::MyFuture::value<core::int*>(3)) as{TypeError} asy::FutureOr<core::int*>*;
+          :return_value = (_in::unsafeCast<core::bool*>(:result) ?{core::Object*} 2 : new self::MyFuture::value<core::int*>(3)) as{TypeError} asy::FutureOr<core::int*>*;
           break #L2;
         }
         asy::_completeOnAsyncReturn(:async_completer, :return_value);
diff --git a/pkg/front_end/testcases/inference/future_then_conditional_5.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/future_then_conditional_5.dart.strong.transformed.expect
index 71a707c..9cda589 100644
--- a/pkg/front_end/testcases/inference/future_then_conditional_5.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/future_then_conditional_5.dart.strong.transformed.expect
@@ -2,6 +2,7 @@
 import self as self;
 import "dart:core" as core;
 import "dart:async" as asy;
+import "dart:_internal" as _in;
 
 import "dart:async";
 
@@ -31,10 +32,10 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
-    dynamic :async_temporary_0;
+    core::int* :async_temporary_0;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
         #L1:
@@ -44,7 +45,7 @@
           }
           else {
             [yield] let dynamic #t1 = asy::_awaitHelper(new self::MyFuture::value<core::int*>(3), :async_op_then, :async_op_error, :async_op) in null;
-            :async_temporary_0 = :result;
+            :async_temporary_0 = _in::unsafeCast<core::int*>(:result);
           }
           :return_value = :async_temporary_0;
           break #L1;
@@ -67,7 +68,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
@@ -75,7 +76,7 @@
         #L2:
         {
           [yield] let dynamic #t2 = asy::_awaitHelper(x, :async_op_then, :async_op_error, :async_op) in null;
-          :return_value = (:result ?{core::Object*} 2 : new self::MyFuture::value<core::int*>(3)) as{TypeError} asy::FutureOr<core::int*>*;
+          :return_value = (_in::unsafeCast<core::bool*>(:result) ?{core::Object*} 2 : new self::MyFuture::value<core::int*>(3)) as{TypeError} asy::FutureOr<core::int*>*;
           break #L2;
         }
         asy::_completeOnAsyncReturn(:async_completer, :return_value);
diff --git a/pkg/front_end/testcases/inference/future_then_conditional_6.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/future_then_conditional_6.dart.strong.transformed.expect
index 7cdb74e..50485af 100644
--- a/pkg/front_end/testcases/inference/future_then_conditional_6.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/future_then_conditional_6.dart.strong.transformed.expect
@@ -2,6 +2,7 @@
 import self as self;
 import "dart:core" as core;
 import "dart:async" as asy;
+import "dart:_internal" as _in;
 
 import "dart:async";
 
@@ -31,10 +32,10 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
-    dynamic :async_temporary_0;
+    core::int* :async_temporary_0;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
         #L1:
@@ -44,7 +45,7 @@
           }
           else {
             [yield] let dynamic #t1 = asy::_awaitHelper(asy::Future::value<core::int*>(3), :async_op_then, :async_op_error, :async_op) in null;
-            :async_temporary_0 = :result;
+            :async_temporary_0 = _in::unsafeCast<core::int*>(:result);
           }
           :return_value = :async_temporary_0;
           break #L1;
@@ -67,7 +68,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
@@ -75,7 +76,7 @@
         #L2:
         {
           [yield] let dynamic #t2 = asy::_awaitHelper(x, :async_op_then, :async_op_error, :async_op) in null;
-          :return_value = (:result ?{core::Object*} 2 : asy::Future::value<core::int*>(3)) as{TypeError} asy::FutureOr<core::int*>*;
+          :return_value = (_in::unsafeCast<core::bool*>(:result) ?{core::Object*} 2 : asy::Future::value<core::int*>(3)) as{TypeError} asy::FutureOr<core::int*>*;
           break #L2;
         }
         asy::_completeOnAsyncReturn(:async_completer, :return_value);
diff --git a/pkg/front_end/testcases/inference/future_then_ifNull.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/future_then_ifNull.dart.strong.transformed.expect
index 49ce857..760de92 100644
--- a/pkg/front_end/testcases/inference/future_then_ifNull.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/future_then_ifNull.dart.strong.transformed.expect
@@ -2,6 +2,7 @@
 import self as self;
 import "dart:core" as core;
 import "dart:async" as asy;
+import "dart:_internal" as _in;
 
 import "dart:async";
 
@@ -31,10 +32,10 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
-    dynamic :async_temporary_0;
+    core::int* :async_temporary_0;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
         #L1:
@@ -42,7 +43,7 @@
           final core::int* #t1 = x;
           if(#t1.{core::num::==}(null)) {
             [yield] let dynamic #t2 = asy::_awaitHelper(asy::Future::value<core::int*>(3), :async_op_then, :async_op_error, :async_op) in null;
-            :async_temporary_0 = :result;
+            :async_temporary_0 = _in::unsafeCast<core::int*>(:result);
           }
           else {
             :async_temporary_0 = #t1;
@@ -68,7 +69,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
@@ -76,7 +77,7 @@
         #L2:
         {
           [yield] let dynamic #t3 = asy::_awaitHelper(x, :async_op_then, :async_op_error, :async_op) in null;
-          :return_value = (let final core::int* #t4 = :result in #t4.{core::num::==}(null) ?{core::Object*} asy::Future::value<core::int*>(3) : #t4) as{TypeError} asy::FutureOr<core::int*>*;
+          :return_value = (let final core::int* #t4 = _in::unsafeCast<core::int*>(:result) in #t4.{core::num::==}(null) ?{core::Object*} asy::Future::value<core::int*>(3) : #t4) as{TypeError} asy::FutureOr<core::int*>*;
           break #L2;
         }
         asy::_completeOnAsyncReturn(:async_completer, :return_value);
diff --git a/pkg/front_end/testcases/inference/future_union_async_conditional.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/future_union_async_conditional.dart.strong.transformed.expect
index 0c94989..4f29e0f 100644
--- a/pkg/front_end/testcases/inference/future_union_async_conditional.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/future_union_async_conditional.dart.strong.transformed.expect
@@ -29,7 +29,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
     try {
@@ -56,7 +56,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
     try {
@@ -83,7 +83,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
     try {
diff --git a/pkg/front_end/testcases/inference/future_union_async_conditional_2.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/future_union_async_conditional_2.dart.strong.transformed.expect
index 8d24cfe..46ac20c 100644
--- a/pkg/front_end/testcases/inference/future_union_async_conditional_2.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/future_union_async_conditional_2.dart.strong.transformed.expect
@@ -29,7 +29,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
     try {
@@ -56,7 +56,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
     try {
@@ -83,7 +83,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
     try {
diff --git a/pkg/front_end/testcases/inference/future_union_downwards.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/future_union_downwards.dart.strong.transformed.expect
index 873f587..2819009 100644
--- a/pkg/front_end/testcases/inference/future_union_downwards.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/future_union_downwards.dart.strong.transformed.expect
@@ -43,7 +43,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
     try {
@@ -70,7 +70,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
     try {
diff --git a/pkg/front_end/testcases/inference/future_union_downwards_2.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/future_union_downwards_2.dart.strong.transformed.expect
index 5d28067..e4688e7 100644
--- a/pkg/front_end/testcases/inference/future_union_downwards_2.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/future_union_downwards_2.dart.strong.transformed.expect
@@ -32,7 +32,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
     try {
@@ -59,7 +59,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
     try {
diff --git a/pkg/front_end/testcases/inference/future_union_downwards_3.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/future_union_downwards_3.dart.strong.transformed.expect
index af242e2..daeed90 100644
--- a/pkg/front_end/testcases/inference/future_union_downwards_3.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/future_union_downwards_3.dart.strong.transformed.expect
@@ -43,7 +43,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
     try {
@@ -70,7 +70,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
     try {
diff --git a/pkg/front_end/testcases/inference/future_union_downwards_4.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/future_union_downwards_4.dart.strong.transformed.expect
index 675a8a6..7bd9b40 100644
--- a/pkg/front_end/testcases/inference/future_union_downwards_4.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/future_union_downwards_4.dart.strong.transformed.expect
@@ -32,7 +32,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
     try {
@@ -59,7 +59,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
     try {
diff --git a/pkg/front_end/testcases/inference/future_union_downwards_generic_method_with_future_return.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/future_union_downwards_generic_method_with_future_return.dart.strong.transformed.expect
index 4ec9a21..69f42e3 100644
--- a/pkg/front_end/testcases/inference/future_union_downwards_generic_method_with_future_return.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/future_union_downwards_generic_method_with_future_return.dart.strong.transformed.expect
@@ -2,6 +2,7 @@
 import self as self;
 import "dart:core" as core;
 import "dart:async" as asy;
+import "dart:_internal" as _in;
 
 import "dart:async";
 
@@ -16,7 +17,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   dynamic :saved_try_context_var0;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
@@ -26,7 +27,7 @@
         asy::Future<core::List<self::A*>*>* f1 = null;
         asy::Future<core::List<self::A*>*>* f2 = null;
         [yield] let dynamic #t1 = asy::_awaitHelper(asy::Future::wait<core::List<self::A*>*>(<asy::Future<core::List<self::A*>*>*>[f1, f2]), :async_op_then, :async_op_error, :async_op) in null;
-        core::List<core::List<self::A*>*>* merged = :result;
+        core::List<core::List<self::A*>*>* merged = _in::unsafeCast<core::List<core::List<self::A*>*>*>(:result);
       }
       asy::_completeOnAsyncReturn(:async_completer, :return_value);
       return;
diff --git a/pkg/front_end/testcases/inference/future_union_downwards_generic_method_with_generic_return.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/future_union_downwards_generic_method_with_generic_return.dart.strong.transformed.expect
index 671564f..ce99844 100644
--- a/pkg/front_end/testcases/inference/future_union_downwards_generic_method_with_generic_return.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/future_union_downwards_generic_method_with_generic_return.dart.strong.transformed.expect
@@ -2,6 +2,7 @@
 import self as self;
 import "dart:core" as core;
 import "dart:async" as asy;
+import "dart:_internal" as _in;
 
 import "dart:async";
 
@@ -13,7 +14,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   dynamic :saved_try_context_var0;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
@@ -22,7 +23,7 @@
       {
         asy::Future<core::String*>* f;
         [yield] let dynamic #t1 = asy::_awaitHelper(self::id<asy::FutureOr<core::String*>*>(f), :async_op_then, :async_op_error, :async_op) in null;
-        core::String* s = :result;
+        core::String* s = _in::unsafeCast<core::String*>(:result);
       }
       asy::_completeOnAsyncReturn(:async_completer, :return_value);
       return;
diff --git a/pkg/front_end/testcases/inference/future_union_upwards_generic_methods.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/future_union_upwards_generic_methods.dart.strong.transformed.expect
index 0ae7eb2..c71cd17 100644
--- a/pkg/front_end/testcases/inference/future_union_upwards_generic_methods.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/future_union_upwards_generic_methods.dart.strong.transformed.expect
@@ -2,6 +2,7 @@
 import self as self;
 import "dart:core" as core;
 import "dart:async" as asy;
+import "dart:_internal" as _in;
 
 import "dart:async";
 
@@ -26,7 +27,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   dynamic :saved_try_context_var0;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
@@ -37,9 +38,9 @@
         asy::Future<self::C*>* c = asy::Future::value<self::C*>(new self::C::•());
         core::List<asy::Future<self::A*>*>* lll = <asy::Future<self::A*>*>[b, c];
         [yield] let dynamic #t1 = asy::_awaitHelper(asy::Future::wait<self::A*>(lll), :async_op_then, :async_op_error, :async_op) in null;
-        core::List<self::A*>* result = :result;
+        core::List<self::A*>* result = _in::unsafeCast<core::List<self::A*>*>(:result);
         [yield] let dynamic #t2 = asy::_awaitHelper(asy::Future::wait<self::A*>(<asy::Future<self::A*>*>[b, c]), :async_op_then, :async_op_error, :async_op) in null;
-        core::List<self::A*>* result2 = :result;
+        core::List<self::A*>* result2 = _in::unsafeCast<core::List<self::A*>*>(:result);
         core::List<self::A*>* list = result;
         list = result2;
       }
diff --git a/pkg/front_end/testcases/inference/generator_closure.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/generator_closure.dart.strong.transformed.expect
index 2f0ff59..fc34967 100644
--- a/pkg/front_end/testcases/inference/generator_closure.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/generator_closure.dart.strong.transformed.expect
@@ -13,7 +13,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
     dynamic :saved_try_context_var1;
diff --git a/pkg/front_end/testcases/inference/generic_methods_infer_generic_function_parameter_type2.dart.outline.expect b/pkg/front_end/testcases/inference/generic_methods_infer_generic_function_parameter_type2.dart.outline.expect
index 4c088aa..cd56022 100644
--- a/pkg/front_end/testcases/inference/generic_methods_infer_generic_function_parameter_type2.dart.outline.expect
+++ b/pkg/front_end/testcases/inference/generic_methods_infer_generic_function_parameter_type2.dart.outline.expect
@@ -2,7 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-typedef G<unrelated V extends core::Object* = dynamic> = () →* core::List<V*>*;
+typedef G<V extends core::Object* = dynamic> = () →* core::List<V*>*;
 class C<T extends core::Object* = dynamic> extends self::D<self::C::T*> {
   synthetic constructor •() → self::C<self::C::T*>*
     ;
diff --git a/pkg/front_end/testcases/inference/infer_local_function_return_type.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/infer_local_function_return_type.dart.strong.transformed.expect
index 5ee8e86..e6b1e38 100644
--- a/pkg/front_end/testcases/inference/infer_local_function_return_type.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/infer_local_function_return_type.dart.strong.transformed.expect
@@ -12,7 +12,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
@@ -42,7 +42,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
@@ -64,7 +64,7 @@
     return :async_completer.{asy::Completer::future};
   }
   function f4() → core::Iterable<core::int*>* /* originally sync* */ {
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     function :sync_op(core::_SyncIterator<core::int*>* :iterator) → core::bool* yielding {
       {
@@ -83,7 +83,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
     dynamic :saved_try_context_var1;
diff --git a/pkg/front_end/testcases/inference/infer_types_on_loop_indices_for_each_loop_async.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/infer_types_on_loop_indices_for_each_loop_async.dart.strong.transformed.expect
index 55072fa..7fe8c70 100644
--- a/pkg/front_end/testcases/inference/infer_types_on_loop_indices_for_each_loop_async.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/infer_types_on_loop_indices_for_each_loop_async.dart.strong.transformed.expect
@@ -31,6 +31,7 @@
 import self as self;
 import "dart:core" as core;
 import "dart:async" as asy;
+import "dart:_internal" as _in;
 
 import "dart:async";
 
@@ -50,7 +51,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
     dynamic :saved_try_context_var1;
@@ -69,7 +70,7 @@
               while (true) {
                 dynamic #t1 = asy::_asyncStarMoveNextHelper(:stream);
                 [yield] let dynamic #t2 = asy::_awaitHelper(:for-iterator.{asy::_StreamIterator::moveNext}(), :async_op_then, :async_op_error, :async_op) in null;
-                if(:result) {
+                if(_in::unsafeCast<core::bool*>(:result)) {
                   core::String* i = :for-iterator.{asy::_StreamIterator::current};
                   {
                     core::int* x = let final<BottomType> #t3 = invalid-expression "pkg/front_end/testcases/inference/infer_types_on_loop_indices_for_each_loop_async.dart:17:44: Error: A value of type 'String' can't be assigned to a variable of type 'int'.
@@ -110,7 +111,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
     dynamic :saved_try_context_var1;
@@ -129,7 +130,7 @@
               while (true) {
                 dynamic #t5 = asy::_asyncStarMoveNextHelper(:stream);
                 [yield] let dynamic #t6 = asy::_awaitHelper(:for-iterator.{asy::_StreamIterator::moveNext}(), :async_op_then, :async_op_error, :async_op) in null;
-                if(:result) {
+                if(_in::unsafeCast<core::bool*>(:result)) {
                   self::Baz::T* i = :for-iterator.{asy::_StreamIterator::current};
                   {
                     core::int* x = let final<BottomType> #t7 = invalid-expression "pkg/front_end/testcases/inference/infer_types_on_loop_indices_for_each_loop_async.dart:25:44: Error: A value of type 'T' can't be assigned to a variable of type 'int'.
@@ -171,7 +172,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   dynamic :saved_try_context_var0;
   dynamic :saved_try_context_var1;
@@ -191,7 +192,7 @@
             while (true) {
               dynamic #t9 = asy::_asyncStarMoveNextHelper(:stream);
               [yield] let dynamic #t10 = asy::_awaitHelper(:for-iterator.{asy::_StreamIterator::moveNext}(), :async_op_then, :async_op_error, :async_op) in null;
-              if(:result) {
+              if(_in::unsafeCast<core::bool*>(:result)) {
                 self::Foo* x = :for-iterator.{asy::_StreamIterator::current};
                 {
                   core::String* y = let final<BottomType> #t11 = invalid-expression "pkg/front_end/testcases/inference/infer_types_on_loop_indices_for_each_loop_async.dart:38:45: Error: A value of type 'Foo' can't be assigned to a variable of type 'String'.
@@ -218,7 +219,7 @@
             while (true) {
               dynamic #t13 = asy::_asyncStarMoveNextHelper(:stream);
               [yield] let dynamic #t14 = asy::_awaitHelper(:for-iterator.{asy::_StreamIterator::moveNext}(), :async_op_then, :async_op_error, :async_op) in null;
-              if(:result) {
+              if(_in::unsafeCast<core::bool*>(:result)) {
                 dynamic x = :for-iterator.{asy::_StreamIterator::current};
                 {
                   core::String* y = x as{TypeError} core::String*;
@@ -242,7 +243,7 @@
             while (true) {
               dynamic #t16 = asy::_asyncStarMoveNextHelper(:stream);
               [yield] let dynamic #t17 = asy::_awaitHelper(:for-iterator.{asy::_StreamIterator::moveNext}(), :async_op_then, :async_op_error, :async_op) in null;
-              if(:result) {
+              if(_in::unsafeCast<core::bool*>(:result)) {
                 final self::Foo* #t18 = :for-iterator.{asy::_StreamIterator::current};
                 {
                   core::String* x = let final<BottomType> #t19 = invalid-expression "pkg/front_end/testcases/inference/infer_types_on_loop_indices_for_each_loop_async.dart:45:21: Error: A value of type 'Foo' can't be assigned to a variable of type 'String'.
@@ -272,7 +273,7 @@
             while (true) {
               dynamic #t21 = asy::_asyncStarMoveNextHelper(:stream);
               [yield] let dynamic #t22 = asy::_awaitHelper(:for-iterator.{asy::_StreamIterator::moveNext}(), :async_op_then, :async_op_error, :async_op) in null;
-              if(:result) {
+              if(_in::unsafeCast<core::bool*>(:result)) {
                 final self::Foo* #t23 = :for-iterator.{asy::_StreamIterator::current};
                 {
                   z = #t23;
@@ -298,7 +299,7 @@
             while (true) {
               dynamic #t25 = asy::_asyncStarMoveNextHelper(:stream);
               [yield] let dynamic #t26 = asy::_awaitHelper(:for-iterator.{asy::_StreamIterator::moveNext}(), :async_op_then, :async_op_error, :async_op) in null;
-              if(:result) {
+              if(_in::unsafeCast<core::bool*>(:result)) {
                 final dynamic #t27 = :for-iterator.{asy::_StreamIterator::current};
                 {
                   self::Foo* x = #t27 as{TypeError} self::Foo*;
@@ -324,7 +325,7 @@
             while (true) {
               dynamic #t29 = asy::_asyncStarMoveNextHelper(:stream);
               [yield] let dynamic #t30 = asy::_awaitHelper(:for-iterator.{asy::_StreamIterator::moveNext}(), :async_op_then, :async_op_error, :async_op) in null;
-              if(:result) {
+              if(_in::unsafeCast<core::bool*>(:result)) {
                 final dynamic #t31 = :for-iterator.{asy::_StreamIterator::current};
                 {
                   self::Foo* x = #t31 as{TypeError} self::Foo*;
@@ -355,7 +356,7 @@
             while (true) {
               dynamic #t34 = asy::_asyncStarMoveNextHelper(:stream);
               [yield] let dynamic #t35 = asy::_awaitHelper(:for-iterator.{asy::_StreamIterator::moveNext}(), :async_op_then, :async_op_error, :async_op) in null;
-              if(:result) {
+              if(_in::unsafeCast<core::bool*>(:result)) {
                 dynamic x = :for-iterator.{asy::_StreamIterator::current};
                 {
                   core::String* y = x as{TypeError} core::String*;
diff --git a/pkg/front_end/testcases/inference/local_return_and_yield.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/local_return_and_yield.dart.strong.transformed.expect
index 02cb679..d796649 100644
--- a/pkg/front_end/testcases/inference/local_return_and_yield.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/local_return_and_yield.dart.strong.transformed.expect
@@ -24,7 +24,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
@@ -49,7 +49,7 @@
     return :async_completer.{asy::Completer::future};
   }
   function c() → core::Iterable<(core::int*) →* core::int*>* /* originally sync* */ {
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     function :sync_op(core::_SyncIterator<(core::int*) →* core::int*>* :iterator) → core::bool* yielding {
       {
@@ -63,7 +63,7 @@
     return new core::_SyncIterable::•<(core::int*) →* core::int*>(:sync_op);
   }
   function d() → core::Iterable<(core::int*) →* core::int*>* /* originally sync* */ {
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     function :sync_op(core::_SyncIterator<(core::int*) →* core::int*>* :iterator) → core::bool* yielding {
       {
@@ -82,7 +82,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
     dynamic :saved_try_context_var1;
@@ -117,7 +117,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
     dynamic :saved_try_context_var1;
diff --git a/pkg/front_end/testcases/inference/top_level_return_and_yield.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/top_level_return_and_yield.dart.strong.transformed.expect
index 0dba3ea..f6ea666 100644
--- a/pkg/front_end/testcases/inference/top_level_return_and_yield.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/top_level_return_and_yield.dart.strong.transformed.expect
@@ -23,7 +23,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
     try {
@@ -48,7 +48,7 @@
   return :async_completer.{asy::Completer::future};
 }
 static method c() → core::Iterable<(core::int*) →* core::int*>* /* originally sync* */ {
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   function :sync_op(core::_SyncIterator<(core::int*) →* core::int*>* :iterator) → core::bool* yielding {
     {
@@ -62,7 +62,7 @@
   return new core::_SyncIterable::•<(core::int*) →* core::int*>(:sync_op);
 }
 static method d() → core::Iterable<(core::int*) →* core::int*>* /* originally sync* */ {
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   function :sync_op(core::_SyncIterator<(core::int*) →* core::int*>* :iterator) → core::bool* yielding {
     {
@@ -81,7 +81,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   dynamic :saved_try_context_var0;
   dynamic :saved_try_context_var1;
@@ -116,7 +116,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   dynamic :saved_try_context_var0;
   dynamic :saved_try_context_var1;
diff --git a/pkg/front_end/testcases/inference_new/for_each_invalid_iterable.dart.strong.transformed.expect b/pkg/front_end/testcases/inference_new/for_each_invalid_iterable.dart.strong.transformed.expect
index 200434f..ee4302e 100644
--- a/pkg/front_end/testcases/inference_new/for_each_invalid_iterable.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference_new/for_each_invalid_iterable.dart.strong.transformed.expect
@@ -25,6 +25,7 @@
 import self as self;
 import "dart:async" as asy;
 import "dart:core" as core;
+import "dart:_internal" as _in;
 
 static method test() → dynamic /* originally async */ {
   final asy::_AsyncAwaitCompleter<dynamic>* :async_completer = new asy::_AsyncAwaitCompleter::•<dynamic>();
@@ -32,7 +33,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   dynamic :saved_try_context_var0;
   dynamic :saved_try_context_var1;
@@ -61,7 +62,7 @@
             while (true) {
               dynamic #t4 = asy::_asyncStarMoveNextHelper(:stream);
               [yield] let dynamic #t5 = asy::_awaitHelper(:for-iterator.{asy::_StreamIterator::moveNext}(), :async_op_then, :async_op_error, :async_op) in null;
-              if(:result) {
+              if(_in::unsafeCast<core::bool*>(:result)) {
                 final dynamic #t6 = :for-iterator.{asy::_StreamIterator::current};
                 {
                   core::int* x = #t6 as{TypeError} core::int*;
@@ -95,7 +96,7 @@
             while (true) {
               dynamic #t11 = asy::_asyncStarMoveNextHelper(:stream);
               [yield] let dynamic #t12 = asy::_awaitHelper(:for-iterator.{asy::_StreamIterator::moveNext}(), :async_op_then, :async_op_error, :async_op) in null;
-              if(:result) {
+              if(_in::unsafeCast<core::bool*>(:result)) {
                 final dynamic #t13 = :for-iterator.{asy::_StreamIterator::current};
                 {
                   y = #t13 as{TypeError} core::int*;
diff --git a/pkg/front_end/testcases/inference_new/for_each_outer_var_type.dart.strong.transformed.expect b/pkg/front_end/testcases/inference_new/for_each_outer_var_type.dart.strong.transformed.expect
index 650e52c..649f649 100644
--- a/pkg/front_end/testcases/inference_new/for_each_outer_var_type.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference_new/for_each_outer_var_type.dart.strong.transformed.expect
@@ -17,6 +17,7 @@
 import self as self;
 import "dart:core" as core;
 import "dart:async" as asy;
+import "dart:_internal" as _in;
 
 import "dart:async";
 
@@ -38,7 +39,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   dynamic :saved_try_context_var0;
   dynamic :saved_try_context_var1;
@@ -65,7 +66,7 @@
             while (true) {
               dynamic #t2 = asy::_asyncStarMoveNextHelper(:stream);
               [yield] let dynamic #t3 = asy::_awaitHelper(:for-iterator.{asy::_StreamIterator::moveNext}(), :async_op_then, :async_op_error, :async_op) in null;
-              if(:result) {
+              if(_in::unsafeCast<core::bool*>(:result)) {
                 final self::A* #t4 = :for-iterator.{asy::_StreamIterator::current};
                 {
                   a = #t4;
@@ -92,7 +93,7 @@
             while (true) {
               dynamic #t7 = asy::_asyncStarMoveNextHelper(:stream);
               [yield] let dynamic #t8 = asy::_awaitHelper(:for-iterator.{asy::_StreamIterator::moveNext}(), :async_op_then, :async_op_error, :async_op) in null;
-              if(:result) {
+              if(_in::unsafeCast<core::bool*>(:result)) {
                 final self::A* #t9 = :for-iterator.{asy::_StreamIterator::current};
                 {
                   b = #t9 as{TypeError} self::B*;
@@ -123,7 +124,7 @@
             while (true) {
               dynamic #t13 = asy::_asyncStarMoveNextHelper(:stream);
               [yield] let dynamic #t14 = asy::_awaitHelper(:for-iterator.{asy::_StreamIterator::moveNext}(), :async_op_then, :async_op_error, :async_op) in null;
-              if(:result) {
+              if(_in::unsafeCast<core::bool*>(:result)) {
                 final self::A* #t15 = :for-iterator.{asy::_StreamIterator::current};
                 {
                   i = let final<BottomType> #t16 = invalid-expression "pkg/front_end/testcases/inference_new/for_each_outer_var_type.dart:27:16: Error: A value of type 'A' can't be assigned to a variable of type 'int'.
@@ -154,7 +155,7 @@
             while (true) {
               dynamic #t19 = asy::_asyncStarMoveNextHelper(:stream);
               [yield] let dynamic #t20 = asy::_awaitHelper(:for-iterator.{asy::_StreamIterator::moveNext}(), :async_op_then, :async_op_error, :async_op) in null;
-              if(:result) {
+              if(_in::unsafeCast<core::bool*>(:result)) {
                 final self::A* #t21 = :for-iterator.{asy::_StreamIterator::current};
                 {
                   a = #t21;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_class_typedef_cycle.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_class_typedef_cycle.dart.outline.expect
index 5985c4c..ada0233 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_class_typedef_cycle.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_class_typedef_cycle.dart.outline.expect
@@ -16,7 +16,7 @@
 import self as self;
 import "dart:core" as core;
 
-typedef Fisk<unrelated TypeY extends core::Object* = dynamic> = () →* void;
+typedef Fisk<unrelated TypeY extends dynamic = dynamic> = () →* void;
 class Hest<TypeX extends () →* void = () →* void> extends core::Object {
   synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
     ;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_class_typedef_cycle.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_class_typedef_cycle.dart.strong.expect
index 7b9d47f..f4c5a8b 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_class_typedef_cycle.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_class_typedef_cycle.dart.strong.expect
@@ -16,7 +16,7 @@
 import self as self;
 import "dart:core" as core;
 
-typedef Fisk<unrelated TypeY extends core::Object* = dynamic> = () →* void;
+typedef Fisk<unrelated TypeY extends dynamic = dynamic> = () →* void;
 class Hest<TypeX extends () →* void = () →* void> extends core::Object {
   synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
     : super core::Object::•()
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_class_typedef_cycle.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_class_typedef_cycle.dart.strong.transformed.expect
index 7b9d47f..f4c5a8b 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_class_typedef_cycle.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_class_typedef_cycle.dart.strong.transformed.expect
@@ -16,7 +16,7 @@
 import self as self;
 import "dart:core" as core;
 
-typedef Fisk<unrelated TypeY extends core::Object* = dynamic> = () →* void;
+typedef Fisk<unrelated TypeY extends dynamic = dynamic> = () →* void;
 class Hest<TypeX extends () →* void = () →* void> extends core::Object {
   synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
     : super core::Object::•()
diff --git a/pkg/front_end/testcases/late_lowering/instance_field_with_initializer.dart b/pkg/front_end/testcases/late_lowering/instance_field_with_initializer.dart
new file mode 100644
index 0000000..1ff72a5
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/instance_field_with_initializer.dart
@@ -0,0 +1,82 @@
+// Copyright (c) 2019, 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 Class {
+  late int field = 10;
+
+  Class.constructor1();
+  Class.constructor2(int this.field);
+  Class.constructor3(int value) : this.field = value + 1;
+  Class.constructor4([int this.field = 42]);
+}
+
+class Subclass extends Class {
+  Subclass.constructor1() : super.constructor1();
+  Subclass.constructor2(int value) : super.constructor2(value);
+  Subclass.constructor3(int value) : super.constructor3(value);
+  Subclass.constructor4([int value = 87]) : super.constructor4(value);
+}
+
+test1() {
+  var c1 = new Class.constructor1();
+  expect(10, c1.field);
+  c1.field = 16;
+  expect(16, c1.field);
+
+  var c2 = new Class.constructor2(42);
+  expect(42, c2.field);
+  c2.field = 43;
+  expect(43, c2.field);
+
+  var c3 = new Class.constructor3(87);
+  expect(88, c3.field);
+  c3.field = 89;
+  expect(89, c3.field);
+
+  var c4 = new Class.constructor4();
+  expect(42, c4.field);
+  c4.field = 43;
+  expect(43, c4.field);
+
+  var c5 = new Class.constructor4(123);
+  expect(123, c5.field);
+  c5.field = 124;
+  expect(124, c5.field);
+}
+
+test2() {
+  var c1 = new Subclass.constructor1();
+  expect(10, c1.field);
+  c1.field = 16;
+  expect(16, c1.field);
+
+  var c2 = new Subclass.constructor2(42);
+  expect(42, c2.field);
+  c2.field = 43;
+  expect(43, c2.field);
+
+  var c3 = new Subclass.constructor3(87);
+  expect(88, c3.field);
+  c3.field = 89;
+  expect(89, c3.field);
+
+  var c4 = new Subclass.constructor4();
+  expect(87, c4.field);
+  c4.field = 88;
+  expect(88, c4.field);
+
+  var c5 = new Subclass.constructor4(123);
+  expect(123, c5.field);
+  c5.field = 124;
+  expect(124, c5.field);
+}
+
+main() {
+  test1();
+  test2();
+}
+
+expect(expected, actual) {
+  if (expected != actual) throw 'Expected $expected, actual $actual';
+}
diff --git a/pkg/front_end/testcases/late_lowering/instance_field_with_initializer.dart.outline.expect b/pkg/front_end/testcases/late_lowering/instance_field_with_initializer.dart.outline.expect
new file mode 100644
index 0000000..e809201
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/instance_field_with_initializer.dart.outline.expect
@@ -0,0 +1,35 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  field core::int? _#field;
+  constructor constructor1() → self::Class
+    ;
+  constructor constructor2(core::int field) → self::Class
+    ;
+  constructor constructor3(core::int value) → self::Class
+    ;
+  constructor constructor4([core::int field]) → self::Class
+    ;
+  get field() → core::int;
+  set field(core::int #t1) → void;
+}
+class Subclass extends self::Class {
+  constructor constructor1() → self::Subclass
+    ;
+  constructor constructor2(core::int value) → self::Subclass
+    ;
+  constructor constructor3(core::int value) → self::Subclass
+    ;
+  constructor constructor4([core::int value]) → self::Subclass
+    ;
+}
+static method test1() → dynamic
+  ;
+static method test2() → dynamic
+  ;
+static method main() → dynamic
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
diff --git a/pkg/front_end/testcases/late_lowering/instance_field_with_initializer.dart.strong.expect b/pkg/front_end/testcases/late_lowering/instance_field_with_initializer.dart.strong.expect
new file mode 100644
index 0000000..77c1250
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/instance_field_with_initializer.dart.strong.expect
@@ -0,0 +1,94 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  field core::int? _#field = null;
+  constructor constructor1() → self::Class
+    : super core::Object::•()
+    ;
+  constructor constructor2(core::int field) → self::Class
+    : self::Class::_#field = field, super core::Object::•()
+    ;
+  constructor constructor3(core::int value) → self::Class
+    : self::Class::_#field = value.{core::num::+}(1), super core::Object::•()
+    ;
+  constructor constructor4([core::int field = #C1]) → self::Class
+    : self::Class::_#field = field, super core::Object::•()
+    ;
+  get field() → core::int
+    return let final core::int? #t1 = this.{self::Class::_#field} in #t1.==(null) ?{core::int} this.{self::Class::_#field} = 10 : #t1{core::int};
+  set field(core::int #t2) → void
+    this.{self::Class::_#field} = #t2;
+}
+class Subclass extends self::Class {
+  constructor constructor1() → self::Subclass
+    : super self::Class::constructor1()
+    ;
+  constructor constructor2(core::int value) → self::Subclass
+    : super self::Class::constructor2(value)
+    ;
+  constructor constructor3(core::int value) → self::Subclass
+    : super self::Class::constructor3(value)
+    ;
+  constructor constructor4([core::int value = #C2]) → self::Subclass
+    : super self::Class::constructor4(value)
+    ;
+}
+static method test1() → dynamic {
+  self::Class c1 = new self::Class::constructor1();
+  self::expect(10, c1.{self::Class::field});
+  c1.{self::Class::field} = 16;
+  self::expect(16, c1.{self::Class::field});
+  self::Class c2 = new self::Class::constructor2(42);
+  self::expect(42, c2.{self::Class::field});
+  c2.{self::Class::field} = 43;
+  self::expect(43, c2.{self::Class::field});
+  self::Class c3 = new self::Class::constructor3(87);
+  self::expect(88, c3.{self::Class::field});
+  c3.{self::Class::field} = 89;
+  self::expect(89, c3.{self::Class::field});
+  self::Class c4 = new self::Class::constructor4();
+  self::expect(42, c4.{self::Class::field});
+  c4.{self::Class::field} = 43;
+  self::expect(43, c4.{self::Class::field});
+  self::Class c5 = new self::Class::constructor4(123);
+  self::expect(123, c5.{self::Class::field});
+  c5.{self::Class::field} = 124;
+  self::expect(124, c5.{self::Class::field});
+}
+static method test2() → dynamic {
+  self::Subclass c1 = new self::Subclass::constructor1();
+  self::expect(10, c1.{self::Class::field});
+  c1.{self::Class::field} = 16;
+  self::expect(16, c1.{self::Class::field});
+  self::Subclass c2 = new self::Subclass::constructor2(42);
+  self::expect(42, c2.{self::Class::field});
+  c2.{self::Class::field} = 43;
+  self::expect(43, c2.{self::Class::field});
+  self::Subclass c3 = new self::Subclass::constructor3(87);
+  self::expect(88, c3.{self::Class::field});
+  c3.{self::Class::field} = 89;
+  self::expect(89, c3.{self::Class::field});
+  self::Subclass c4 = new self::Subclass::constructor4();
+  self::expect(87, c4.{self::Class::field});
+  c4.{self::Class::field} = 88;
+  self::expect(88, c4.{self::Class::field});
+  self::Subclass c5 = new self::Subclass::constructor4(123);
+  self::expect(123, c5.{self::Class::field});
+  c5.{self::Class::field} = 124;
+  self::expect(124, c5.{self::Class::field});
+}
+static method main() → dynamic {
+  self::test1();
+  self::test2();
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+
+constants  {
+  #C1 = 42
+  #C2 = 87
+}
diff --git a/pkg/front_end/testcases/late_lowering/instance_field_with_initializer.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/instance_field_with_initializer.dart.strong.transformed.expect
new file mode 100644
index 0000000..77c1250
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/instance_field_with_initializer.dart.strong.transformed.expect
@@ -0,0 +1,94 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  field core::int? _#field = null;
+  constructor constructor1() → self::Class
+    : super core::Object::•()
+    ;
+  constructor constructor2(core::int field) → self::Class
+    : self::Class::_#field = field, super core::Object::•()
+    ;
+  constructor constructor3(core::int value) → self::Class
+    : self::Class::_#field = value.{core::num::+}(1), super core::Object::•()
+    ;
+  constructor constructor4([core::int field = #C1]) → self::Class
+    : self::Class::_#field = field, super core::Object::•()
+    ;
+  get field() → core::int
+    return let final core::int? #t1 = this.{self::Class::_#field} in #t1.==(null) ?{core::int} this.{self::Class::_#field} = 10 : #t1{core::int};
+  set field(core::int #t2) → void
+    this.{self::Class::_#field} = #t2;
+}
+class Subclass extends self::Class {
+  constructor constructor1() → self::Subclass
+    : super self::Class::constructor1()
+    ;
+  constructor constructor2(core::int value) → self::Subclass
+    : super self::Class::constructor2(value)
+    ;
+  constructor constructor3(core::int value) → self::Subclass
+    : super self::Class::constructor3(value)
+    ;
+  constructor constructor4([core::int value = #C2]) → self::Subclass
+    : super self::Class::constructor4(value)
+    ;
+}
+static method test1() → dynamic {
+  self::Class c1 = new self::Class::constructor1();
+  self::expect(10, c1.{self::Class::field});
+  c1.{self::Class::field} = 16;
+  self::expect(16, c1.{self::Class::field});
+  self::Class c2 = new self::Class::constructor2(42);
+  self::expect(42, c2.{self::Class::field});
+  c2.{self::Class::field} = 43;
+  self::expect(43, c2.{self::Class::field});
+  self::Class c3 = new self::Class::constructor3(87);
+  self::expect(88, c3.{self::Class::field});
+  c3.{self::Class::field} = 89;
+  self::expect(89, c3.{self::Class::field});
+  self::Class c4 = new self::Class::constructor4();
+  self::expect(42, c4.{self::Class::field});
+  c4.{self::Class::field} = 43;
+  self::expect(43, c4.{self::Class::field});
+  self::Class c5 = new self::Class::constructor4(123);
+  self::expect(123, c5.{self::Class::field});
+  c5.{self::Class::field} = 124;
+  self::expect(124, c5.{self::Class::field});
+}
+static method test2() → dynamic {
+  self::Subclass c1 = new self::Subclass::constructor1();
+  self::expect(10, c1.{self::Class::field});
+  c1.{self::Class::field} = 16;
+  self::expect(16, c1.{self::Class::field});
+  self::Subclass c2 = new self::Subclass::constructor2(42);
+  self::expect(42, c2.{self::Class::field});
+  c2.{self::Class::field} = 43;
+  self::expect(43, c2.{self::Class::field});
+  self::Subclass c3 = new self::Subclass::constructor3(87);
+  self::expect(88, c3.{self::Class::field});
+  c3.{self::Class::field} = 89;
+  self::expect(89, c3.{self::Class::field});
+  self::Subclass c4 = new self::Subclass::constructor4();
+  self::expect(87, c4.{self::Class::field});
+  c4.{self::Class::field} = 88;
+  self::expect(88, c4.{self::Class::field});
+  self::Subclass c5 = new self::Subclass::constructor4(123);
+  self::expect(123, c5.{self::Class::field});
+  c5.{self::Class::field} = 124;
+  self::expect(124, c5.{self::Class::field});
+}
+static method main() → dynamic {
+  self::test1();
+  self::test2();
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+
+constants  {
+  #C1 = 42
+  #C2 = 87
+}
diff --git a/pkg/front_end/testcases/late_lowering/instance_field_without_initializer.dart b/pkg/front_end/testcases/late_lowering/instance_field_without_initializer.dart
new file mode 100644
index 0000000..b06db9d
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/instance_field_without_initializer.dart
@@ -0,0 +1,93 @@
+// Copyright (c) 2019, 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 Class {
+  late int field;
+
+  Class.constructor1();
+  Class.constructor2(int this.field);
+  Class.constructor3(int value) : this.field = value + 1;
+  Class.constructor4([int this.field = 42]);
+}
+
+class Subclass extends Class {
+  Subclass.constructor1() : super.constructor1();
+  Subclass.constructor2(int value) : super.constructor2(value);
+  Subclass.constructor3(int value) : super.constructor3(value);
+  Subclass.constructor4([int value = 87]) : super.constructor4(value);
+}
+
+test1() {
+  var c1 = new Class.constructor1();
+  throws(() => c1.field, 'Read value from uninitialized Class.field');
+  c1.field = 16;
+  expect(16, c1.field);
+
+  var c2 = new Class.constructor2(42);
+  expect(42, c2.field);
+  c2.field = 43;
+  expect(43, c2.field);
+
+  var c3 = new Class.constructor3(87);
+  expect(88, c3.field);
+  c3.field = 89;
+  expect(89, c3.field);
+
+  var c4 = new Class.constructor4();
+  expect(42, c4.field);
+  c4.field = 43;
+  expect(43, c4.field);
+
+  var c5 = new Class.constructor4(123);
+  expect(123, c5.field);
+  c5.field = 124;
+  expect(124, c5.field);
+}
+
+test2() {
+  var c1 = new Subclass.constructor1();
+  throws(() => c1.field, 'Read value from uninitialized Class.field');
+  c1.field = 16;
+  expect(16, c1.field);
+
+  var c2 = new Subclass.constructor2(42);
+  expect(42, c2.field);
+  c2.field = 43;
+  expect(43, c2.field);
+
+  var c3 = new Subclass.constructor3(87);
+  expect(88, c3.field);
+  c3.field = 89;
+  expect(89, c3.field);
+
+  var c4 = new Subclass.constructor4();
+  expect(87, c4.field);
+  c4.field = 88;
+  expect(88, c4.field);
+
+  var c5 = new Subclass.constructor4(123);
+  expect(123, c5.field);
+  c5.field = 124;
+  expect(124, c5.field);
+}
+
+main() {
+  test1();
+  test2();
+}
+
+expect(expected, actual) {
+  if (expected != actual) throw 'Expected $expected, actual $actual';
+}
+
+throws(f(), String message) {
+  dynamic value;
+  try {
+    value = f();
+  } catch (e) {
+    print(e);
+    return;
+  }
+  throw '$message: $value';
+}
diff --git a/pkg/front_end/testcases/late_lowering/instance_field_without_initializer.dart.outline.expect b/pkg/front_end/testcases/late_lowering/instance_field_without_initializer.dart.outline.expect
new file mode 100644
index 0000000..46ce40c
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/instance_field_without_initializer.dart.outline.expect
@@ -0,0 +1,37 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  field core::int? _#field;
+  constructor constructor1() → self::Class
+    ;
+  constructor constructor2(core::int field) → self::Class
+    ;
+  constructor constructor3(core::int value) → self::Class
+    ;
+  constructor constructor4([core::int field]) → self::Class
+    ;
+  get field() → core::int;
+  set field(core::int #t1) → void;
+}
+class Subclass extends self::Class {
+  constructor constructor1() → self::Subclass
+    ;
+  constructor constructor2(core::int value) → self::Subclass
+    ;
+  constructor constructor3(core::int value) → self::Subclass
+    ;
+  constructor constructor4([core::int value]) → self::Subclass
+    ;
+}
+static method test1() → dynamic
+  ;
+static method test2() → dynamic
+  ;
+static method main() → dynamic
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
+static method throws(() → dynamic f, core::String message) → dynamic
+  ;
diff --git a/pkg/front_end/testcases/late_lowering/instance_field_without_initializer.dart.strong.expect b/pkg/front_end/testcases/late_lowering/instance_field_without_initializer.dart.strong.expect
new file mode 100644
index 0000000..7e44af1
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/instance_field_without_initializer.dart.strong.expect
@@ -0,0 +1,105 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  field core::int? _#field = null;
+  constructor constructor1() → self::Class
+    : super core::Object::•()
+    ;
+  constructor constructor2(core::int field) → self::Class
+    : self::Class::_#field = field, super core::Object::•()
+    ;
+  constructor constructor3(core::int value) → self::Class
+    : self::Class::_#field = value.{core::num::+}(1), super core::Object::•()
+    ;
+  constructor constructor4([core::int field = #C1]) → self::Class
+    : self::Class::_#field = field, super core::Object::•()
+    ;
+  get field() → core::int
+    return let final core::int? #t1 = this.{self::Class::_#field} in #t1.==(null) ?{core::int} throw "Field 'field' has not been initialized." : #t1{core::int};
+  set field(core::int #t2) → void
+    this.{self::Class::_#field} = #t2;
+}
+class Subclass extends self::Class {
+  constructor constructor1() → self::Subclass
+    : super self::Class::constructor1()
+    ;
+  constructor constructor2(core::int value) → self::Subclass
+    : super self::Class::constructor2(value)
+    ;
+  constructor constructor3(core::int value) → self::Subclass
+    : super self::Class::constructor3(value)
+    ;
+  constructor constructor4([core::int value = #C2]) → self::Subclass
+    : super self::Class::constructor4(value)
+    ;
+}
+static method test1() → dynamic {
+  self::Class c1 = new self::Class::constructor1();
+  self::throws(() → core::int => c1.{self::Class::field}, "Read value from uninitialized Class.field");
+  c1.{self::Class::field} = 16;
+  self::expect(16, c1.{self::Class::field});
+  self::Class c2 = new self::Class::constructor2(42);
+  self::expect(42, c2.{self::Class::field});
+  c2.{self::Class::field} = 43;
+  self::expect(43, c2.{self::Class::field});
+  self::Class c3 = new self::Class::constructor3(87);
+  self::expect(88, c3.{self::Class::field});
+  c3.{self::Class::field} = 89;
+  self::expect(89, c3.{self::Class::field});
+  self::Class c4 = new self::Class::constructor4();
+  self::expect(42, c4.{self::Class::field});
+  c4.{self::Class::field} = 43;
+  self::expect(43, c4.{self::Class::field});
+  self::Class c5 = new self::Class::constructor4(123);
+  self::expect(123, c5.{self::Class::field});
+  c5.{self::Class::field} = 124;
+  self::expect(124, c5.{self::Class::field});
+}
+static method test2() → dynamic {
+  self::Subclass c1 = new self::Subclass::constructor1();
+  self::throws(() → core::int => c1.{self::Class::field}, "Read value from uninitialized Class.field");
+  c1.{self::Class::field} = 16;
+  self::expect(16, c1.{self::Class::field});
+  self::Subclass c2 = new self::Subclass::constructor2(42);
+  self::expect(42, c2.{self::Class::field});
+  c2.{self::Class::field} = 43;
+  self::expect(43, c2.{self::Class::field});
+  self::Subclass c3 = new self::Subclass::constructor3(87);
+  self::expect(88, c3.{self::Class::field});
+  c3.{self::Class::field} = 89;
+  self::expect(89, c3.{self::Class::field});
+  self::Subclass c4 = new self::Subclass::constructor4();
+  self::expect(87, c4.{self::Class::field});
+  c4.{self::Class::field} = 88;
+  self::expect(88, c4.{self::Class::field});
+  self::Subclass c5 = new self::Subclass::constructor4(123);
+  self::expect(123, c5.{self::Class::field});
+  c5.{self::Class::field} = 124;
+  self::expect(124, c5.{self::Class::field});
+}
+static method main() → dynamic {
+  self::test1();
+  self::test2();
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, core::String message) → dynamic {
+  dynamic value;
+  try {
+    value = f.call();
+  }
+  on dynamic catch(final dynamic e) {
+    core::print(e);
+    return;
+  }
+  throw "${message}: ${value}";
+}
+
+constants  {
+  #C1 = 42
+  #C2 = 87
+}
diff --git a/pkg/front_end/testcases/late_lowering/instance_field_without_initializer.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/instance_field_without_initializer.dart.strong.transformed.expect
new file mode 100644
index 0000000..7e44af1
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/instance_field_without_initializer.dart.strong.transformed.expect
@@ -0,0 +1,105 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  field core::int? _#field = null;
+  constructor constructor1() → self::Class
+    : super core::Object::•()
+    ;
+  constructor constructor2(core::int field) → self::Class
+    : self::Class::_#field = field, super core::Object::•()
+    ;
+  constructor constructor3(core::int value) → self::Class
+    : self::Class::_#field = value.{core::num::+}(1), super core::Object::•()
+    ;
+  constructor constructor4([core::int field = #C1]) → self::Class
+    : self::Class::_#field = field, super core::Object::•()
+    ;
+  get field() → core::int
+    return let final core::int? #t1 = this.{self::Class::_#field} in #t1.==(null) ?{core::int} throw "Field 'field' has not been initialized." : #t1{core::int};
+  set field(core::int #t2) → void
+    this.{self::Class::_#field} = #t2;
+}
+class Subclass extends self::Class {
+  constructor constructor1() → self::Subclass
+    : super self::Class::constructor1()
+    ;
+  constructor constructor2(core::int value) → self::Subclass
+    : super self::Class::constructor2(value)
+    ;
+  constructor constructor3(core::int value) → self::Subclass
+    : super self::Class::constructor3(value)
+    ;
+  constructor constructor4([core::int value = #C2]) → self::Subclass
+    : super self::Class::constructor4(value)
+    ;
+}
+static method test1() → dynamic {
+  self::Class c1 = new self::Class::constructor1();
+  self::throws(() → core::int => c1.{self::Class::field}, "Read value from uninitialized Class.field");
+  c1.{self::Class::field} = 16;
+  self::expect(16, c1.{self::Class::field});
+  self::Class c2 = new self::Class::constructor2(42);
+  self::expect(42, c2.{self::Class::field});
+  c2.{self::Class::field} = 43;
+  self::expect(43, c2.{self::Class::field});
+  self::Class c3 = new self::Class::constructor3(87);
+  self::expect(88, c3.{self::Class::field});
+  c3.{self::Class::field} = 89;
+  self::expect(89, c3.{self::Class::field});
+  self::Class c4 = new self::Class::constructor4();
+  self::expect(42, c4.{self::Class::field});
+  c4.{self::Class::field} = 43;
+  self::expect(43, c4.{self::Class::field});
+  self::Class c5 = new self::Class::constructor4(123);
+  self::expect(123, c5.{self::Class::field});
+  c5.{self::Class::field} = 124;
+  self::expect(124, c5.{self::Class::field});
+}
+static method test2() → dynamic {
+  self::Subclass c1 = new self::Subclass::constructor1();
+  self::throws(() → core::int => c1.{self::Class::field}, "Read value from uninitialized Class.field");
+  c1.{self::Class::field} = 16;
+  self::expect(16, c1.{self::Class::field});
+  self::Subclass c2 = new self::Subclass::constructor2(42);
+  self::expect(42, c2.{self::Class::field});
+  c2.{self::Class::field} = 43;
+  self::expect(43, c2.{self::Class::field});
+  self::Subclass c3 = new self::Subclass::constructor3(87);
+  self::expect(88, c3.{self::Class::field});
+  c3.{self::Class::field} = 89;
+  self::expect(89, c3.{self::Class::field});
+  self::Subclass c4 = new self::Subclass::constructor4();
+  self::expect(87, c4.{self::Class::field});
+  c4.{self::Class::field} = 88;
+  self::expect(88, c4.{self::Class::field});
+  self::Subclass c5 = new self::Subclass::constructor4(123);
+  self::expect(123, c5.{self::Class::field});
+  c5.{self::Class::field} = 124;
+  self::expect(124, c5.{self::Class::field});
+}
+static method main() → dynamic {
+  self::test1();
+  self::test2();
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, core::String message) → dynamic {
+  dynamic value;
+  try {
+    value = f.call();
+  }
+  on dynamic catch(final dynamic e) {
+    core::print(e);
+    return;
+  }
+  throw "${message}: ${value}";
+}
+
+constants  {
+  #C1 = 42
+  #C2 = 87
+}
diff --git a/pkg/front_end/testcases/late_lowering/instance_final_field_without_initializer.dart b/pkg/front_end/testcases/late_lowering/instance_final_field_without_initializer.dart
new file mode 100644
index 0000000..e857d22
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/instance_final_field_without_initializer.dart
@@ -0,0 +1,97 @@
+// Copyright (c) 2019, 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 Class {
+  late final int field;
+
+  Class.constructor1();
+  Class.constructor2(int this.field);
+  Class.constructor3(int value) : this.field = value + 1;
+  Class.constructor4([int this.field = 42]);
+}
+
+class Subclass extends Class {
+  Subclass.constructor1() : super.constructor1();
+  Subclass.constructor2(int value) : super.constructor2(value);
+  Subclass.constructor3(int value) : super.constructor3(value);
+  Subclass.constructor4([int value = 87]) : super.constructor4(value);
+}
+
+test1() {
+  var c1 = new Class.constructor1();
+  throws(() => c1.field, 'Read value from uninitialized Class.field');
+  c1.field = 16;
+  expect(16, c1.field);
+  throws(() => c1.field = 17, 'Write value to initialized Class.field');
+
+  var c2 = new Class.constructor2(42);
+  expect(42, c2.field);
+  throws(() => c2.field = 43, 'Write value to initialized Class.field');
+
+  var c3 = new Class.constructor3(87);
+  expect(88, c3.field);
+  throws(() => c3.field = 89, 'Write value to initialized Class.field');
+
+  var c4 = new Class.constructor4();
+  expect(42, c4.field);
+  throws(() => c4.field = 43, 'Write value to initialized Class.field');
+
+  var c5 = new Class.constructor4(123);
+  expect(123, c5.field);
+  throws(() => c5.field = 124, 'Write value to initialized Class.field');
+
+  var c6 = new Class.constructor1();
+  c6.field = 32;
+  expect(32, c6.field);
+  throws(() => c6.field = 32, 'Write value to initialized Class.field');
+}
+
+test2() {
+  var c1 = new Subclass.constructor1();
+  throws(() => c1.field, 'Read value from uninitialized Class1.field');
+  c1.field = 16;
+  expect(16, c1.field);
+  throws(() => c1.field = 17, 'Write value to initialized Class.field');
+
+  var c2 = new Subclass.constructor2(42);
+  expect(42, c2.field);
+  throws(() => c2.field = 43, 'Write value to initialized Class.field');
+
+  var c3 = new Subclass.constructor3(87);
+  expect(88, c3.field);
+  throws(() => c3.field = 89, 'Write value to initialized Class.field');
+
+  var c4 = new Subclass.constructor4();
+  expect(87, c4.field);
+  throws(() => c4.field = 88, 'Write value to initialized Class.field');
+
+  var c5 = new Subclass.constructor4(123);
+  expect(123, c5.field);
+  throws(() => c5.field = 124, 'Write value to initialized Class.field');
+
+  var c6 = new Subclass.constructor1();
+  c6.field = 32;
+  expect(32, c6.field);
+  throws(() => c6.field = 32, 'Write value to initialized Class.field');
+}
+
+main() {
+  test1();
+  test2();
+}
+
+expect(expected, actual) {
+  if (expected != actual) throw 'Expected $expected, actual $actual';
+}
+
+throws(f(), String message) {
+  dynamic value;
+  try {
+    value = f();
+  } catch (e) {
+    print(e);
+    return;
+  }
+  throw '$message: $value';
+}
diff --git a/pkg/front_end/testcases/late_lowering/instance_final_field_without_initializer.dart.outline.expect b/pkg/front_end/testcases/late_lowering/instance_final_field_without_initializer.dart.outline.expect
new file mode 100644
index 0000000..46ce40c
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/instance_final_field_without_initializer.dart.outline.expect
@@ -0,0 +1,37 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  field core::int? _#field;
+  constructor constructor1() → self::Class
+    ;
+  constructor constructor2(core::int field) → self::Class
+    ;
+  constructor constructor3(core::int value) → self::Class
+    ;
+  constructor constructor4([core::int field]) → self::Class
+    ;
+  get field() → core::int;
+  set field(core::int #t1) → void;
+}
+class Subclass extends self::Class {
+  constructor constructor1() → self::Subclass
+    ;
+  constructor constructor2(core::int value) → self::Subclass
+    ;
+  constructor constructor3(core::int value) → self::Subclass
+    ;
+  constructor constructor4([core::int value]) → self::Subclass
+    ;
+}
+static method test1() → dynamic
+  ;
+static method test2() → dynamic
+  ;
+static method main() → dynamic
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
+static method throws(() → dynamic f, core::String message) → dynamic
+  ;
diff --git a/pkg/front_end/testcases/late_lowering/instance_final_field_without_initializer.dart.strong.expect b/pkg/front_end/testcases/late_lowering/instance_final_field_without_initializer.dart.strong.expect
new file mode 100644
index 0000000..8e4ad19
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/instance_final_field_without_initializer.dart.strong.expect
@@ -0,0 +1,110 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  field core::int? _#field = null;
+  constructor constructor1() → self::Class
+    : super core::Object::•()
+    ;
+  constructor constructor2(core::int field) → self::Class
+    : self::Class::_#field = field, super core::Object::•()
+    ;
+  constructor constructor3(core::int value) → self::Class
+    : self::Class::_#field = value.{core::num::+}(1), super core::Object::•()
+    ;
+  constructor constructor4([core::int field = #C1]) → self::Class
+    : self::Class::_#field = field, super core::Object::•()
+    ;
+  get field() → core::int
+    return let final core::int? #t1 = this.{self::Class::_#field} in #t1.==(null) ?{core::int} throw "Field 'field' has not been initialized." : #t1{core::int};
+  set field(core::int #t2) → void
+    if(this.{self::Class::_#field}.==(null))
+      this.{self::Class::_#field} = #t2;
+    else
+      throw "Field 'field' has already been initialized.";
+}
+class Subclass extends self::Class {
+  constructor constructor1() → self::Subclass
+    : super self::Class::constructor1()
+    ;
+  constructor constructor2(core::int value) → self::Subclass
+    : super self::Class::constructor2(value)
+    ;
+  constructor constructor3(core::int value) → self::Subclass
+    : super self::Class::constructor3(value)
+    ;
+  constructor constructor4([core::int value = #C2]) → self::Subclass
+    : super self::Class::constructor4(value)
+    ;
+}
+static method test1() → dynamic {
+  self::Class c1 = new self::Class::constructor1();
+  self::throws(() → core::int => c1.{self::Class::field}, "Read value from uninitialized Class.field");
+  c1.{self::Class::field} = 16;
+  self::expect(16, c1.{self::Class::field});
+  self::throws(() → core::int => c1.{self::Class::field} = 17, "Write value to initialized Class.field");
+  self::Class c2 = new self::Class::constructor2(42);
+  self::expect(42, c2.{self::Class::field});
+  self::throws(() → core::int => c2.{self::Class::field} = 43, "Write value to initialized Class.field");
+  self::Class c3 = new self::Class::constructor3(87);
+  self::expect(88, c3.{self::Class::field});
+  self::throws(() → core::int => c3.{self::Class::field} = 89, "Write value to initialized Class.field");
+  self::Class c4 = new self::Class::constructor4();
+  self::expect(42, c4.{self::Class::field});
+  self::throws(() → core::int => c4.{self::Class::field} = 43, "Write value to initialized Class.field");
+  self::Class c5 = new self::Class::constructor4(123);
+  self::expect(123, c5.{self::Class::field});
+  self::throws(() → core::int => c5.{self::Class::field} = 124, "Write value to initialized Class.field");
+  self::Class c6 = new self::Class::constructor1();
+  c6.{self::Class::field} = 32;
+  self::expect(32, c6.{self::Class::field});
+  self::throws(() → core::int => c6.{self::Class::field} = 32, "Write value to initialized Class.field");
+}
+static method test2() → dynamic {
+  self::Subclass c1 = new self::Subclass::constructor1();
+  self::throws(() → core::int => c1.{self::Class::field}, "Read value from uninitialized Class1.field");
+  c1.{self::Class::field} = 16;
+  self::expect(16, c1.{self::Class::field});
+  self::throws(() → core::int => c1.{self::Class::field} = 17, "Write value to initialized Class.field");
+  self::Subclass c2 = new self::Subclass::constructor2(42);
+  self::expect(42, c2.{self::Class::field});
+  self::throws(() → core::int => c2.{self::Class::field} = 43, "Write value to initialized Class.field");
+  self::Subclass c3 = new self::Subclass::constructor3(87);
+  self::expect(88, c3.{self::Class::field});
+  self::throws(() → core::int => c3.{self::Class::field} = 89, "Write value to initialized Class.field");
+  self::Subclass c4 = new self::Subclass::constructor4();
+  self::expect(87, c4.{self::Class::field});
+  self::throws(() → core::int => c4.{self::Class::field} = 88, "Write value to initialized Class.field");
+  self::Subclass c5 = new self::Subclass::constructor4(123);
+  self::expect(123, c5.{self::Class::field});
+  self::throws(() → core::int => c5.{self::Class::field} = 124, "Write value to initialized Class.field");
+  self::Subclass c6 = new self::Subclass::constructor1();
+  c6.{self::Class::field} = 32;
+  self::expect(32, c6.{self::Class::field});
+  self::throws(() → core::int => c6.{self::Class::field} = 32, "Write value to initialized Class.field");
+}
+static method main() → dynamic {
+  self::test1();
+  self::test2();
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, core::String message) → dynamic {
+  dynamic value;
+  try {
+    value = f.call();
+  }
+  on dynamic catch(final dynamic e) {
+    core::print(e);
+    return;
+  }
+  throw "${message}: ${value}";
+}
+
+constants  {
+  #C1 = 42
+  #C2 = 87
+}
diff --git a/pkg/front_end/testcases/late_lowering/instance_final_field_without_initializer.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/instance_final_field_without_initializer.dart.strong.transformed.expect
new file mode 100644
index 0000000..8e4ad19
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/instance_final_field_without_initializer.dart.strong.transformed.expect
@@ -0,0 +1,110 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  field core::int? _#field = null;
+  constructor constructor1() → self::Class
+    : super core::Object::•()
+    ;
+  constructor constructor2(core::int field) → self::Class
+    : self::Class::_#field = field, super core::Object::•()
+    ;
+  constructor constructor3(core::int value) → self::Class
+    : self::Class::_#field = value.{core::num::+}(1), super core::Object::•()
+    ;
+  constructor constructor4([core::int field = #C1]) → self::Class
+    : self::Class::_#field = field, super core::Object::•()
+    ;
+  get field() → core::int
+    return let final core::int? #t1 = this.{self::Class::_#field} in #t1.==(null) ?{core::int} throw "Field 'field' has not been initialized." : #t1{core::int};
+  set field(core::int #t2) → void
+    if(this.{self::Class::_#field}.==(null))
+      this.{self::Class::_#field} = #t2;
+    else
+      throw "Field 'field' has already been initialized.";
+}
+class Subclass extends self::Class {
+  constructor constructor1() → self::Subclass
+    : super self::Class::constructor1()
+    ;
+  constructor constructor2(core::int value) → self::Subclass
+    : super self::Class::constructor2(value)
+    ;
+  constructor constructor3(core::int value) → self::Subclass
+    : super self::Class::constructor3(value)
+    ;
+  constructor constructor4([core::int value = #C2]) → self::Subclass
+    : super self::Class::constructor4(value)
+    ;
+}
+static method test1() → dynamic {
+  self::Class c1 = new self::Class::constructor1();
+  self::throws(() → core::int => c1.{self::Class::field}, "Read value from uninitialized Class.field");
+  c1.{self::Class::field} = 16;
+  self::expect(16, c1.{self::Class::field});
+  self::throws(() → core::int => c1.{self::Class::field} = 17, "Write value to initialized Class.field");
+  self::Class c2 = new self::Class::constructor2(42);
+  self::expect(42, c2.{self::Class::field});
+  self::throws(() → core::int => c2.{self::Class::field} = 43, "Write value to initialized Class.field");
+  self::Class c3 = new self::Class::constructor3(87);
+  self::expect(88, c3.{self::Class::field});
+  self::throws(() → core::int => c3.{self::Class::field} = 89, "Write value to initialized Class.field");
+  self::Class c4 = new self::Class::constructor4();
+  self::expect(42, c4.{self::Class::field});
+  self::throws(() → core::int => c4.{self::Class::field} = 43, "Write value to initialized Class.field");
+  self::Class c5 = new self::Class::constructor4(123);
+  self::expect(123, c5.{self::Class::field});
+  self::throws(() → core::int => c5.{self::Class::field} = 124, "Write value to initialized Class.field");
+  self::Class c6 = new self::Class::constructor1();
+  c6.{self::Class::field} = 32;
+  self::expect(32, c6.{self::Class::field});
+  self::throws(() → core::int => c6.{self::Class::field} = 32, "Write value to initialized Class.field");
+}
+static method test2() → dynamic {
+  self::Subclass c1 = new self::Subclass::constructor1();
+  self::throws(() → core::int => c1.{self::Class::field}, "Read value from uninitialized Class1.field");
+  c1.{self::Class::field} = 16;
+  self::expect(16, c1.{self::Class::field});
+  self::throws(() → core::int => c1.{self::Class::field} = 17, "Write value to initialized Class.field");
+  self::Subclass c2 = new self::Subclass::constructor2(42);
+  self::expect(42, c2.{self::Class::field});
+  self::throws(() → core::int => c2.{self::Class::field} = 43, "Write value to initialized Class.field");
+  self::Subclass c3 = new self::Subclass::constructor3(87);
+  self::expect(88, c3.{self::Class::field});
+  self::throws(() → core::int => c3.{self::Class::field} = 89, "Write value to initialized Class.field");
+  self::Subclass c4 = new self::Subclass::constructor4();
+  self::expect(87, c4.{self::Class::field});
+  self::throws(() → core::int => c4.{self::Class::field} = 88, "Write value to initialized Class.field");
+  self::Subclass c5 = new self::Subclass::constructor4(123);
+  self::expect(123, c5.{self::Class::field});
+  self::throws(() → core::int => c5.{self::Class::field} = 124, "Write value to initialized Class.field");
+  self::Subclass c6 = new self::Subclass::constructor1();
+  c6.{self::Class::field} = 32;
+  self::expect(32, c6.{self::Class::field});
+  self::throws(() → core::int => c6.{self::Class::field} = 32, "Write value to initialized Class.field");
+}
+static method main() → dynamic {
+  self::test1();
+  self::test2();
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, core::String message) → dynamic {
+  dynamic value;
+  try {
+    value = f.call();
+  }
+  on dynamic catch(final dynamic e) {
+    core::print(e);
+    return;
+  }
+  throw "${message}: ${value}";
+}
+
+constants  {
+  #C1 = 42
+  #C2 = 87
+}
diff --git a/pkg/front_end/testcases/late_lowering/instance_nullable_field_with_initializer.dart b/pkg/front_end/testcases/late_lowering/instance_nullable_field_with_initializer.dart
new file mode 100644
index 0000000..c7bf971
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/instance_nullable_field_with_initializer.dart
@@ -0,0 +1,84 @@
+// Copyright (c) 2019, 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.
+
+int? initField() => 10;
+
+class Class {
+  late int? field = initField();
+
+  Class.constructor1();
+  Class.constructor2(int this.field);
+  Class.constructor3(int value) : this.field = value + 1;
+  Class.constructor4([int this.field = 42]);
+}
+
+class Subclass extends Class {
+  Subclass.constructor1() : super.constructor1();
+  Subclass.constructor2(int value) : super.constructor2(value);
+  Subclass.constructor3(int value) : super.constructor3(value);
+  Subclass.constructor4([int value = 87]) : super.constructor4(value);
+}
+
+test1() {
+  var c1 = new Class.constructor1();
+  expect(10, c1.field);
+  c1.field = 16;
+  expect(16, c1.field);
+
+  var c2 = new Class.constructor2(42);
+  expect(42, c2.field);
+  c2.field = 43;
+  expect(43, c2.field);
+
+  var c3 = new Class.constructor3(87);
+  expect(88, c3.field);
+  c3.field = 89;
+  expect(89, c3.field);
+
+  var c4 = new Class.constructor4();
+  expect(42, c4.field);
+  c4.field = 43;
+  expect(43, c4.field);
+
+  var c5 = new Class.constructor4(123);
+  expect(123, c5.field);
+  c5.field = 124;
+  expect(124, c5.field);
+}
+
+test2() {
+  var c1 = new Subclass.constructor1();
+  expect(10, c1.field);
+  c1.field = 16;
+  expect(16, c1.field);
+
+  var c2 = new Subclass.constructor2(42);
+  expect(42, c2.field);
+  c2.field = 43;
+  expect(43, c2.field);
+
+  var c3 = new Subclass.constructor3(87);
+  expect(88, c3.field);
+  c3.field = 89;
+  expect(89, c3.field);
+
+  var c4 = new Subclass.constructor4();
+  expect(87, c4.field);
+  c4.field = 88;
+  expect(88, c4.field);
+
+  var c5 = new Subclass.constructor4(123);
+  expect(123, c5.field);
+  c5.field = 124;
+  expect(124, c5.field);
+}
+
+main() {
+  test1();
+  test2();
+}
+
+expect(expected, actual) {
+  if (expected != actual) throw 'Expected $expected, actual $actual';
+}
diff --git a/pkg/front_end/testcases/late_lowering/instance_nullable_field_with_initializer.dart.outline.expect b/pkg/front_end/testcases/late_lowering/instance_nullable_field_with_initializer.dart.outline.expect
new file mode 100644
index 0000000..395faa3
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/instance_nullable_field_with_initializer.dart.outline.expect
@@ -0,0 +1,38 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  field core::int? _#field;
+  field dynamic _#field#isSet;
+  constructor constructor1() → self::Class
+    ;
+  constructor constructor2(core::int field) → self::Class
+    ;
+  constructor constructor3(core::int value) → self::Class
+    ;
+  constructor constructor4([core::int field]) → self::Class
+    ;
+  get field() → core::int?;
+  set field(core::int? #t1) → void;
+}
+class Subclass extends self::Class {
+  constructor constructor1() → self::Subclass
+    ;
+  constructor constructor2(core::int value) → self::Subclass
+    ;
+  constructor constructor3(core::int value) → self::Subclass
+    ;
+  constructor constructor4([core::int value]) → self::Subclass
+    ;
+}
+static method initField() → core::int?
+  ;
+static method test1() → dynamic
+  ;
+static method test2() → dynamic
+  ;
+static method main() → dynamic
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
diff --git a/pkg/front_end/testcases/late_lowering/instance_nullable_field_with_initializer.dart.strong.expect b/pkg/front_end/testcases/late_lowering/instance_nullable_field_with_initializer.dart.strong.expect
new file mode 100644
index 0000000..b7e7998
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/instance_nullable_field_with_initializer.dart.strong.expect
@@ -0,0 +1,104 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  field core::int? _#field = null;
+  field dynamic _#field#isSet = false;
+  constructor constructor1() → self::Class
+    : super core::Object::•()
+    ;
+  constructor constructor2(core::int field) → self::Class
+    : self::Class::_#field#isSet = true, self::Class::_#field = field, super core::Object::•()
+    ;
+  constructor constructor3(core::int value) → self::Class
+    : self::Class::_#field#isSet = true, self::Class::_#field = value.{core::num::+}(1), super core::Object::•()
+    ;
+  constructor constructor4([core::int field = #C1]) → self::Class
+    : self::Class::_#field#isSet = true, self::Class::_#field = field, super core::Object::•()
+    ;
+  get field() → core::int? {
+    if(!this.{self::Class::_#field#isSet}) {
+      this.{self::Class::_#field#isSet} = true;
+      this.{self::Class::_#field} = self::initField();
+    }
+    return this.{self::Class::_#field};
+  }
+  set field(core::int? #t1) → void {
+    this.{self::Class::_#field#isSet} = true;
+    this.{self::Class::_#field} = #t1;
+  }
+}
+class Subclass extends self::Class {
+  constructor constructor1() → self::Subclass
+    : super self::Class::constructor1()
+    ;
+  constructor constructor2(core::int value) → self::Subclass
+    : super self::Class::constructor2(value)
+    ;
+  constructor constructor3(core::int value) → self::Subclass
+    : super self::Class::constructor3(value)
+    ;
+  constructor constructor4([core::int value = #C2]) → self::Subclass
+    : super self::Class::constructor4(value)
+    ;
+}
+static method initField() → core::int?
+  return 10;
+static method test1() → dynamic {
+  self::Class c1 = new self::Class::constructor1();
+  self::expect(10, c1.{self::Class::field});
+  c1.{self::Class::field} = 16;
+  self::expect(16, c1.{self::Class::field});
+  self::Class c2 = new self::Class::constructor2(42);
+  self::expect(42, c2.{self::Class::field});
+  c2.{self::Class::field} = 43;
+  self::expect(43, c2.{self::Class::field});
+  self::Class c3 = new self::Class::constructor3(87);
+  self::expect(88, c3.{self::Class::field});
+  c3.{self::Class::field} = 89;
+  self::expect(89, c3.{self::Class::field});
+  self::Class c4 = new self::Class::constructor4();
+  self::expect(42, c4.{self::Class::field});
+  c4.{self::Class::field} = 43;
+  self::expect(43, c4.{self::Class::field});
+  self::Class c5 = new self::Class::constructor4(123);
+  self::expect(123, c5.{self::Class::field});
+  c5.{self::Class::field} = 124;
+  self::expect(124, c5.{self::Class::field});
+}
+static method test2() → dynamic {
+  self::Subclass c1 = new self::Subclass::constructor1();
+  self::expect(10, c1.{self::Class::field});
+  c1.{self::Class::field} = 16;
+  self::expect(16, c1.{self::Class::field});
+  self::Subclass c2 = new self::Subclass::constructor2(42);
+  self::expect(42, c2.{self::Class::field});
+  c2.{self::Class::field} = 43;
+  self::expect(43, c2.{self::Class::field});
+  self::Subclass c3 = new self::Subclass::constructor3(87);
+  self::expect(88, c3.{self::Class::field});
+  c3.{self::Class::field} = 89;
+  self::expect(89, c3.{self::Class::field});
+  self::Subclass c4 = new self::Subclass::constructor4();
+  self::expect(87, c4.{self::Class::field});
+  c4.{self::Class::field} = 88;
+  self::expect(88, c4.{self::Class::field});
+  self::Subclass c5 = new self::Subclass::constructor4(123);
+  self::expect(123, c5.{self::Class::field});
+  c5.{self::Class::field} = 124;
+  self::expect(124, c5.{self::Class::field});
+}
+static method main() → dynamic {
+  self::test1();
+  self::test2();
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+
+constants  {
+  #C1 = 42
+  #C2 = 87
+}
diff --git a/pkg/front_end/testcases/late_lowering/instance_nullable_field_with_initializer.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/instance_nullable_field_with_initializer.dart.strong.transformed.expect
new file mode 100644
index 0000000..b7e7998
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/instance_nullable_field_with_initializer.dart.strong.transformed.expect
@@ -0,0 +1,104 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  field core::int? _#field = null;
+  field dynamic _#field#isSet = false;
+  constructor constructor1() → self::Class
+    : super core::Object::•()
+    ;
+  constructor constructor2(core::int field) → self::Class
+    : self::Class::_#field#isSet = true, self::Class::_#field = field, super core::Object::•()
+    ;
+  constructor constructor3(core::int value) → self::Class
+    : self::Class::_#field#isSet = true, self::Class::_#field = value.{core::num::+}(1), super core::Object::•()
+    ;
+  constructor constructor4([core::int field = #C1]) → self::Class
+    : self::Class::_#field#isSet = true, self::Class::_#field = field, super core::Object::•()
+    ;
+  get field() → core::int? {
+    if(!this.{self::Class::_#field#isSet}) {
+      this.{self::Class::_#field#isSet} = true;
+      this.{self::Class::_#field} = self::initField();
+    }
+    return this.{self::Class::_#field};
+  }
+  set field(core::int? #t1) → void {
+    this.{self::Class::_#field#isSet} = true;
+    this.{self::Class::_#field} = #t1;
+  }
+}
+class Subclass extends self::Class {
+  constructor constructor1() → self::Subclass
+    : super self::Class::constructor1()
+    ;
+  constructor constructor2(core::int value) → self::Subclass
+    : super self::Class::constructor2(value)
+    ;
+  constructor constructor3(core::int value) → self::Subclass
+    : super self::Class::constructor3(value)
+    ;
+  constructor constructor4([core::int value = #C2]) → self::Subclass
+    : super self::Class::constructor4(value)
+    ;
+}
+static method initField() → core::int?
+  return 10;
+static method test1() → dynamic {
+  self::Class c1 = new self::Class::constructor1();
+  self::expect(10, c1.{self::Class::field});
+  c1.{self::Class::field} = 16;
+  self::expect(16, c1.{self::Class::field});
+  self::Class c2 = new self::Class::constructor2(42);
+  self::expect(42, c2.{self::Class::field});
+  c2.{self::Class::field} = 43;
+  self::expect(43, c2.{self::Class::field});
+  self::Class c3 = new self::Class::constructor3(87);
+  self::expect(88, c3.{self::Class::field});
+  c3.{self::Class::field} = 89;
+  self::expect(89, c3.{self::Class::field});
+  self::Class c4 = new self::Class::constructor4();
+  self::expect(42, c4.{self::Class::field});
+  c4.{self::Class::field} = 43;
+  self::expect(43, c4.{self::Class::field});
+  self::Class c5 = new self::Class::constructor4(123);
+  self::expect(123, c5.{self::Class::field});
+  c5.{self::Class::field} = 124;
+  self::expect(124, c5.{self::Class::field});
+}
+static method test2() → dynamic {
+  self::Subclass c1 = new self::Subclass::constructor1();
+  self::expect(10, c1.{self::Class::field});
+  c1.{self::Class::field} = 16;
+  self::expect(16, c1.{self::Class::field});
+  self::Subclass c2 = new self::Subclass::constructor2(42);
+  self::expect(42, c2.{self::Class::field});
+  c2.{self::Class::field} = 43;
+  self::expect(43, c2.{self::Class::field});
+  self::Subclass c3 = new self::Subclass::constructor3(87);
+  self::expect(88, c3.{self::Class::field});
+  c3.{self::Class::field} = 89;
+  self::expect(89, c3.{self::Class::field});
+  self::Subclass c4 = new self::Subclass::constructor4();
+  self::expect(87, c4.{self::Class::field});
+  c4.{self::Class::field} = 88;
+  self::expect(88, c4.{self::Class::field});
+  self::Subclass c5 = new self::Subclass::constructor4(123);
+  self::expect(123, c5.{self::Class::field});
+  c5.{self::Class::field} = 124;
+  self::expect(124, c5.{self::Class::field});
+}
+static method main() → dynamic {
+  self::test1();
+  self::test2();
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+
+constants  {
+  #C1 = 42
+  #C2 = 87
+}
diff --git a/pkg/front_end/testcases/late_lowering/instance_nullable_field_without_initializer.dart b/pkg/front_end/testcases/late_lowering/instance_nullable_field_without_initializer.dart
new file mode 100644
index 0000000..f3497a1
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/instance_nullable_field_without_initializer.dart
@@ -0,0 +1,93 @@
+// Copyright (c) 2019, 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 Class {
+  late int? field;
+
+  Class.constructor1();
+  Class.constructor2(int this.field);
+  Class.constructor3(int value) : this.field = value + 1;
+  Class.constructor4([int this.field = 42]);
+}
+
+class Subclass extends Class {
+  Subclass.constructor1() : super.constructor1();
+  Subclass.constructor2(int value) : super.constructor2(value);
+  Subclass.constructor3(int value) : super.constructor3(value);
+  Subclass.constructor4([int value = 87]) : super.constructor4(value);
+}
+
+test1() {
+  var c1 = new Class.constructor1();
+  throws(() => c1.field, 'Read value from uninitialized Class.field');
+  c1.field = 16;
+  expect(16, c1.field);
+
+  var c2 = new Class.constructor2(42);
+  expect(42, c2.field);
+  c2.field = 43;
+  expect(43, c2.field);
+
+  var c3 = new Class.constructor3(87);
+  expect(88, c3.field);
+  c3.field = 89;
+  expect(89, c3.field);
+
+  var c4 = new Class.constructor4();
+  expect(42, c4.field);
+  c4.field = 43;
+  expect(43, c4.field);
+
+  var c5 = new Class.constructor4(123);
+  expect(123, c5.field);
+  c5.field = 124;
+  expect(124, c5.field);
+}
+
+test2() {
+  var c1 = new Subclass.constructor1();
+  throws(() => c1.field, 'Read value from uninitialized Class.field');
+  c1.field = 16;
+  expect(16, c1.field);
+
+  var c2 = new Subclass.constructor2(42);
+  expect(42, c2.field);
+  c2.field = 43;
+  expect(43, c2.field);
+
+  var c3 = new Subclass.constructor3(87);
+  expect(88, c3.field);
+  c3.field = 89;
+  expect(89, c3.field);
+
+  var c4 = new Subclass.constructor4();
+  expect(87, c4.field);
+  c4.field = 88;
+  expect(88, c4.field);
+
+  var c5 = new Subclass.constructor4(123);
+  expect(123, c5.field);
+  c5.field = 124;
+  expect(124, c5.field);
+}
+
+main() {
+  test1();
+  test2();
+}
+
+expect(expected, actual) {
+  if (expected != actual) throw 'Expected $expected, actual $actual';
+}
+
+throws(f(), String message) {
+  dynamic value;
+  try {
+    value = f();
+  } catch (e) {
+    print(e);
+    return;
+  }
+  throw '$message: $value';
+}
diff --git a/pkg/front_end/testcases/late_lowering/instance_nullable_field_without_initializer.dart.outline.expect b/pkg/front_end/testcases/late_lowering/instance_nullable_field_without_initializer.dart.outline.expect
new file mode 100644
index 0000000..4a4e3d4
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/instance_nullable_field_without_initializer.dart.outline.expect
@@ -0,0 +1,38 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  field core::int? _#field;
+  field dynamic _#field#isSet;
+  constructor constructor1() → self::Class
+    ;
+  constructor constructor2(core::int field) → self::Class
+    ;
+  constructor constructor3(core::int value) → self::Class
+    ;
+  constructor constructor4([core::int field]) → self::Class
+    ;
+  get field() → core::int?;
+  set field(core::int? #t1) → void;
+}
+class Subclass extends self::Class {
+  constructor constructor1() → self::Subclass
+    ;
+  constructor constructor2(core::int value) → self::Subclass
+    ;
+  constructor constructor3(core::int value) → self::Subclass
+    ;
+  constructor constructor4([core::int value]) → self::Subclass
+    ;
+}
+static method test1() → dynamic
+  ;
+static method test2() → dynamic
+  ;
+static method main() → dynamic
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
+static method throws(() → dynamic f, core::String message) → dynamic
+  ;
diff --git a/pkg/front_end/testcases/late_lowering/instance_nullable_field_without_initializer.dart.strong.expect b/pkg/front_end/testcases/late_lowering/instance_nullable_field_without_initializer.dart.strong.expect
new file mode 100644
index 0000000..33b5099
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/instance_nullable_field_without_initializer.dart.strong.expect
@@ -0,0 +1,108 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  field core::int? _#field = null;
+  field dynamic _#field#isSet = false;
+  constructor constructor1() → self::Class
+    : super core::Object::•()
+    ;
+  constructor constructor2(core::int field) → self::Class
+    : self::Class::_#field#isSet = true, self::Class::_#field = field, super core::Object::•()
+    ;
+  constructor constructor3(core::int value) → self::Class
+    : self::Class::_#field#isSet = true, self::Class::_#field = value.{core::num::+}(1), super core::Object::•()
+    ;
+  constructor constructor4([core::int field = #C1]) → self::Class
+    : self::Class::_#field#isSet = true, self::Class::_#field = field, super core::Object::•()
+    ;
+  get field() → core::int?
+    return this.{self::Class::_#field#isSet} ?{core::int?} this.{self::Class::_#field} : throw "Field 'field' has not been initialized.";
+  set field(core::int? #t1) → void {
+    this.{self::Class::_#field#isSet} = true;
+    this.{self::Class::_#field} = #t1;
+  }
+}
+class Subclass extends self::Class {
+  constructor constructor1() → self::Subclass
+    : super self::Class::constructor1()
+    ;
+  constructor constructor2(core::int value) → self::Subclass
+    : super self::Class::constructor2(value)
+    ;
+  constructor constructor3(core::int value) → self::Subclass
+    : super self::Class::constructor3(value)
+    ;
+  constructor constructor4([core::int value = #C2]) → self::Subclass
+    : super self::Class::constructor4(value)
+    ;
+}
+static method test1() → dynamic {
+  self::Class c1 = new self::Class::constructor1();
+  self::throws(() → core::int? => c1.{self::Class::field}, "Read value from uninitialized Class.field");
+  c1.{self::Class::field} = 16;
+  self::expect(16, c1.{self::Class::field});
+  self::Class c2 = new self::Class::constructor2(42);
+  self::expect(42, c2.{self::Class::field});
+  c2.{self::Class::field} = 43;
+  self::expect(43, c2.{self::Class::field});
+  self::Class c3 = new self::Class::constructor3(87);
+  self::expect(88, c3.{self::Class::field});
+  c3.{self::Class::field} = 89;
+  self::expect(89, c3.{self::Class::field});
+  self::Class c4 = new self::Class::constructor4();
+  self::expect(42, c4.{self::Class::field});
+  c4.{self::Class::field} = 43;
+  self::expect(43, c4.{self::Class::field});
+  self::Class c5 = new self::Class::constructor4(123);
+  self::expect(123, c5.{self::Class::field});
+  c5.{self::Class::field} = 124;
+  self::expect(124, c5.{self::Class::field});
+}
+static method test2() → dynamic {
+  self::Subclass c1 = new self::Subclass::constructor1();
+  self::throws(() → core::int? => c1.{self::Class::field}, "Read value from uninitialized Class.field");
+  c1.{self::Class::field} = 16;
+  self::expect(16, c1.{self::Class::field});
+  self::Subclass c2 = new self::Subclass::constructor2(42);
+  self::expect(42, c2.{self::Class::field});
+  c2.{self::Class::field} = 43;
+  self::expect(43, c2.{self::Class::field});
+  self::Subclass c3 = new self::Subclass::constructor3(87);
+  self::expect(88, c3.{self::Class::field});
+  c3.{self::Class::field} = 89;
+  self::expect(89, c3.{self::Class::field});
+  self::Subclass c4 = new self::Subclass::constructor4();
+  self::expect(87, c4.{self::Class::field});
+  c4.{self::Class::field} = 88;
+  self::expect(88, c4.{self::Class::field});
+  self::Subclass c5 = new self::Subclass::constructor4(123);
+  self::expect(123, c5.{self::Class::field});
+  c5.{self::Class::field} = 124;
+  self::expect(124, c5.{self::Class::field});
+}
+static method main() → dynamic {
+  self::test1();
+  self::test2();
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, core::String message) → dynamic {
+  dynamic value;
+  try {
+    value = f.call();
+  }
+  on dynamic catch(final dynamic e) {
+    core::print(e);
+    return;
+  }
+  throw "${message}: ${value}";
+}
+
+constants  {
+  #C1 = 42
+  #C2 = 87
+}
diff --git a/pkg/front_end/testcases/late_lowering/instance_nullable_field_without_initializer.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/instance_nullable_field_without_initializer.dart.strong.transformed.expect
new file mode 100644
index 0000000..33b5099
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/instance_nullable_field_without_initializer.dart.strong.transformed.expect
@@ -0,0 +1,108 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  field core::int? _#field = null;
+  field dynamic _#field#isSet = false;
+  constructor constructor1() → self::Class
+    : super core::Object::•()
+    ;
+  constructor constructor2(core::int field) → self::Class
+    : self::Class::_#field#isSet = true, self::Class::_#field = field, super core::Object::•()
+    ;
+  constructor constructor3(core::int value) → self::Class
+    : self::Class::_#field#isSet = true, self::Class::_#field = value.{core::num::+}(1), super core::Object::•()
+    ;
+  constructor constructor4([core::int field = #C1]) → self::Class
+    : self::Class::_#field#isSet = true, self::Class::_#field = field, super core::Object::•()
+    ;
+  get field() → core::int?
+    return this.{self::Class::_#field#isSet} ?{core::int?} this.{self::Class::_#field} : throw "Field 'field' has not been initialized.";
+  set field(core::int? #t1) → void {
+    this.{self::Class::_#field#isSet} = true;
+    this.{self::Class::_#field} = #t1;
+  }
+}
+class Subclass extends self::Class {
+  constructor constructor1() → self::Subclass
+    : super self::Class::constructor1()
+    ;
+  constructor constructor2(core::int value) → self::Subclass
+    : super self::Class::constructor2(value)
+    ;
+  constructor constructor3(core::int value) → self::Subclass
+    : super self::Class::constructor3(value)
+    ;
+  constructor constructor4([core::int value = #C2]) → self::Subclass
+    : super self::Class::constructor4(value)
+    ;
+}
+static method test1() → dynamic {
+  self::Class c1 = new self::Class::constructor1();
+  self::throws(() → core::int? => c1.{self::Class::field}, "Read value from uninitialized Class.field");
+  c1.{self::Class::field} = 16;
+  self::expect(16, c1.{self::Class::field});
+  self::Class c2 = new self::Class::constructor2(42);
+  self::expect(42, c2.{self::Class::field});
+  c2.{self::Class::field} = 43;
+  self::expect(43, c2.{self::Class::field});
+  self::Class c3 = new self::Class::constructor3(87);
+  self::expect(88, c3.{self::Class::field});
+  c3.{self::Class::field} = 89;
+  self::expect(89, c3.{self::Class::field});
+  self::Class c4 = new self::Class::constructor4();
+  self::expect(42, c4.{self::Class::field});
+  c4.{self::Class::field} = 43;
+  self::expect(43, c4.{self::Class::field});
+  self::Class c5 = new self::Class::constructor4(123);
+  self::expect(123, c5.{self::Class::field});
+  c5.{self::Class::field} = 124;
+  self::expect(124, c5.{self::Class::field});
+}
+static method test2() → dynamic {
+  self::Subclass c1 = new self::Subclass::constructor1();
+  self::throws(() → core::int? => c1.{self::Class::field}, "Read value from uninitialized Class.field");
+  c1.{self::Class::field} = 16;
+  self::expect(16, c1.{self::Class::field});
+  self::Subclass c2 = new self::Subclass::constructor2(42);
+  self::expect(42, c2.{self::Class::field});
+  c2.{self::Class::field} = 43;
+  self::expect(43, c2.{self::Class::field});
+  self::Subclass c3 = new self::Subclass::constructor3(87);
+  self::expect(88, c3.{self::Class::field});
+  c3.{self::Class::field} = 89;
+  self::expect(89, c3.{self::Class::field});
+  self::Subclass c4 = new self::Subclass::constructor4();
+  self::expect(87, c4.{self::Class::field});
+  c4.{self::Class::field} = 88;
+  self::expect(88, c4.{self::Class::field});
+  self::Subclass c5 = new self::Subclass::constructor4(123);
+  self::expect(123, c5.{self::Class::field});
+  c5.{self::Class::field} = 124;
+  self::expect(124, c5.{self::Class::field});
+}
+static method main() → dynamic {
+  self::test1();
+  self::test2();
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, core::String message) → dynamic {
+  dynamic value;
+  try {
+    value = f.call();
+  }
+  on dynamic catch(final dynamic e) {
+    core::print(e);
+    return;
+  }
+  throw "${message}: ${value}";
+}
+
+constants  {
+  #C1 = 42
+  #C2 = 87
+}
diff --git a/pkg/front_end/testcases/late_lowering/instance_nullable_final_field_without_initializer.dart b/pkg/front_end/testcases/late_lowering/instance_nullable_final_field_without_initializer.dart
new file mode 100644
index 0000000..7a79d4a
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/instance_nullable_final_field_without_initializer.dart
@@ -0,0 +1,97 @@
+// Copyright (c) 2019, 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 Class {
+  late final int? field;
+
+  Class.constructor1();
+  Class.constructor2(int this.field);
+  Class.constructor3(int value) : this.field = value + 1;
+  Class.constructor4([int this.field = 42]);
+}
+
+class Subclass extends Class {
+  Subclass.constructor1() : super.constructor1();
+  Subclass.constructor2(int value) : super.constructor2(value);
+  Subclass.constructor3(int value) : super.constructor3(value);
+  Subclass.constructor4([int value = 87]) : super.constructor4(value);
+}
+
+test1() {
+  var c1 = new Class.constructor1();
+  throws(() => c1.field, 'Read value from uninitialized Class.field');
+  c1.field = 16;
+  expect(16, c1.field);
+  throws(() => c1.field = 17, 'Write value to initialized Class.field');
+
+  var c2 = new Class.constructor2(42);
+  expect(42, c2.field);
+  throws(() => c2.field = 43, 'Write value to initialized Class.field');
+
+  var c3 = new Class.constructor3(87);
+  expect(88, c3.field);
+  throws(() => c3.field = 89, 'Write value to initialized Class.field');
+
+  var c4 = new Class.constructor4();
+  expect(42, c4.field);
+  throws(() => c4.field = 43, 'Write value to initialized Class.field');
+
+  var c5 = new Class.constructor4(123);
+  expect(123, c5.field);
+  throws(() => c5.field = 124, 'Write value to initialized Class.field');
+
+  var c6 = new Class.constructor1();
+  c6.field = 32;
+  expect(32, c6.field);
+  throws(() => c6.field = 32, 'Write value to initialized Class.field');
+}
+
+test2() {
+  var c1 = new Subclass.constructor1();
+  throws(() => c1.field, 'Read value from uninitialized Class1.field');
+  c1.field = 16;
+  expect(16, c1.field);
+  throws(() => c1.field = 17, 'Write value to initialized Class.field');
+
+  var c2 = new Subclass.constructor2(42);
+  expect(42, c2.field);
+  throws(() => c2.field = 43, 'Write value to initialized Class.field');
+
+  var c3 = new Subclass.constructor3(87);
+  expect(88, c3.field);
+  throws(() => c3.field = 89, 'Write value to initialized Class.field');
+
+  var c4 = new Subclass.constructor4();
+  expect(87, c4.field);
+  throws(() => c4.field = 88, 'Write value to initialized Class.field');
+
+  var c5 = new Subclass.constructor4(123);
+  expect(123, c5.field);
+  throws(() => c5.field = 124, 'Write value to initialized Class.field');
+
+  var c6 = new Subclass.constructor1();
+  c6.field = 32;
+  expect(32, c6.field);
+  throws(() => c6.field = 32, 'Write value to initialized Class.field');
+}
+
+main() {
+  test1();
+  test2();
+}
+
+expect(expected, actual) {
+  if (expected != actual) throw 'Expected $expected, actual $actual';
+}
+
+throws(f(), String message) {
+  dynamic value;
+  try {
+    value = f();
+  } catch (e) {
+    print(e);
+    return;
+  }
+  throw '$message: $value';
+}
diff --git a/pkg/front_end/testcases/late_lowering/instance_nullable_final_field_without_initializer.dart.outline.expect b/pkg/front_end/testcases/late_lowering/instance_nullable_final_field_without_initializer.dart.outline.expect
new file mode 100644
index 0000000..4a4e3d4
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/instance_nullable_final_field_without_initializer.dart.outline.expect
@@ -0,0 +1,38 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  field core::int? _#field;
+  field dynamic _#field#isSet;
+  constructor constructor1() → self::Class
+    ;
+  constructor constructor2(core::int field) → self::Class
+    ;
+  constructor constructor3(core::int value) → self::Class
+    ;
+  constructor constructor4([core::int field]) → self::Class
+    ;
+  get field() → core::int?;
+  set field(core::int? #t1) → void;
+}
+class Subclass extends self::Class {
+  constructor constructor1() → self::Subclass
+    ;
+  constructor constructor2(core::int value) → self::Subclass
+    ;
+  constructor constructor3(core::int value) → self::Subclass
+    ;
+  constructor constructor4([core::int value]) → self::Subclass
+    ;
+}
+static method test1() → dynamic
+  ;
+static method test2() → dynamic
+  ;
+static method main() → dynamic
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
+static method throws(() → dynamic f, core::String message) → dynamic
+  ;
diff --git a/pkg/front_end/testcases/late_lowering/instance_nullable_final_field_without_initializer.dart.strong.expect b/pkg/front_end/testcases/late_lowering/instance_nullable_final_field_without_initializer.dart.strong.expect
new file mode 100644
index 0000000..f4ff248
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/instance_nullable_final_field_without_initializer.dart.strong.expect
@@ -0,0 +1,113 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  field core::int? _#field = null;
+  field dynamic _#field#isSet = false;
+  constructor constructor1() → self::Class
+    : super core::Object::•()
+    ;
+  constructor constructor2(core::int field) → self::Class
+    : self::Class::_#field#isSet = true, self::Class::_#field = field, super core::Object::•()
+    ;
+  constructor constructor3(core::int value) → self::Class
+    : self::Class::_#field#isSet = true, self::Class::_#field = value.{core::num::+}(1), super core::Object::•()
+    ;
+  constructor constructor4([core::int field = #C1]) → self::Class
+    : self::Class::_#field#isSet = true, self::Class::_#field = field, super core::Object::•()
+    ;
+  get field() → core::int?
+    return this.{self::Class::_#field#isSet} ?{core::int?} this.{self::Class::_#field} : throw "Field 'field' has not been initialized.";
+  set field(core::int? #t1) → void
+    if(this.{self::Class::_#field#isSet})
+      throw "Field 'field' has already been initialized.";
+    else {
+      this.{self::Class::_#field#isSet} = true;
+      this.{self::Class::_#field} = #t1;
+    }
+}
+class Subclass extends self::Class {
+  constructor constructor1() → self::Subclass
+    : super self::Class::constructor1()
+    ;
+  constructor constructor2(core::int value) → self::Subclass
+    : super self::Class::constructor2(value)
+    ;
+  constructor constructor3(core::int value) → self::Subclass
+    : super self::Class::constructor3(value)
+    ;
+  constructor constructor4([core::int value = #C2]) → self::Subclass
+    : super self::Class::constructor4(value)
+    ;
+}
+static method test1() → dynamic {
+  self::Class c1 = new self::Class::constructor1();
+  self::throws(() → core::int? => c1.{self::Class::field}, "Read value from uninitialized Class.field");
+  c1.{self::Class::field} = 16;
+  self::expect(16, c1.{self::Class::field});
+  self::throws(() → core::int => c1.{self::Class::field} = 17, "Write value to initialized Class.field");
+  self::Class c2 = new self::Class::constructor2(42);
+  self::expect(42, c2.{self::Class::field});
+  self::throws(() → core::int => c2.{self::Class::field} = 43, "Write value to initialized Class.field");
+  self::Class c3 = new self::Class::constructor3(87);
+  self::expect(88, c3.{self::Class::field});
+  self::throws(() → core::int => c3.{self::Class::field} = 89, "Write value to initialized Class.field");
+  self::Class c4 = new self::Class::constructor4();
+  self::expect(42, c4.{self::Class::field});
+  self::throws(() → core::int => c4.{self::Class::field} = 43, "Write value to initialized Class.field");
+  self::Class c5 = new self::Class::constructor4(123);
+  self::expect(123, c5.{self::Class::field});
+  self::throws(() → core::int => c5.{self::Class::field} = 124, "Write value to initialized Class.field");
+  self::Class c6 = new self::Class::constructor1();
+  c6.{self::Class::field} = 32;
+  self::expect(32, c6.{self::Class::field});
+  self::throws(() → core::int => c6.{self::Class::field} = 32, "Write value to initialized Class.field");
+}
+static method test2() → dynamic {
+  self::Subclass c1 = new self::Subclass::constructor1();
+  self::throws(() → core::int? => c1.{self::Class::field}, "Read value from uninitialized Class1.field");
+  c1.{self::Class::field} = 16;
+  self::expect(16, c1.{self::Class::field});
+  self::throws(() → core::int => c1.{self::Class::field} = 17, "Write value to initialized Class.field");
+  self::Subclass c2 = new self::Subclass::constructor2(42);
+  self::expect(42, c2.{self::Class::field});
+  self::throws(() → core::int => c2.{self::Class::field} = 43, "Write value to initialized Class.field");
+  self::Subclass c3 = new self::Subclass::constructor3(87);
+  self::expect(88, c3.{self::Class::field});
+  self::throws(() → core::int => c3.{self::Class::field} = 89, "Write value to initialized Class.field");
+  self::Subclass c4 = new self::Subclass::constructor4();
+  self::expect(87, c4.{self::Class::field});
+  self::throws(() → core::int => c4.{self::Class::field} = 88, "Write value to initialized Class.field");
+  self::Subclass c5 = new self::Subclass::constructor4(123);
+  self::expect(123, c5.{self::Class::field});
+  self::throws(() → core::int => c5.{self::Class::field} = 124, "Write value to initialized Class.field");
+  self::Subclass c6 = new self::Subclass::constructor1();
+  c6.{self::Class::field} = 32;
+  self::expect(32, c6.{self::Class::field});
+  self::throws(() → core::int => c6.{self::Class::field} = 32, "Write value to initialized Class.field");
+}
+static method main() → dynamic {
+  self::test1();
+  self::test2();
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, core::String message) → dynamic {
+  dynamic value;
+  try {
+    value = f.call();
+  }
+  on dynamic catch(final dynamic e) {
+    core::print(e);
+    return;
+  }
+  throw "${message}: ${value}";
+}
+
+constants  {
+  #C1 = 42
+  #C2 = 87
+}
diff --git a/pkg/front_end/testcases/late_lowering/instance_nullable_final_field_without_initializer.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/instance_nullable_final_field_without_initializer.dart.strong.transformed.expect
new file mode 100644
index 0000000..f4ff248
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/instance_nullable_final_field_without_initializer.dart.strong.transformed.expect
@@ -0,0 +1,113 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  field core::int? _#field = null;
+  field dynamic _#field#isSet = false;
+  constructor constructor1() → self::Class
+    : super core::Object::•()
+    ;
+  constructor constructor2(core::int field) → self::Class
+    : self::Class::_#field#isSet = true, self::Class::_#field = field, super core::Object::•()
+    ;
+  constructor constructor3(core::int value) → self::Class
+    : self::Class::_#field#isSet = true, self::Class::_#field = value.{core::num::+}(1), super core::Object::•()
+    ;
+  constructor constructor4([core::int field = #C1]) → self::Class
+    : self::Class::_#field#isSet = true, self::Class::_#field = field, super core::Object::•()
+    ;
+  get field() → core::int?
+    return this.{self::Class::_#field#isSet} ?{core::int?} this.{self::Class::_#field} : throw "Field 'field' has not been initialized.";
+  set field(core::int? #t1) → void
+    if(this.{self::Class::_#field#isSet})
+      throw "Field 'field' has already been initialized.";
+    else {
+      this.{self::Class::_#field#isSet} = true;
+      this.{self::Class::_#field} = #t1;
+    }
+}
+class Subclass extends self::Class {
+  constructor constructor1() → self::Subclass
+    : super self::Class::constructor1()
+    ;
+  constructor constructor2(core::int value) → self::Subclass
+    : super self::Class::constructor2(value)
+    ;
+  constructor constructor3(core::int value) → self::Subclass
+    : super self::Class::constructor3(value)
+    ;
+  constructor constructor4([core::int value = #C2]) → self::Subclass
+    : super self::Class::constructor4(value)
+    ;
+}
+static method test1() → dynamic {
+  self::Class c1 = new self::Class::constructor1();
+  self::throws(() → core::int? => c1.{self::Class::field}, "Read value from uninitialized Class.field");
+  c1.{self::Class::field} = 16;
+  self::expect(16, c1.{self::Class::field});
+  self::throws(() → core::int => c1.{self::Class::field} = 17, "Write value to initialized Class.field");
+  self::Class c2 = new self::Class::constructor2(42);
+  self::expect(42, c2.{self::Class::field});
+  self::throws(() → core::int => c2.{self::Class::field} = 43, "Write value to initialized Class.field");
+  self::Class c3 = new self::Class::constructor3(87);
+  self::expect(88, c3.{self::Class::field});
+  self::throws(() → core::int => c3.{self::Class::field} = 89, "Write value to initialized Class.field");
+  self::Class c4 = new self::Class::constructor4();
+  self::expect(42, c4.{self::Class::field});
+  self::throws(() → core::int => c4.{self::Class::field} = 43, "Write value to initialized Class.field");
+  self::Class c5 = new self::Class::constructor4(123);
+  self::expect(123, c5.{self::Class::field});
+  self::throws(() → core::int => c5.{self::Class::field} = 124, "Write value to initialized Class.field");
+  self::Class c6 = new self::Class::constructor1();
+  c6.{self::Class::field} = 32;
+  self::expect(32, c6.{self::Class::field});
+  self::throws(() → core::int => c6.{self::Class::field} = 32, "Write value to initialized Class.field");
+}
+static method test2() → dynamic {
+  self::Subclass c1 = new self::Subclass::constructor1();
+  self::throws(() → core::int? => c1.{self::Class::field}, "Read value from uninitialized Class1.field");
+  c1.{self::Class::field} = 16;
+  self::expect(16, c1.{self::Class::field});
+  self::throws(() → core::int => c1.{self::Class::field} = 17, "Write value to initialized Class.field");
+  self::Subclass c2 = new self::Subclass::constructor2(42);
+  self::expect(42, c2.{self::Class::field});
+  self::throws(() → core::int => c2.{self::Class::field} = 43, "Write value to initialized Class.field");
+  self::Subclass c3 = new self::Subclass::constructor3(87);
+  self::expect(88, c3.{self::Class::field});
+  self::throws(() → core::int => c3.{self::Class::field} = 89, "Write value to initialized Class.field");
+  self::Subclass c4 = new self::Subclass::constructor4();
+  self::expect(87, c4.{self::Class::field});
+  self::throws(() → core::int => c4.{self::Class::field} = 88, "Write value to initialized Class.field");
+  self::Subclass c5 = new self::Subclass::constructor4(123);
+  self::expect(123, c5.{self::Class::field});
+  self::throws(() → core::int => c5.{self::Class::field} = 124, "Write value to initialized Class.field");
+  self::Subclass c6 = new self::Subclass::constructor1();
+  c6.{self::Class::field} = 32;
+  self::expect(32, c6.{self::Class::field});
+  self::throws(() → core::int => c6.{self::Class::field} = 32, "Write value to initialized Class.field");
+}
+static method main() → dynamic {
+  self::test1();
+  self::test2();
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, core::String message) → dynamic {
+  dynamic value;
+  try {
+    value = f.call();
+  }
+  on dynamic catch(final dynamic e) {
+    core::print(e);
+    return;
+  }
+  throw "${message}: ${value}";
+}
+
+constants  {
+  #C1 = 42
+  #C2 = 87
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_field_with_initializer.dart b/pkg/front_end/testcases/late_lowering/late_field_with_initializer.dart
new file mode 100644
index 0000000..ba5046c
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_field_with_initializer.dart
@@ -0,0 +1,41 @@
+// Copyright (c) 2019, 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 lateTopLevelField1 = 123;
+
+class Class {
+  static late int lateStaticField1 = 87;
+  static late int lateStaticField2 = 42;
+
+  static staticMethod() {
+    expect(42, lateStaticField2);
+    lateStaticField2 = 43;
+    expect(43, lateStaticField2);
+  }
+
+  late int lateInstanceField = 16;
+
+  instanceMethod() {
+    expect(16, lateInstanceField);
+    lateInstanceField = 17;
+    expect(17, lateInstanceField);
+  }
+}
+
+main() {
+  expect(123, lateTopLevelField1);
+  lateTopLevelField1 = 124;
+  expect(124, lateTopLevelField1);
+
+  expect(87, Class.lateStaticField1);
+  Class.lateStaticField1 = 88;
+  expect(88, Class.lateStaticField1);
+
+  Class.staticMethod();
+  new Class().instanceMethod();
+}
+
+expect(expected, actual) {
+  if (expected != actual) throw 'Expected $expected, actual $actual';
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_field_with_initializer.dart.outline.expect b/pkg/front_end/testcases/late_lowering/late_field_with_initializer.dart.outline.expect
new file mode 100644
index 0000000..dff7386
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_field_with_initializer.dart.outline.expect
@@ -0,0 +1,28 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  static field core::int? _#lateStaticField1;
+  static field core::int? _#lateStaticField2;
+  field core::int? _#lateInstanceField;
+  synthetic constructor •() → self::Class*
+    ;
+  static get lateStaticField1() → core::int;
+  static set lateStaticField1(core::int #t1) → void;
+  static get lateStaticField2() → core::int;
+  static set lateStaticField2(core::int #t2) → void;
+  static method staticMethod() → dynamic
+    ;
+  get lateInstanceField() → core::int;
+  set lateInstanceField(core::int #t3) → void;
+  method instanceMethod() → dynamic
+    ;
+}
+static field core::int? _#lateTopLevelField1;
+static get lateTopLevelField1() → core::int;
+static set lateTopLevelField1(core::int #t4) → void;
+static method main() → dynamic
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
diff --git a/pkg/front_end/testcases/late_lowering/late_field_with_initializer.dart.strong.expect b/pkg/front_end/testcases/late_lowering/late_field_with_initializer.dart.strong.expect
new file mode 100644
index 0000000..f873e75
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_field_with_initializer.dart.strong.expect
@@ -0,0 +1,53 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  static field core::int? _#lateStaticField1 = null;
+  static field core::int? _#lateStaticField2 = null;
+  field core::int? _#lateInstanceField = null;
+  synthetic constructor •() → self::Class*
+    : super core::Object::•()
+    ;
+  static get lateStaticField1() → core::int
+    return let final core::int? #t1 = self::Class::_#lateStaticField1 in #t1.==(null) ?{core::int} self::Class::_#lateStaticField1 = 87 : #t1{core::int};
+  static set lateStaticField1(core::int #t2) → void
+    self::Class::_#lateStaticField1 = #t2;
+  static get lateStaticField2() → core::int
+    return let final core::int? #t3 = self::Class::_#lateStaticField2 in #t3.==(null) ?{core::int} self::Class::_#lateStaticField2 = 42 : #t3{core::int};
+  static set lateStaticField2(core::int #t4) → void
+    self::Class::_#lateStaticField2 = #t4;
+  static method staticMethod() → dynamic {
+    self::expect(42, self::Class::lateStaticField2);
+    self::Class::lateStaticField2 = 43;
+    self::expect(43, self::Class::lateStaticField2);
+  }
+  get lateInstanceField() → core::int
+    return let final core::int? #t5 = this.{self::Class::_#lateInstanceField} in #t5.==(null) ?{core::int} this.{self::Class::_#lateInstanceField} = 16 : #t5{core::int};
+  set lateInstanceField(core::int #t6) → void
+    this.{self::Class::_#lateInstanceField} = #t6;
+  method instanceMethod() → dynamic {
+    self::expect(16, this.{self::Class::lateInstanceField});
+    this.{self::Class::lateInstanceField} = 17;
+    self::expect(17, this.{self::Class::lateInstanceField});
+  }
+}
+static field core::int? _#lateTopLevelField1 = null;
+static get lateTopLevelField1() → core::int
+  return let final core::int? #t7 = self::_#lateTopLevelField1 in #t7.==(null) ?{core::int} self::_#lateTopLevelField1 = 123 : #t7{core::int};
+static set lateTopLevelField1(core::int #t8) → void
+  self::_#lateTopLevelField1 = #t8;
+static method main() → dynamic {
+  self::expect(123, self::lateTopLevelField1);
+  self::lateTopLevelField1 = 124;
+  self::expect(124, self::lateTopLevelField1);
+  self::expect(87, self::Class::lateStaticField1);
+  self::Class::lateStaticField1 = 88;
+  self::expect(88, self::Class::lateStaticField1);
+  self::Class::staticMethod();
+  new self::Class::•().{self::Class::instanceMethod}();
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_field_with_initializer.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/late_field_with_initializer.dart.strong.transformed.expect
new file mode 100644
index 0000000..f873e75
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_field_with_initializer.dart.strong.transformed.expect
@@ -0,0 +1,53 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  static field core::int? _#lateStaticField1 = null;
+  static field core::int? _#lateStaticField2 = null;
+  field core::int? _#lateInstanceField = null;
+  synthetic constructor •() → self::Class*
+    : super core::Object::•()
+    ;
+  static get lateStaticField1() → core::int
+    return let final core::int? #t1 = self::Class::_#lateStaticField1 in #t1.==(null) ?{core::int} self::Class::_#lateStaticField1 = 87 : #t1{core::int};
+  static set lateStaticField1(core::int #t2) → void
+    self::Class::_#lateStaticField1 = #t2;
+  static get lateStaticField2() → core::int
+    return let final core::int? #t3 = self::Class::_#lateStaticField2 in #t3.==(null) ?{core::int} self::Class::_#lateStaticField2 = 42 : #t3{core::int};
+  static set lateStaticField2(core::int #t4) → void
+    self::Class::_#lateStaticField2 = #t4;
+  static method staticMethod() → dynamic {
+    self::expect(42, self::Class::lateStaticField2);
+    self::Class::lateStaticField2 = 43;
+    self::expect(43, self::Class::lateStaticField2);
+  }
+  get lateInstanceField() → core::int
+    return let final core::int? #t5 = this.{self::Class::_#lateInstanceField} in #t5.==(null) ?{core::int} this.{self::Class::_#lateInstanceField} = 16 : #t5{core::int};
+  set lateInstanceField(core::int #t6) → void
+    this.{self::Class::_#lateInstanceField} = #t6;
+  method instanceMethod() → dynamic {
+    self::expect(16, this.{self::Class::lateInstanceField});
+    this.{self::Class::lateInstanceField} = 17;
+    self::expect(17, this.{self::Class::lateInstanceField});
+  }
+}
+static field core::int? _#lateTopLevelField1 = null;
+static get lateTopLevelField1() → core::int
+  return let final core::int? #t7 = self::_#lateTopLevelField1 in #t7.==(null) ?{core::int} self::_#lateTopLevelField1 = 123 : #t7{core::int};
+static set lateTopLevelField1(core::int #t8) → void
+  self::_#lateTopLevelField1 = #t8;
+static method main() → dynamic {
+  self::expect(123, self::lateTopLevelField1);
+  self::lateTopLevelField1 = 124;
+  self::expect(124, self::lateTopLevelField1);
+  self::expect(87, self::Class::lateStaticField1);
+  self::Class::lateStaticField1 = 88;
+  self::expect(88, self::Class::lateStaticField1);
+  self::Class::staticMethod();
+  new self::Class::•().{self::Class::instanceMethod}();
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_field_without_initializer.dart b/pkg/front_end/testcases/late_lowering/late_field_without_initializer.dart
new file mode 100644
index 0000000..e1b36a4
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_field_without_initializer.dart
@@ -0,0 +1,62 @@
+// Copyright (c) 2019, 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 lateTopLevelField;
+
+class Class {
+  static late int lateStaticField1;
+  static late int lateStaticField2;
+
+  static staticMethod() {
+    throws(() => lateStaticField2,
+        'Read value from uninitialized Class.lateStaticField2');
+    lateStaticField2 = 42;
+    expect(42, lateStaticField2);
+  }
+
+  late int lateInstanceField;
+
+  instanceMethod() {
+    throws(() => lateInstanceField,
+        'Read value from uninitialized Class.lateInstanceField');
+    lateInstanceField = 16;
+    expect(16, lateInstanceField);
+  }
+}
+
+main() {
+  throws(() => lateTopLevelField,
+      'Read value from uninitialized lateTopLevelField');
+  lateTopLevelField = 123;
+  expect(123, lateTopLevelField);
+
+  throws(() => Class.lateStaticField1,
+      'Read value from uninitialized Class.lateStaticField1');
+  Class.lateStaticField1 = 87;
+  expect(87, Class.lateStaticField1);
+
+  Class.staticMethod();
+  new Class().instanceMethod();
+
+  var c = new Class();
+  throws(() => c.lateInstanceField,
+      'Read value from uninitialized Class.lateInstanceField');
+  c.lateInstanceField = 16;
+  expect(16, c.lateInstanceField);
+}
+
+expect(expected, actual) {
+  if (expected != actual) throw 'Expected $expected, actual $actual';
+}
+
+throws(f(), String message) {
+  dynamic value;
+  try {
+    value = f();
+  } catch (e) {
+    print(e);
+    return;
+  }
+  throw '$message: $value';
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_field_without_initializer.dart.outline.expect b/pkg/front_end/testcases/late_lowering/late_field_without_initializer.dart.outline.expect
new file mode 100644
index 0000000..553fa89
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_field_without_initializer.dart.outline.expect
@@ -0,0 +1,30 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  static field core::int? _#lateStaticField1;
+  static field core::int? _#lateStaticField2;
+  field core::int? _#lateInstanceField;
+  synthetic constructor •() → self::Class*
+    ;
+  static get lateStaticField1() → core::int;
+  static set lateStaticField1(core::int #t1) → void;
+  static get lateStaticField2() → core::int;
+  static set lateStaticField2(core::int #t2) → void;
+  static method staticMethod() → dynamic
+    ;
+  get lateInstanceField() → core::int;
+  set lateInstanceField(core::int #t3) → void;
+  method instanceMethod() → dynamic
+    ;
+}
+static field core::int? _#lateTopLevelField;
+static get lateTopLevelField() → core::int;
+static set lateTopLevelField(core::int #t4) → void;
+static method main() → dynamic
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
+static method throws(() → dynamic f, core::String message) → dynamic
+  ;
diff --git a/pkg/front_end/testcases/late_lowering/late_field_without_initializer.dart.strong.expect b/pkg/front_end/testcases/late_lowering/late_field_without_initializer.dart.strong.expect
new file mode 100644
index 0000000..a61fbc2
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_field_without_initializer.dart.strong.expect
@@ -0,0 +1,68 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  static field core::int? _#lateStaticField1 = null;
+  static field core::int? _#lateStaticField2 = null;
+  field core::int? _#lateInstanceField = null;
+  synthetic constructor •() → self::Class*
+    : super core::Object::•()
+    ;
+  static get lateStaticField1() → core::int
+    return let final core::int? #t1 = self::Class::_#lateStaticField1 in #t1.==(null) ?{core::int} throw "Field 'lateStaticField1' has not been initialized." : #t1{core::int};
+  static set lateStaticField1(core::int #t2) → void
+    self::Class::_#lateStaticField1 = #t2;
+  static get lateStaticField2() → core::int
+    return let final core::int? #t3 = self::Class::_#lateStaticField2 in #t3.==(null) ?{core::int} throw "Field 'lateStaticField2' has not been initialized." : #t3{core::int};
+  static set lateStaticField2(core::int #t4) → void
+    self::Class::_#lateStaticField2 = #t4;
+  static method staticMethod() → dynamic {
+    self::throws(() → core::int => self::Class::lateStaticField2, "Read value from uninitialized Class.lateStaticField2");
+    self::Class::lateStaticField2 = 42;
+    self::expect(42, self::Class::lateStaticField2);
+  }
+  get lateInstanceField() → core::int
+    return let final core::int? #t5 = this.{self::Class::_#lateInstanceField} in #t5.==(null) ?{core::int} throw "Field 'lateInstanceField' has not been initialized." : #t5{core::int};
+  set lateInstanceField(core::int #t6) → void
+    this.{self::Class::_#lateInstanceField} = #t6;
+  method instanceMethod() → dynamic {
+    self::throws(() → core::int => this.{self::Class::lateInstanceField}, "Read value from uninitialized Class.lateInstanceField");
+    this.{self::Class::lateInstanceField} = 16;
+    self::expect(16, this.{self::Class::lateInstanceField});
+  }
+}
+static field core::int? _#lateTopLevelField = null;
+static get lateTopLevelField() → core::int
+  return let final core::int? #t7 = self::_#lateTopLevelField in #t7.==(null) ?{core::int} throw "Field 'lateTopLevelField' has not been initialized." : #t7{core::int};
+static set lateTopLevelField(core::int #t8) → void
+  self::_#lateTopLevelField = #t8;
+static method main() → dynamic {
+  self::throws(() → core::int => self::lateTopLevelField, "Read value from uninitialized lateTopLevelField");
+  self::lateTopLevelField = 123;
+  self::expect(123, self::lateTopLevelField);
+  self::throws(() → core::int => self::Class::lateStaticField1, "Read value from uninitialized Class.lateStaticField1");
+  self::Class::lateStaticField1 = 87;
+  self::expect(87, self::Class::lateStaticField1);
+  self::Class::staticMethod();
+  new self::Class::•().{self::Class::instanceMethod}();
+  self::Class c = new self::Class::•();
+  self::throws(() → core::int => c.{self::Class::lateInstanceField}, "Read value from uninitialized Class.lateInstanceField");
+  c.{self::Class::lateInstanceField} = 16;
+  self::expect(16, c.{self::Class::lateInstanceField});
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, core::String message) → dynamic {
+  dynamic value;
+  try {
+    value = f.call();
+  }
+  on dynamic catch(final dynamic e) {
+    core::print(e);
+    return;
+  }
+  throw "${message}: ${value}";
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_field_without_initializer.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/late_field_without_initializer.dart.strong.transformed.expect
new file mode 100644
index 0000000..a61fbc2
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_field_without_initializer.dart.strong.transformed.expect
@@ -0,0 +1,68 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  static field core::int? _#lateStaticField1 = null;
+  static field core::int? _#lateStaticField2 = null;
+  field core::int? _#lateInstanceField = null;
+  synthetic constructor •() → self::Class*
+    : super core::Object::•()
+    ;
+  static get lateStaticField1() → core::int
+    return let final core::int? #t1 = self::Class::_#lateStaticField1 in #t1.==(null) ?{core::int} throw "Field 'lateStaticField1' has not been initialized." : #t1{core::int};
+  static set lateStaticField1(core::int #t2) → void
+    self::Class::_#lateStaticField1 = #t2;
+  static get lateStaticField2() → core::int
+    return let final core::int? #t3 = self::Class::_#lateStaticField2 in #t3.==(null) ?{core::int} throw "Field 'lateStaticField2' has not been initialized." : #t3{core::int};
+  static set lateStaticField2(core::int #t4) → void
+    self::Class::_#lateStaticField2 = #t4;
+  static method staticMethod() → dynamic {
+    self::throws(() → core::int => self::Class::lateStaticField2, "Read value from uninitialized Class.lateStaticField2");
+    self::Class::lateStaticField2 = 42;
+    self::expect(42, self::Class::lateStaticField2);
+  }
+  get lateInstanceField() → core::int
+    return let final core::int? #t5 = this.{self::Class::_#lateInstanceField} in #t5.==(null) ?{core::int} throw "Field 'lateInstanceField' has not been initialized." : #t5{core::int};
+  set lateInstanceField(core::int #t6) → void
+    this.{self::Class::_#lateInstanceField} = #t6;
+  method instanceMethod() → dynamic {
+    self::throws(() → core::int => this.{self::Class::lateInstanceField}, "Read value from uninitialized Class.lateInstanceField");
+    this.{self::Class::lateInstanceField} = 16;
+    self::expect(16, this.{self::Class::lateInstanceField});
+  }
+}
+static field core::int? _#lateTopLevelField = null;
+static get lateTopLevelField() → core::int
+  return let final core::int? #t7 = self::_#lateTopLevelField in #t7.==(null) ?{core::int} throw "Field 'lateTopLevelField' has not been initialized." : #t7{core::int};
+static set lateTopLevelField(core::int #t8) → void
+  self::_#lateTopLevelField = #t8;
+static method main() → dynamic {
+  self::throws(() → core::int => self::lateTopLevelField, "Read value from uninitialized lateTopLevelField");
+  self::lateTopLevelField = 123;
+  self::expect(123, self::lateTopLevelField);
+  self::throws(() → core::int => self::Class::lateStaticField1, "Read value from uninitialized Class.lateStaticField1");
+  self::Class::lateStaticField1 = 87;
+  self::expect(87, self::Class::lateStaticField1);
+  self::Class::staticMethod();
+  new self::Class::•().{self::Class::instanceMethod}();
+  self::Class c = new self::Class::•();
+  self::throws(() → core::int => c.{self::Class::lateInstanceField}, "Read value from uninitialized Class.lateInstanceField");
+  c.{self::Class::lateInstanceField} = 16;
+  self::expect(16, c.{self::Class::lateInstanceField});
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, core::String message) → dynamic {
+  dynamic value;
+  try {
+    value = f.call();
+  }
+  on dynamic catch(final dynamic e) {
+    core::print(e);
+    return;
+  }
+  throw "${message}: ${value}";
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_field_without_initializer.dart.type_promotion.expect b/pkg/front_end/testcases/late_lowering/late_field_without_initializer.dart.type_promotion.expect
new file mode 100644
index 0000000..8fd2b5a
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_field_without_initializer.dart.type_promotion.expect
@@ -0,0 +1,3 @@
+pkg/front_end/testcases/late_lowering/late_field_without_initializer.dart:40:11: Context: Write to value@1029
+    value = f();
+          ^
diff --git a/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart b/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart
new file mode 100644
index 0000000..0fba375
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart
@@ -0,0 +1,62 @@
+// Copyright (c) 2019, 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.
+
+int? lateTopLevelField1Init;
+int initLateTopLevelField1(int value) {
+  return lateTopLevelField1Init = value;
+}
+
+late final int lateTopLevelField1 = initLateTopLevelField1(123);
+
+class Class {
+  static int? lateStaticField1Init;
+  static int initLateStaticField1(int value) {
+    return lateStaticField1Init = value;
+  }
+
+  static late final int lateStaticField1 = initLateStaticField1(87);
+
+  static int? lateStaticField2Init;
+  static int initLateStaticField2(int value) {
+    return lateStaticField2Init = value;
+  }
+
+  static late final int lateStaticField2 = initLateStaticField2(42);
+
+  static staticMethod() {
+    expect(null, lateStaticField2Init);
+    expect(42, lateStaticField2);
+    expect(42, lateStaticField2Init);
+  }
+
+  int? lateInstanceFieldInit;
+  int initLateInstanceField(int value) {
+    return lateInstanceFieldInit = value;
+  }
+
+  late final int lateInstanceField = initLateInstanceField(16);
+
+  instanceMethod() {
+    expect(null, lateInstanceFieldInit);
+    expect(16, lateInstanceField);
+    expect(16, lateInstanceFieldInit);
+  }
+}
+
+main() {
+  expect(null, lateTopLevelField1Init);
+  expect(123, lateTopLevelField1);
+  expect(123, lateTopLevelField1Init);
+
+  expect(null, Class.lateStaticField1Init);
+  expect(87, Class.lateStaticField1);
+  expect(87, Class.lateStaticField1Init);
+
+  Class.staticMethod();
+  new Class().instanceMethod();
+}
+
+expect(expected, actual) {
+  if (expected != actual) throw 'Expected $expected, actual $actual';
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.outline.expect b/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.outline.expect
new file mode 100644
index 0000000..42bc15e
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.outline.expect
@@ -0,0 +1,36 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  static field core::int? lateStaticField1Init;
+  static field core::int? _#lateStaticField1;
+  static field core::int? lateStaticField2Init;
+  static field core::int? _#lateStaticField2;
+  field core::int? lateInstanceFieldInit;
+  field core::int? _#lateInstanceField;
+  synthetic constructor •() → self::Class*
+    ;
+  static method initLateStaticField1(core::int value) → core::int
+    ;
+  static get lateStaticField1() → core::int;
+  static method initLateStaticField2(core::int value) → core::int
+    ;
+  static get lateStaticField2() → core::int;
+  static method staticMethod() → dynamic
+    ;
+  method initLateInstanceField(core::int value) → core::int
+    ;
+  get lateInstanceField() → core::int;
+  method instanceMethod() → dynamic
+    ;
+}
+static field core::int? lateTopLevelField1Init;
+static field core::int? _#lateTopLevelField1;
+static method initLateTopLevelField1(core::int value) → core::int
+  ;
+static get lateTopLevelField1() → core::int;
+static method main() → dynamic
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
diff --git a/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.strong.expect b/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.strong.expect
new file mode 100644
index 0000000..69ddb3c
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.strong.expect
@@ -0,0 +1,61 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  static field core::int? lateStaticField1Init = null;
+  static field core::int? _#lateStaticField1 = null;
+  static field core::int? lateStaticField2Init = null;
+  static field core::int? _#lateStaticField2 = null;
+  field core::int? lateInstanceFieldInit = null;
+  field core::int? _#lateInstanceField = null;
+  synthetic constructor •() → self::Class*
+    : super core::Object::•()
+    ;
+  static method initLateStaticField1(core::int value) → core::int {
+    return self::Class::lateStaticField1Init = value;
+  }
+  static get lateStaticField1() → core::int
+    return let final core::int? #t1 = self::Class::_#lateStaticField1 in #t1.==(null) ?{core::int} self::Class::_#lateStaticField1 = self::Class::initLateStaticField1(87) : #t1{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? #t2 = self::Class::_#lateStaticField2 in #t2.==(null) ?{core::int} self::Class::_#lateStaticField2 = self::Class::initLateStaticField2(42) : #t2{core::int};
+  static method staticMethod() → dynamic {
+    self::expect(null, self::Class::lateStaticField2Init);
+    self::expect(42, self::Class::lateStaticField2);
+    self::expect(42, self::Class::lateStaticField2Init);
+  }
+  method initLateInstanceField(core::int value) → core::int {
+    return this.{self::Class::lateInstanceFieldInit} = value;
+  }
+  get lateInstanceField() → core::int
+    return let final core::int? #t3 = this.{self::Class::_#lateInstanceField} in #t3.==(null) ?{core::int} this.{self::Class::_#lateInstanceField} = this.{self::Class::initLateInstanceField}(16) : #t3{core::int};
+  method instanceMethod() → dynamic {
+    self::expect(null, this.{self::Class::lateInstanceFieldInit});
+    self::expect(16, this.{self::Class::lateInstanceField});
+    self::expect(16, this.{self::Class::lateInstanceFieldInit});
+  }
+}
+static field core::int? lateTopLevelField1Init;
+static field core::int? _#lateTopLevelField1 = null;
+static method initLateTopLevelField1(core::int value) → core::int {
+  return self::lateTopLevelField1Init = value;
+}
+static get lateTopLevelField1() → core::int
+  return let final core::int? #t4 = self::_#lateTopLevelField1 in #t4.==(null) ?{core::int} self::_#lateTopLevelField1 = self::initLateTopLevelField1(123) : #t4{core::int};
+static method main() → dynamic {
+  self::expect(null, self::lateTopLevelField1Init);
+  self::expect(123, self::lateTopLevelField1);
+  self::expect(123, self::lateTopLevelField1Init);
+  self::expect(null, self::Class::lateStaticField1Init);
+  self::expect(87, self::Class::lateStaticField1);
+  self::expect(87, self::Class::lateStaticField1Init);
+  self::Class::staticMethod();
+  new self::Class::•().{self::Class::instanceMethod}();
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.strong.transformed.expect
new file mode 100644
index 0000000..69ddb3c
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_final_field_with_initializer.dart.strong.transformed.expect
@@ -0,0 +1,61 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  static field core::int? lateStaticField1Init = null;
+  static field core::int? _#lateStaticField1 = null;
+  static field core::int? lateStaticField2Init = null;
+  static field core::int? _#lateStaticField2 = null;
+  field core::int? lateInstanceFieldInit = null;
+  field core::int? _#lateInstanceField = null;
+  synthetic constructor •() → self::Class*
+    : super core::Object::•()
+    ;
+  static method initLateStaticField1(core::int value) → core::int {
+    return self::Class::lateStaticField1Init = value;
+  }
+  static get lateStaticField1() → core::int
+    return let final core::int? #t1 = self::Class::_#lateStaticField1 in #t1.==(null) ?{core::int} self::Class::_#lateStaticField1 = self::Class::initLateStaticField1(87) : #t1{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? #t2 = self::Class::_#lateStaticField2 in #t2.==(null) ?{core::int} self::Class::_#lateStaticField2 = self::Class::initLateStaticField2(42) : #t2{core::int};
+  static method staticMethod() → dynamic {
+    self::expect(null, self::Class::lateStaticField2Init);
+    self::expect(42, self::Class::lateStaticField2);
+    self::expect(42, self::Class::lateStaticField2Init);
+  }
+  method initLateInstanceField(core::int value) → core::int {
+    return this.{self::Class::lateInstanceFieldInit} = value;
+  }
+  get lateInstanceField() → core::int
+    return let final core::int? #t3 = this.{self::Class::_#lateInstanceField} in #t3.==(null) ?{core::int} this.{self::Class::_#lateInstanceField} = this.{self::Class::initLateInstanceField}(16) : #t3{core::int};
+  method instanceMethod() → dynamic {
+    self::expect(null, this.{self::Class::lateInstanceFieldInit});
+    self::expect(16, this.{self::Class::lateInstanceField});
+    self::expect(16, this.{self::Class::lateInstanceFieldInit});
+  }
+}
+static field core::int? lateTopLevelField1Init;
+static field core::int? _#lateTopLevelField1 = null;
+static method initLateTopLevelField1(core::int value) → core::int {
+  return self::lateTopLevelField1Init = value;
+}
+static get lateTopLevelField1() → core::int
+  return let final core::int? #t4 = self::_#lateTopLevelField1 in #t4.==(null) ?{core::int} self::_#lateTopLevelField1 = self::initLateTopLevelField1(123) : #t4{core::int};
+static method main() → dynamic {
+  self::expect(null, self::lateTopLevelField1Init);
+  self::expect(123, self::lateTopLevelField1);
+  self::expect(123, self::lateTopLevelField1Init);
+  self::expect(null, self::Class::lateStaticField1Init);
+  self::expect(87, self::Class::lateStaticField1);
+  self::expect(87, self::Class::lateStaticField1Init);
+  self::Class::staticMethod();
+  new self::Class::•().{self::Class::instanceMethod}();
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_final_field_without_initializer.dart b/pkg/front_end/testcases/late_lowering/late_final_field_without_initializer.dart
new file mode 100644
index 0000000..b209f6f
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_final_field_without_initializer.dart
@@ -0,0 +1,64 @@
+// Copyright (c) 2019, 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 final int lateTopLevelField;
+
+class Class {
+  static late final int lateStaticField1;
+  static late final int lateStaticField2;
+
+  static staticMethod() {
+    throws(() => lateStaticField2,
+        'Read value from uninitialized Class.lateStaticField2');
+    lateStaticField2 = 42;
+    expect(42, lateStaticField2);
+    throws(() => lateStaticField2 = 43,
+        'Write value to initialized Class.lateStaticField2');
+  }
+
+  late final int lateInstanceField;
+
+  instanceMethod() {
+    throws(() => lateInstanceField,
+        'Read value from uninitialized Class.lateInstanceField');
+    lateInstanceField = 16;
+    expect(16, lateInstanceField);
+    throws(() => lateInstanceField = 17,
+        'Write value to initialized Class.lateInstanceField');
+  }
+}
+
+main() {
+  throws(() => lateTopLevelField,
+      'Read value from uninitialized lateTopLevelField');
+  lateTopLevelField = 123;
+  expect(123, lateTopLevelField);
+  throws(() => lateTopLevelField = 124,
+      'Write value to initialized lateTopLevelField');
+
+  throws(() => Class.lateStaticField1,
+      'Read value from uninitialized Class.lateStaticField1');
+  Class.lateStaticField1 = 87;
+  expect(87, Class.lateStaticField1);
+  throws(() => Class.lateStaticField1 = 88,
+      'Write value to initialized Class.lateStaticField1');
+
+  Class.staticMethod();
+  new Class().instanceMethod();
+}
+
+expect(expected, actual) {
+  if (expected != actual) throw 'Expected $expected, actual $actual';
+}
+
+throws(f(), String message) {
+  dynamic value;
+  try {
+    value = f();
+  } catch (e) {
+    print(e);
+    return;
+  }
+  throw '$message: $value';
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_final_field_without_initializer.dart.outline.expect b/pkg/front_end/testcases/late_lowering/late_final_field_without_initializer.dart.outline.expect
new file mode 100644
index 0000000..553fa89
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_final_field_without_initializer.dart.outline.expect
@@ -0,0 +1,30 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  static field core::int? _#lateStaticField1;
+  static field core::int? _#lateStaticField2;
+  field core::int? _#lateInstanceField;
+  synthetic constructor •() → self::Class*
+    ;
+  static get lateStaticField1() → core::int;
+  static set lateStaticField1(core::int #t1) → void;
+  static get lateStaticField2() → core::int;
+  static set lateStaticField2(core::int #t2) → void;
+  static method staticMethod() → dynamic
+    ;
+  get lateInstanceField() → core::int;
+  set lateInstanceField(core::int #t3) → void;
+  method instanceMethod() → dynamic
+    ;
+}
+static field core::int? _#lateTopLevelField;
+static get lateTopLevelField() → core::int;
+static set lateTopLevelField(core::int #t4) → void;
+static method main() → dynamic
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
+static method throws(() → dynamic f, core::String message) → dynamic
+  ;
diff --git a/pkg/front_end/testcases/late_lowering/late_final_field_without_initializer.dart.strong.expect b/pkg/front_end/testcases/late_lowering/late_final_field_without_initializer.dart.strong.expect
new file mode 100644
index 0000000..0617737
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_final_field_without_initializer.dart.strong.expect
@@ -0,0 +1,80 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  static field core::int? _#lateStaticField1 = null;
+  static field core::int? _#lateStaticField2 = null;
+  field core::int? _#lateInstanceField = null;
+  synthetic constructor •() → self::Class*
+    : super core::Object::•()
+    ;
+  static get lateStaticField1() → core::int
+    return let final core::int? #t1 = self::Class::_#lateStaticField1 in #t1.==(null) ?{core::int} throw "Field 'lateStaticField1' has not been initialized." : #t1{core::int};
+  static set lateStaticField1(core::int #t2) → void
+    if(self::Class::_#lateStaticField1.==(null))
+      self::Class::_#lateStaticField1 = #t2;
+    else
+      throw "Field 'lateStaticField1' has already been initialized.";
+  static get lateStaticField2() → core::int
+    return let final core::int? #t3 = self::Class::_#lateStaticField2 in #t3.==(null) ?{core::int} throw "Field 'lateStaticField2' has not been initialized." : #t3{core::int};
+  static set lateStaticField2(core::int #t4) → void
+    if(self::Class::_#lateStaticField2.==(null))
+      self::Class::_#lateStaticField2 = #t4;
+    else
+      throw "Field 'lateStaticField2' has already been initialized.";
+  static method staticMethod() → dynamic {
+    self::throws(() → core::int => self::Class::lateStaticField2, "Read value from uninitialized Class.lateStaticField2");
+    self::Class::lateStaticField2 = 42;
+    self::expect(42, self::Class::lateStaticField2);
+    self::throws(() → core::int => self::Class::lateStaticField2 = 43, "Write value to initialized Class.lateStaticField2");
+  }
+  get lateInstanceField() → core::int
+    return let final core::int? #t5 = this.{self::Class::_#lateInstanceField} in #t5.==(null) ?{core::int} throw "Field 'lateInstanceField' has not been initialized." : #t5{core::int};
+  set lateInstanceField(core::int #t6) → void
+    if(this.{self::Class::_#lateInstanceField}.==(null))
+      this.{self::Class::_#lateInstanceField} = #t6;
+    else
+      throw "Field 'lateInstanceField' has already been initialized.";
+  method instanceMethod() → dynamic {
+    self::throws(() → core::int => this.{self::Class::lateInstanceField}, "Read value from uninitialized Class.lateInstanceField");
+    this.{self::Class::lateInstanceField} = 16;
+    self::expect(16, this.{self::Class::lateInstanceField});
+    self::throws(() → core::int => this.{self::Class::lateInstanceField} = 17, "Write value to initialized Class.lateInstanceField");
+  }
+}
+static field core::int? _#lateTopLevelField = null;
+static get lateTopLevelField() → core::int
+  return let final core::int? #t7 = self::_#lateTopLevelField in #t7.==(null) ?{core::int} throw "Field 'lateTopLevelField' has not been initialized." : #t7{core::int};
+static set lateTopLevelField(core::int #t8) → void
+  if(self::_#lateTopLevelField.==(null))
+    self::_#lateTopLevelField = #t8;
+  else
+    throw "Field 'lateTopLevelField' has already been initialized.";
+static method main() → dynamic {
+  self::throws(() → core::int => self::lateTopLevelField, "Read value from uninitialized lateTopLevelField");
+  self::lateTopLevelField = 123;
+  self::expect(123, self::lateTopLevelField);
+  self::throws(() → core::int => self::lateTopLevelField = 124, "Write value to initialized lateTopLevelField");
+  self::throws(() → core::int => self::Class::lateStaticField1, "Read value from uninitialized Class.lateStaticField1");
+  self::Class::lateStaticField1 = 87;
+  self::expect(87, self::Class::lateStaticField1);
+  self::throws(() → core::int => self::Class::lateStaticField1 = 88, "Write value to initialized Class.lateStaticField1");
+  self::Class::staticMethod();
+  new self::Class::•().{self::Class::instanceMethod}();
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, core::String message) → dynamic {
+  dynamic value;
+  try {
+    value = f.call();
+  }
+  on dynamic catch(final dynamic e) {
+    core::print(e);
+    return;
+  }
+  throw "${message}: ${value}";
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_final_field_without_initializer.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/late_final_field_without_initializer.dart.strong.transformed.expect
new file mode 100644
index 0000000..0617737
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_final_field_without_initializer.dart.strong.transformed.expect
@@ -0,0 +1,80 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  static field core::int? _#lateStaticField1 = null;
+  static field core::int? _#lateStaticField2 = null;
+  field core::int? _#lateInstanceField = null;
+  synthetic constructor •() → self::Class*
+    : super core::Object::•()
+    ;
+  static get lateStaticField1() → core::int
+    return let final core::int? #t1 = self::Class::_#lateStaticField1 in #t1.==(null) ?{core::int} throw "Field 'lateStaticField1' has not been initialized." : #t1{core::int};
+  static set lateStaticField1(core::int #t2) → void
+    if(self::Class::_#lateStaticField1.==(null))
+      self::Class::_#lateStaticField1 = #t2;
+    else
+      throw "Field 'lateStaticField1' has already been initialized.";
+  static get lateStaticField2() → core::int
+    return let final core::int? #t3 = self::Class::_#lateStaticField2 in #t3.==(null) ?{core::int} throw "Field 'lateStaticField2' has not been initialized." : #t3{core::int};
+  static set lateStaticField2(core::int #t4) → void
+    if(self::Class::_#lateStaticField2.==(null))
+      self::Class::_#lateStaticField2 = #t4;
+    else
+      throw "Field 'lateStaticField2' has already been initialized.";
+  static method staticMethod() → dynamic {
+    self::throws(() → core::int => self::Class::lateStaticField2, "Read value from uninitialized Class.lateStaticField2");
+    self::Class::lateStaticField2 = 42;
+    self::expect(42, self::Class::lateStaticField2);
+    self::throws(() → core::int => self::Class::lateStaticField2 = 43, "Write value to initialized Class.lateStaticField2");
+  }
+  get lateInstanceField() → core::int
+    return let final core::int? #t5 = this.{self::Class::_#lateInstanceField} in #t5.==(null) ?{core::int} throw "Field 'lateInstanceField' has not been initialized." : #t5{core::int};
+  set lateInstanceField(core::int #t6) → void
+    if(this.{self::Class::_#lateInstanceField}.==(null))
+      this.{self::Class::_#lateInstanceField} = #t6;
+    else
+      throw "Field 'lateInstanceField' has already been initialized.";
+  method instanceMethod() → dynamic {
+    self::throws(() → core::int => this.{self::Class::lateInstanceField}, "Read value from uninitialized Class.lateInstanceField");
+    this.{self::Class::lateInstanceField} = 16;
+    self::expect(16, this.{self::Class::lateInstanceField});
+    self::throws(() → core::int => this.{self::Class::lateInstanceField} = 17, "Write value to initialized Class.lateInstanceField");
+  }
+}
+static field core::int? _#lateTopLevelField = null;
+static get lateTopLevelField() → core::int
+  return let final core::int? #t7 = self::_#lateTopLevelField in #t7.==(null) ?{core::int} throw "Field 'lateTopLevelField' has not been initialized." : #t7{core::int};
+static set lateTopLevelField(core::int #t8) → void
+  if(self::_#lateTopLevelField.==(null))
+    self::_#lateTopLevelField = #t8;
+  else
+    throw "Field 'lateTopLevelField' has already been initialized.";
+static method main() → dynamic {
+  self::throws(() → core::int => self::lateTopLevelField, "Read value from uninitialized lateTopLevelField");
+  self::lateTopLevelField = 123;
+  self::expect(123, self::lateTopLevelField);
+  self::throws(() → core::int => self::lateTopLevelField = 124, "Write value to initialized lateTopLevelField");
+  self::throws(() → core::int => self::Class::lateStaticField1, "Read value from uninitialized Class.lateStaticField1");
+  self::Class::lateStaticField1 = 87;
+  self::expect(87, self::Class::lateStaticField1);
+  self::throws(() → core::int => self::Class::lateStaticField1 = 88, "Write value to initialized Class.lateStaticField1");
+  self::Class::staticMethod();
+  new self::Class::•().{self::Class::instanceMethod}();
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, core::String message) → dynamic {
+  dynamic value;
+  try {
+    value = f.call();
+  }
+  on dynamic catch(final dynamic e) {
+    core::print(e);
+    return;
+  }
+  throw "${message}: ${value}";
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_final_field_without_initializer.dart.type_promotion.expect b/pkg/front_end/testcases/late_lowering/late_final_field_without_initializer.dart.type_promotion.expect
new file mode 100644
index 0000000..1f84ecc
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_final_field_without_initializer.dart.type_promotion.expect
@@ -0,0 +1,3 @@
+pkg/front_end/testcases/late_lowering/late_final_field_without_initializer.dart:46:11: Context: Write to value@1348
+    value = f();
+          ^
diff --git a/pkg/front_end/testcases/late_lowering/late_final_local_with_initializer.dart b/pkg/front_end/testcases/late_lowering/late_final_local_with_initializer.dart
new file mode 100644
index 0000000..d2a2bd7
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_final_local_with_initializer.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2019, 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.
+
+main() {
+  int? lateLocalInit;
+  int initLateLocal(int value) {
+    return lateLocalInit = value;
+  }
+
+  late final int lateLocal = initLateLocal(123);
+
+  expect(null, lateLocalInit);
+  expect(123, lateLocal);
+  expect(123, lateLocalInit);
+}
+
+expect(expected, actual) {
+  if (expected != actual) throw 'Expected $expected, actual $actual';
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_final_local_with_initializer.dart.outline.expect b/pkg/front_end/testcases/late_lowering/late_final_local_with_initializer.dart.outline.expect
new file mode 100644
index 0000000..81d34cf
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_final_local_with_initializer.dart.outline.expect
@@ -0,0 +1,7 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
diff --git a/pkg/front_end/testcases/late_lowering/late_final_local_with_initializer.dart.strong.expect b/pkg/front_end/testcases/late_lowering/late_final_local_with_initializer.dart.strong.expect
new file mode 100644
index 0000000..3c9d2c6
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_final_local_with_initializer.dart.strong.expect
@@ -0,0 +1,20 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  core::int? lateLocalInit;
+  function initLateLocal(core::int value) → core::int {
+    return lateLocalInit = value;
+  }
+  final core::int? lateLocal;
+  function #lateLocal#get() → core::int
+    return let final core::int? #t1 = lateLocal in #t1.==(null) ?{core::int} lateLocal = initLateLocal.call(123) : #t1{core::int};
+  self::expect(null, lateLocalInit);
+  self::expect(123, #lateLocal#get.call());
+  self::expect(123, lateLocalInit);
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_final_local_with_initializer.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/late_final_local_with_initializer.dart.strong.transformed.expect
new file mode 100644
index 0000000..3c9d2c6
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_final_local_with_initializer.dart.strong.transformed.expect
@@ -0,0 +1,20 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  core::int? lateLocalInit;
+  function initLateLocal(core::int value) → core::int {
+    return lateLocalInit = value;
+  }
+  final core::int? lateLocal;
+  function #lateLocal#get() → core::int
+    return let final core::int? #t1 = lateLocal in #t1.==(null) ?{core::int} lateLocal = initLateLocal.call(123) : #t1{core::int};
+  self::expect(null, lateLocalInit);
+  self::expect(123, #lateLocal#get.call());
+  self::expect(123, lateLocalInit);
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_final_local_without_initializer.dart b/pkg/front_end/testcases/late_lowering/late_final_local_without_initializer.dart
new file mode 100644
index 0000000..33f43cb
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_final_local_without_initializer.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2019, 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.
+
+main() {
+  late final int lateLocal;
+
+  throws(() => lateLocal, 'Read value from uninitialized lateLocal');
+  expect(123, lateLocal = 123);
+  expect(123, lateLocal);
+  throws(() => lateLocal = 124, 'Write value to initialized lateLocal');
+}
+
+expect(expected, actual) {
+  if (expected != actual) throw 'Expected $expected, actual $actual';
+}
+
+throws(f(), String message) {
+  dynamic value;
+  try {
+    value = f();
+  } catch (e) {
+    print(e);
+    return;
+  }
+  throw '$message: $value';
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_final_local_without_initializer.dart.outline.expect b/pkg/front_end/testcases/late_lowering/late_final_local_without_initializer.dart.outline.expect
new file mode 100644
index 0000000..9cba406
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_final_local_without_initializer.dart.outline.expect
@@ -0,0 +1,10 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
+static method throws(() → dynamic f, core::String message) → dynamic
+  ;
diff --git a/pkg/front_end/testcases/late_lowering/late_final_local_without_initializer.dart.strong.expect b/pkg/front_end/testcases/late_lowering/late_final_local_without_initializer.dart.strong.expect
new file mode 100644
index 0000000..904b411
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_final_local_without_initializer.dart.strong.expect
@@ -0,0 +1,33 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  final core::int? lateLocal;
+  function #lateLocal#get() → core::int
+    return let final core::int? #t1 = lateLocal in #t1.==(null) ?{core::int} throw "Local 'lateLocal' has not been initialized." : #t1{core::int};
+  function #lateLocal#set(core::int #t2) → dynamic
+    if(lateLocal.==(null))
+      return lateLocal = #t2;
+    else
+      throw "Local 'lateLocal' has already been initialized.";
+  self::throws(() → core::int? => #lateLocal#get.call(), "Read value from uninitialized lateLocal");
+  self::expect(123, #lateLocal#set.call(123));
+  self::expect(123, #lateLocal#get.call());
+  self::throws(() → core::int => #lateLocal#set.call(124), "Write value to initialized lateLocal");
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, core::String message) → dynamic {
+  dynamic value;
+  try {
+    value = f.call();
+  }
+  on dynamic catch(final dynamic e) {
+    core::print(e);
+    return;
+  }
+  throw "${message}: ${value}";
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_final_local_without_initializer.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/late_final_local_without_initializer.dart.strong.transformed.expect
new file mode 100644
index 0000000..904b411
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_final_local_without_initializer.dart.strong.transformed.expect
@@ -0,0 +1,33 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  final core::int? lateLocal;
+  function #lateLocal#get() → core::int
+    return let final core::int? #t1 = lateLocal in #t1.==(null) ?{core::int} throw "Local 'lateLocal' has not been initialized." : #t1{core::int};
+  function #lateLocal#set(core::int #t2) → dynamic
+    if(lateLocal.==(null))
+      return lateLocal = #t2;
+    else
+      throw "Local 'lateLocal' has already been initialized.";
+  self::throws(() → core::int? => #lateLocal#get.call(), "Read value from uninitialized lateLocal");
+  self::expect(123, #lateLocal#set.call(123));
+  self::expect(123, #lateLocal#get.call());
+  self::throws(() → core::int => #lateLocal#set.call(124), "Write value to initialized lateLocal");
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, core::String message) → dynamic {
+  dynamic value;
+  try {
+    value = f.call();
+  }
+  on dynamic catch(final dynamic e) {
+    core::print(e);
+    return;
+  }
+  throw "${message}: ${value}";
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart
new file mode 100644
index 0000000..ff68189
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart
@@ -0,0 +1,62 @@
+// Copyright (c) 2019, 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.
+
+int? lateTopLevelField1Init;
+int? initLateTopLevelField1(int value) {
+  return lateTopLevelField1Init = value;
+}
+
+late final int? lateTopLevelField1 = initLateTopLevelField1(123);
+
+class Class {
+  static int? lateStaticField1Init;
+  static int? initLateStaticField1(int value) {
+    return lateStaticField1Init = value;
+  }
+
+  static late final int? lateStaticField1 = initLateStaticField1(87);
+
+  static int? lateStaticField2Init;
+  static int? initLateStaticField2(int value) {
+    return lateStaticField2Init = value;
+  }
+
+  static late final int? lateStaticField2 = initLateStaticField2(42);
+
+  static staticMethod() {
+    expect(null, lateStaticField2Init);
+    expect(42, lateStaticField2);
+    expect(42, lateStaticField2Init);
+  }
+
+  int? lateInstanceFieldInit;
+  int? initLateInstanceField(int value) {
+    return lateInstanceFieldInit = value;
+  }
+
+  late final int? lateInstanceField = initLateInstanceField(16);
+
+  instanceMethod() {
+    expect(null, lateInstanceFieldInit);
+    expect(16, lateInstanceField);
+    expect(16, lateInstanceFieldInit);
+  }
+}
+
+main() {
+  expect(null, lateTopLevelField1Init);
+  expect(123, lateTopLevelField1);
+  expect(123, lateTopLevelField1Init);
+
+  expect(null, Class.lateStaticField1Init);
+  expect(87, Class.lateStaticField1);
+  expect(87, Class.lateStaticField1Init);
+
+  Class.staticMethod();
+  new Class().instanceMethod();
+}
+
+expect(expected, actual) {
+  if (expected != actual) throw 'Expected $expected, actual $actual';
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.outline.expect b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.outline.expect
new file mode 100644
index 0000000..d9b8c23
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.outline.expect
@@ -0,0 +1,40 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  static field core::int? lateStaticField1Init;
+  static field core::int? _#lateStaticField1;
+  static field dynamic _#lateStaticField1#isSet;
+  static field core::int? lateStaticField2Init;
+  static field core::int? _#lateStaticField2;
+  static field dynamic _#lateStaticField2#isSet;
+  field core::int? lateInstanceFieldInit;
+  field core::int? _#lateInstanceField;
+  field dynamic _#lateInstanceField#isSet;
+  synthetic constructor •() → self::Class*
+    ;
+  static method initLateStaticField1(core::int value) → core::int?
+    ;
+  static get lateStaticField1() → core::int?;
+  static method initLateStaticField2(core::int value) → core::int?
+    ;
+  static get lateStaticField2() → core::int?;
+  static method staticMethod() → dynamic
+    ;
+  method initLateInstanceField(core::int value) → core::int?
+    ;
+  get lateInstanceField() → core::int?;
+  method instanceMethod() → dynamic
+    ;
+}
+static field core::int? lateTopLevelField1Init;
+static field core::int? _#lateTopLevelField1;
+static field dynamic _#lateTopLevelField1#isSet;
+static method initLateTopLevelField1(core::int value) → core::int?
+  ;
+static get lateTopLevelField1() → core::int?;
+static method main() → dynamic
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.strong.expect b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.strong.expect
new file mode 100644
index 0000000..d26702c
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.strong.expect
@@ -0,0 +1,85 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  static field core::int? lateStaticField1Init = null;
+  static field core::int? _#lateStaticField1 = null;
+  static field dynamic _#lateStaticField1#isSet = false;
+  static field core::int? lateStaticField2Init = null;
+  static field core::int? _#lateStaticField2 = null;
+  static field dynamic _#lateStaticField2#isSet = false;
+  field core::int? lateInstanceFieldInit = null;
+  field core::int? _#lateInstanceField = null;
+  field dynamic _#lateInstanceField#isSet = false;
+  synthetic constructor •() → self::Class*
+    : super core::Object::•()
+    ;
+  static method initLateStaticField1(core::int value) → core::int? {
+    return self::Class::lateStaticField1Init = value;
+  }
+  static get lateStaticField1() → core::int? {
+    if(!self::Class::_#lateStaticField1#isSet) {
+      self::Class::_#lateStaticField1#isSet = true;
+      self::Class::_#lateStaticField1 = self::Class::initLateStaticField1(87);
+    }
+    return self::Class::_#lateStaticField1;
+  }
+  static method initLateStaticField2(core::int value) → core::int? {
+    return self::Class::lateStaticField2Init = value;
+  }
+  static get lateStaticField2() → core::int? {
+    if(!self::Class::_#lateStaticField2#isSet) {
+      self::Class::_#lateStaticField2#isSet = true;
+      self::Class::_#lateStaticField2 = self::Class::initLateStaticField2(42);
+    }
+    return self::Class::_#lateStaticField2;
+  }
+  static method staticMethod() → dynamic {
+    self::expect(null, self::Class::lateStaticField2Init);
+    self::expect(42, self::Class::lateStaticField2);
+    self::expect(42, self::Class::lateStaticField2Init);
+  }
+  method initLateInstanceField(core::int value) → core::int? {
+    return this.{self::Class::lateInstanceFieldInit} = value;
+  }
+  get lateInstanceField() → core::int? {
+    if(!this.{self::Class::_#lateInstanceField#isSet}) {
+      this.{self::Class::_#lateInstanceField#isSet} = true;
+      this.{self::Class::_#lateInstanceField} = this.{self::Class::initLateInstanceField}(16);
+    }
+    return this.{self::Class::_#lateInstanceField};
+  }
+  method instanceMethod() → dynamic {
+    self::expect(null, this.{self::Class::lateInstanceFieldInit});
+    self::expect(16, this.{self::Class::lateInstanceField});
+    self::expect(16, this.{self::Class::lateInstanceFieldInit});
+  }
+}
+static field core::int? lateTopLevelField1Init;
+static field core::int? _#lateTopLevelField1 = null;
+static field dynamic _#lateTopLevelField1#isSet = false;
+static method initLateTopLevelField1(core::int value) → core::int? {
+  return self::lateTopLevelField1Init = value;
+}
+static get lateTopLevelField1() → core::int? {
+  if(!self::_#lateTopLevelField1#isSet) {
+    self::_#lateTopLevelField1#isSet = true;
+    self::_#lateTopLevelField1 = self::initLateTopLevelField1(123);
+  }
+  return self::_#lateTopLevelField1;
+}
+static method main() → dynamic {
+  self::expect(null, self::lateTopLevelField1Init);
+  self::expect(123, self::lateTopLevelField1);
+  self::expect(123, self::lateTopLevelField1Init);
+  self::expect(null, self::Class::lateStaticField1Init);
+  self::expect(87, self::Class::lateStaticField1);
+  self::expect(87, self::Class::lateStaticField1Init);
+  self::Class::staticMethod();
+  new self::Class::•().{self::Class::instanceMethod}();
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.strong.transformed.expect
new file mode 100644
index 0000000..d26702c
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_with_initializer.dart.strong.transformed.expect
@@ -0,0 +1,85 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  static field core::int? lateStaticField1Init = null;
+  static field core::int? _#lateStaticField1 = null;
+  static field dynamic _#lateStaticField1#isSet = false;
+  static field core::int? lateStaticField2Init = null;
+  static field core::int? _#lateStaticField2 = null;
+  static field dynamic _#lateStaticField2#isSet = false;
+  field core::int? lateInstanceFieldInit = null;
+  field core::int? _#lateInstanceField = null;
+  field dynamic _#lateInstanceField#isSet = false;
+  synthetic constructor •() → self::Class*
+    : super core::Object::•()
+    ;
+  static method initLateStaticField1(core::int value) → core::int? {
+    return self::Class::lateStaticField1Init = value;
+  }
+  static get lateStaticField1() → core::int? {
+    if(!self::Class::_#lateStaticField1#isSet) {
+      self::Class::_#lateStaticField1#isSet = true;
+      self::Class::_#lateStaticField1 = self::Class::initLateStaticField1(87);
+    }
+    return self::Class::_#lateStaticField1;
+  }
+  static method initLateStaticField2(core::int value) → core::int? {
+    return self::Class::lateStaticField2Init = value;
+  }
+  static get lateStaticField2() → core::int? {
+    if(!self::Class::_#lateStaticField2#isSet) {
+      self::Class::_#lateStaticField2#isSet = true;
+      self::Class::_#lateStaticField2 = self::Class::initLateStaticField2(42);
+    }
+    return self::Class::_#lateStaticField2;
+  }
+  static method staticMethod() → dynamic {
+    self::expect(null, self::Class::lateStaticField2Init);
+    self::expect(42, self::Class::lateStaticField2);
+    self::expect(42, self::Class::lateStaticField2Init);
+  }
+  method initLateInstanceField(core::int value) → core::int? {
+    return this.{self::Class::lateInstanceFieldInit} = value;
+  }
+  get lateInstanceField() → core::int? {
+    if(!this.{self::Class::_#lateInstanceField#isSet}) {
+      this.{self::Class::_#lateInstanceField#isSet} = true;
+      this.{self::Class::_#lateInstanceField} = this.{self::Class::initLateInstanceField}(16);
+    }
+    return this.{self::Class::_#lateInstanceField};
+  }
+  method instanceMethod() → dynamic {
+    self::expect(null, this.{self::Class::lateInstanceFieldInit});
+    self::expect(16, this.{self::Class::lateInstanceField});
+    self::expect(16, this.{self::Class::lateInstanceFieldInit});
+  }
+}
+static field core::int? lateTopLevelField1Init;
+static field core::int? _#lateTopLevelField1 = null;
+static field dynamic _#lateTopLevelField1#isSet = false;
+static method initLateTopLevelField1(core::int value) → core::int? {
+  return self::lateTopLevelField1Init = value;
+}
+static get lateTopLevelField1() → core::int? {
+  if(!self::_#lateTopLevelField1#isSet) {
+    self::_#lateTopLevelField1#isSet = true;
+    self::_#lateTopLevelField1 = self::initLateTopLevelField1(123);
+  }
+  return self::_#lateTopLevelField1;
+}
+static method main() → dynamic {
+  self::expect(null, self::lateTopLevelField1Init);
+  self::expect(123, self::lateTopLevelField1);
+  self::expect(123, self::lateTopLevelField1Init);
+  self::expect(null, self::Class::lateStaticField1Init);
+  self::expect(87, self::Class::lateStaticField1);
+  self::expect(87, self::Class::lateStaticField1Init);
+  self::Class::staticMethod();
+  new self::Class::•().{self::Class::instanceMethod}();
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_field_without_initializer.dart b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_without_initializer.dart
new file mode 100644
index 0000000..98dcf57
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_without_initializer.dart
@@ -0,0 +1,64 @@
+// Copyright (c) 2019, 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 final int? lateTopLevelField;
+
+class Class {
+  static late final int? lateStaticField1;
+  static late final int? lateStaticField2;
+
+  static staticMethod() {
+    throws(() => lateStaticField2,
+        'Read value from uninitialized Class.lateStaticField2');
+    lateStaticField2 = 42;
+    expect(42, lateStaticField2);
+    throws(() => lateStaticField2 = 43,
+        'Write value to initialized Class.lateStaticField2');
+  }
+
+  late final int? lateInstanceField;
+
+  instanceMethod() {
+    throws(() => lateInstanceField,
+        'Read value from uninitialized Class.lateInstanceField');
+    lateInstanceField = 16;
+    expect(16, lateInstanceField);
+    throws(() => lateInstanceField = 17,
+        'Write value to initialized Class.lateInstanceField');
+  }
+}
+
+main() {
+  throws(() => lateTopLevelField,
+      'Read value from uninitialized lateTopLevelField');
+  lateTopLevelField = 123;
+  expect(123, lateTopLevelField);
+  throws(() => lateTopLevelField = 124,
+      'Write value to initialized lateTopLevelField');
+
+  throws(() => Class.lateStaticField1,
+      'Read value from uninitialized Class.lateStaticField1');
+  Class.lateStaticField1 = 87;
+  expect(87, Class.lateStaticField1);
+  throws(() => Class.lateStaticField1 = 88,
+      'Write value to initialized Class.lateStaticField1');
+
+  Class.staticMethod();
+  new Class().instanceMethod();
+}
+
+expect(expected, actual) {
+  if (expected != actual) throw 'Expected $expected, actual $actual';
+}
+
+throws(f(), String message) {
+  dynamic value;
+  try {
+    value = f();
+  } catch (e) {
+    print(e);
+    return;
+  }
+  throw '$message: $value';
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_field_without_initializer.dart.outline.expect b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_without_initializer.dart.outline.expect
new file mode 100644
index 0000000..9dc7c80
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_without_initializer.dart.outline.expect
@@ -0,0 +1,34 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  static field core::int? _#lateStaticField1;
+  static field dynamic _#lateStaticField1#isSet;
+  static field core::int? _#lateStaticField2;
+  static field dynamic _#lateStaticField2#isSet;
+  field core::int? _#lateInstanceField;
+  field dynamic _#lateInstanceField#isSet;
+  synthetic constructor •() → self::Class*
+    ;
+  static get lateStaticField1() → core::int?;
+  static set lateStaticField1(core::int? #t1) → void;
+  static get lateStaticField2() → core::int?;
+  static set lateStaticField2(core::int? #t2) → void;
+  static method staticMethod() → dynamic
+    ;
+  get lateInstanceField() → core::int?;
+  set lateInstanceField(core::int? #t3) → void;
+  method instanceMethod() → dynamic
+    ;
+}
+static field core::int? _#lateTopLevelField;
+static field dynamic _#lateTopLevelField#isSet;
+static get lateTopLevelField() → core::int?;
+static set lateTopLevelField(core::int? #t4) → void;
+static method main() → dynamic
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
+static method throws(() → dynamic f, core::String message) → dynamic
+  ;
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_field_without_initializer.dart.strong.expect b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_without_initializer.dart.strong.expect
new file mode 100644
index 0000000..fff7e44
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_without_initializer.dart.strong.expect
@@ -0,0 +1,92 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  static field core::int? _#lateStaticField1 = null;
+  static field dynamic _#lateStaticField1#isSet = false;
+  static field core::int? _#lateStaticField2 = null;
+  static field dynamic _#lateStaticField2#isSet = false;
+  field core::int? _#lateInstanceField = null;
+  field dynamic _#lateInstanceField#isSet = false;
+  synthetic constructor •() → self::Class*
+    : super core::Object::•()
+    ;
+  static get lateStaticField1() → core::int?
+    return self::Class::_#lateStaticField1#isSet ?{core::int?} self::Class::_#lateStaticField1 : throw "Field 'lateStaticField1' has not been initialized.";
+  static set lateStaticField1(core::int? #t1) → void
+    if(self::Class::_#lateStaticField1#isSet)
+      throw "Field 'lateStaticField1' has already been initialized.";
+    else {
+      self::Class::_#lateStaticField1#isSet = true;
+      self::Class::_#lateStaticField1 = #t1;
+    }
+  static get lateStaticField2() → core::int?
+    return self::Class::_#lateStaticField2#isSet ?{core::int?} self::Class::_#lateStaticField2 : throw "Field 'lateStaticField2' has not been initialized.";
+  static set lateStaticField2(core::int? #t2) → void
+    if(self::Class::_#lateStaticField2#isSet)
+      throw "Field 'lateStaticField2' has already been initialized.";
+    else {
+      self::Class::_#lateStaticField2#isSet = true;
+      self::Class::_#lateStaticField2 = #t2;
+    }
+  static method staticMethod() → dynamic {
+    self::throws(() → core::int? => self::Class::lateStaticField2, "Read value from uninitialized Class.lateStaticField2");
+    self::Class::lateStaticField2 = 42;
+    self::expect(42, self::Class::lateStaticField2);
+    self::throws(() → core::int => self::Class::lateStaticField2 = 43, "Write value to initialized Class.lateStaticField2");
+  }
+  get lateInstanceField() → core::int?
+    return this.{self::Class::_#lateInstanceField#isSet} ?{core::int?} this.{self::Class::_#lateInstanceField} : throw "Field 'lateInstanceField' has not been initialized.";
+  set lateInstanceField(core::int? #t3) → void
+    if(this.{self::Class::_#lateInstanceField#isSet})
+      throw "Field 'lateInstanceField' has already been initialized.";
+    else {
+      this.{self::Class::_#lateInstanceField#isSet} = true;
+      this.{self::Class::_#lateInstanceField} = #t3;
+    }
+  method instanceMethod() → dynamic {
+    self::throws(() → core::int? => this.{self::Class::lateInstanceField}, "Read value from uninitialized Class.lateInstanceField");
+    this.{self::Class::lateInstanceField} = 16;
+    self::expect(16, this.{self::Class::lateInstanceField});
+    self::throws(() → core::int => this.{self::Class::lateInstanceField} = 17, "Write value to initialized Class.lateInstanceField");
+  }
+}
+static field core::int? _#lateTopLevelField = null;
+static field dynamic _#lateTopLevelField#isSet = false;
+static get lateTopLevelField() → core::int?
+  return self::_#lateTopLevelField#isSet ?{core::int?} self::_#lateTopLevelField : throw "Field 'lateTopLevelField' has not been initialized.";
+static set lateTopLevelField(core::int? #t4) → void
+  if(self::_#lateTopLevelField#isSet)
+    throw "Field 'lateTopLevelField' has already been initialized.";
+  else {
+    self::_#lateTopLevelField#isSet = true;
+    self::_#lateTopLevelField = #t4;
+  }
+static method main() → dynamic {
+  self::throws(() → core::int? => self::lateTopLevelField, "Read value from uninitialized lateTopLevelField");
+  self::lateTopLevelField = 123;
+  self::expect(123, self::lateTopLevelField);
+  self::throws(() → core::int => self::lateTopLevelField = 124, "Write value to initialized lateTopLevelField");
+  self::throws(() → core::int? => self::Class::lateStaticField1, "Read value from uninitialized Class.lateStaticField1");
+  self::Class::lateStaticField1 = 87;
+  self::expect(87, self::Class::lateStaticField1);
+  self::throws(() → core::int => self::Class::lateStaticField1 = 88, "Write value to initialized Class.lateStaticField1");
+  self::Class::staticMethod();
+  new self::Class::•().{self::Class::instanceMethod}();
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, core::String message) → dynamic {
+  dynamic value;
+  try {
+    value = f.call();
+  }
+  on dynamic catch(final dynamic e) {
+    core::print(e);
+    return;
+  }
+  throw "${message}: ${value}";
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_field_without_initializer.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_without_initializer.dart.strong.transformed.expect
new file mode 100644
index 0000000..fff7e44
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_without_initializer.dart.strong.transformed.expect
@@ -0,0 +1,92 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  static field core::int? _#lateStaticField1 = null;
+  static field dynamic _#lateStaticField1#isSet = false;
+  static field core::int? _#lateStaticField2 = null;
+  static field dynamic _#lateStaticField2#isSet = false;
+  field core::int? _#lateInstanceField = null;
+  field dynamic _#lateInstanceField#isSet = false;
+  synthetic constructor •() → self::Class*
+    : super core::Object::•()
+    ;
+  static get lateStaticField1() → core::int?
+    return self::Class::_#lateStaticField1#isSet ?{core::int?} self::Class::_#lateStaticField1 : throw "Field 'lateStaticField1' has not been initialized.";
+  static set lateStaticField1(core::int? #t1) → void
+    if(self::Class::_#lateStaticField1#isSet)
+      throw "Field 'lateStaticField1' has already been initialized.";
+    else {
+      self::Class::_#lateStaticField1#isSet = true;
+      self::Class::_#lateStaticField1 = #t1;
+    }
+  static get lateStaticField2() → core::int?
+    return self::Class::_#lateStaticField2#isSet ?{core::int?} self::Class::_#lateStaticField2 : throw "Field 'lateStaticField2' has not been initialized.";
+  static set lateStaticField2(core::int? #t2) → void
+    if(self::Class::_#lateStaticField2#isSet)
+      throw "Field 'lateStaticField2' has already been initialized.";
+    else {
+      self::Class::_#lateStaticField2#isSet = true;
+      self::Class::_#lateStaticField2 = #t2;
+    }
+  static method staticMethod() → dynamic {
+    self::throws(() → core::int? => self::Class::lateStaticField2, "Read value from uninitialized Class.lateStaticField2");
+    self::Class::lateStaticField2 = 42;
+    self::expect(42, self::Class::lateStaticField2);
+    self::throws(() → core::int => self::Class::lateStaticField2 = 43, "Write value to initialized Class.lateStaticField2");
+  }
+  get lateInstanceField() → core::int?
+    return this.{self::Class::_#lateInstanceField#isSet} ?{core::int?} this.{self::Class::_#lateInstanceField} : throw "Field 'lateInstanceField' has not been initialized.";
+  set lateInstanceField(core::int? #t3) → void
+    if(this.{self::Class::_#lateInstanceField#isSet})
+      throw "Field 'lateInstanceField' has already been initialized.";
+    else {
+      this.{self::Class::_#lateInstanceField#isSet} = true;
+      this.{self::Class::_#lateInstanceField} = #t3;
+    }
+  method instanceMethod() → dynamic {
+    self::throws(() → core::int? => this.{self::Class::lateInstanceField}, "Read value from uninitialized Class.lateInstanceField");
+    this.{self::Class::lateInstanceField} = 16;
+    self::expect(16, this.{self::Class::lateInstanceField});
+    self::throws(() → core::int => this.{self::Class::lateInstanceField} = 17, "Write value to initialized Class.lateInstanceField");
+  }
+}
+static field core::int? _#lateTopLevelField = null;
+static field dynamic _#lateTopLevelField#isSet = false;
+static get lateTopLevelField() → core::int?
+  return self::_#lateTopLevelField#isSet ?{core::int?} self::_#lateTopLevelField : throw "Field 'lateTopLevelField' has not been initialized.";
+static set lateTopLevelField(core::int? #t4) → void
+  if(self::_#lateTopLevelField#isSet)
+    throw "Field 'lateTopLevelField' has already been initialized.";
+  else {
+    self::_#lateTopLevelField#isSet = true;
+    self::_#lateTopLevelField = #t4;
+  }
+static method main() → dynamic {
+  self::throws(() → core::int? => self::lateTopLevelField, "Read value from uninitialized lateTopLevelField");
+  self::lateTopLevelField = 123;
+  self::expect(123, self::lateTopLevelField);
+  self::throws(() → core::int => self::lateTopLevelField = 124, "Write value to initialized lateTopLevelField");
+  self::throws(() → core::int? => self::Class::lateStaticField1, "Read value from uninitialized Class.lateStaticField1");
+  self::Class::lateStaticField1 = 87;
+  self::expect(87, self::Class::lateStaticField1);
+  self::throws(() → core::int => self::Class::lateStaticField1 = 88, "Write value to initialized Class.lateStaticField1");
+  self::Class::staticMethod();
+  new self::Class::•().{self::Class::instanceMethod}();
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, core::String message) → dynamic {
+  dynamic value;
+  try {
+    value = f.call();
+  }
+  on dynamic catch(final dynamic e) {
+    core::print(e);
+    return;
+  }
+  throw "${message}: ${value}";
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_field_without_initializer.dart.type_promotion.expect b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_without_initializer.dart.type_promotion.expect
new file mode 100644
index 0000000..96b2d9f
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_field_without_initializer.dart.type_promotion.expect
@@ -0,0 +1,3 @@
+pkg/front_end/testcases/late_lowering/late_final_nullable_field_without_initializer.dart:46:11: Context: Write to value@1351
+    value = f();
+          ^
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_local_with_initializer.dart b/pkg/front_end/testcases/late_lowering/late_final_nullable_local_with_initializer.dart
new file mode 100644
index 0000000..778e612
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_local_with_initializer.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2019, 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.
+
+main() {
+  int? lateLocalInit;
+  int? initLateLocal(int? value) {
+    return lateLocalInit = value;
+  }
+
+  late final int? lateLocal = initLateLocal(123);
+
+  expect(null, lateLocalInit);
+  expect(123, lateLocal);
+  expect(123, lateLocalInit);
+}
+
+expect(expected, actual) {
+  if (expected != actual) throw 'Expected $expected, actual $actual';
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_local_with_initializer.dart.outline.expect b/pkg/front_end/testcases/late_lowering/late_final_nullable_local_with_initializer.dart.outline.expect
new file mode 100644
index 0000000..81d34cf
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_local_with_initializer.dart.outline.expect
@@ -0,0 +1,7 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_local_with_initializer.dart.strong.expect b/pkg/front_end/testcases/late_lowering/late_final_nullable_local_with_initializer.dart.strong.expect
new file mode 100644
index 0000000..f019032
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_local_with_initializer.dart.strong.expect
@@ -0,0 +1,26 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  core::int? lateLocalInit;
+  function initLateLocal(core::int? value) → core::int? {
+    return lateLocalInit = value;
+  }
+  final core::int? lateLocal;
+  core::bool #lateLocal#isSet = false;
+  function #lateLocal#get() → core::int? {
+    if(!#lateLocal#isSet) {
+      #lateLocal#isSet = true;
+      lateLocal = initLateLocal.call(123);
+    }
+    return lateLocal;
+  }
+  self::expect(null, lateLocalInit);
+  self::expect(123, #lateLocal#get.call());
+  self::expect(123, lateLocalInit);
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_local_with_initializer.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/late_final_nullable_local_with_initializer.dart.strong.transformed.expect
new file mode 100644
index 0000000..f019032
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_local_with_initializer.dart.strong.transformed.expect
@@ -0,0 +1,26 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  core::int? lateLocalInit;
+  function initLateLocal(core::int? value) → core::int? {
+    return lateLocalInit = value;
+  }
+  final core::int? lateLocal;
+  core::bool #lateLocal#isSet = false;
+  function #lateLocal#get() → core::int? {
+    if(!#lateLocal#isSet) {
+      #lateLocal#isSet = true;
+      lateLocal = initLateLocal.call(123);
+    }
+    return lateLocal;
+  }
+  self::expect(null, lateLocalInit);
+  self::expect(123, #lateLocal#get.call());
+  self::expect(123, lateLocalInit);
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_local_without_initializer.dart b/pkg/front_end/testcases/late_lowering/late_final_nullable_local_without_initializer.dart
new file mode 100644
index 0000000..cfa53bc
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_local_without_initializer.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2019, 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.
+
+main() {
+  late final int? lateLocal;
+
+  throws(() => lateLocal, 'Read value from uninitialized lateLocal');
+  expect(123, lateLocal = 123);
+  expect(123, lateLocal);
+  throws(() => lateLocal = 124, 'Write value to initialized lateLocal');
+}
+
+expect(expected, actual) {
+  if (expected != actual) throw 'Expected $expected, actual $actual';
+}
+
+throws(f(), String message) {
+  dynamic value;
+  try {
+    value = f();
+  } catch (e) {
+    print(e);
+    return;
+  }
+  throw '$message: $value';
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_local_without_initializer.dart.outline.expect b/pkg/front_end/testcases/late_lowering/late_final_nullable_local_without_initializer.dart.outline.expect
new file mode 100644
index 0000000..9cba406
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_local_without_initializer.dart.outline.expect
@@ -0,0 +1,10 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
+static method throws(() → dynamic f, core::String message) → dynamic
+  ;
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_local_without_initializer.dart.strong.expect b/pkg/front_end/testcases/late_lowering/late_final_nullable_local_without_initializer.dart.strong.expect
new file mode 100644
index 0000000..97cbe14
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_local_without_initializer.dart.strong.expect
@@ -0,0 +1,36 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  final core::int? lateLocal;
+  core::bool #lateLocal#isSet = false;
+  function #lateLocal#get() → core::int?
+    return #lateLocal#isSet ?{core::int?} lateLocal : throw "Local 'lateLocal' has not been initialized.";
+  function #lateLocal#set(core::int? #t1) → dynamic
+    if(#lateLocal#isSet)
+      throw "Local 'lateLocal' has already been initialized.";
+    else {
+      #lateLocal#isSet = true;
+      return lateLocal = #t1;
+    }
+  self::throws(() → core::int? => #lateLocal#get.call(), "Read value from uninitialized lateLocal");
+  self::expect(123, #lateLocal#set.call(123));
+  self::expect(123, #lateLocal#get.call());
+  self::throws(() → core::int => #lateLocal#set.call(124), "Write value to initialized lateLocal");
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, core::String message) → dynamic {
+  dynamic value;
+  try {
+    value = f.call();
+  }
+  on dynamic catch(final dynamic e) {
+    core::print(e);
+    return;
+  }
+  throw "${message}: ${value}";
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_final_nullable_local_without_initializer.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/late_final_nullable_local_without_initializer.dart.strong.transformed.expect
new file mode 100644
index 0000000..97cbe14
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_final_nullable_local_without_initializer.dart.strong.transformed.expect
@@ -0,0 +1,36 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  final core::int? lateLocal;
+  core::bool #lateLocal#isSet = false;
+  function #lateLocal#get() → core::int?
+    return #lateLocal#isSet ?{core::int?} lateLocal : throw "Local 'lateLocal' has not been initialized.";
+  function #lateLocal#set(core::int? #t1) → dynamic
+    if(#lateLocal#isSet)
+      throw "Local 'lateLocal' has already been initialized.";
+    else {
+      #lateLocal#isSet = true;
+      return lateLocal = #t1;
+    }
+  self::throws(() → core::int? => #lateLocal#get.call(), "Read value from uninitialized lateLocal");
+  self::expect(123, #lateLocal#set.call(123));
+  self::expect(123, #lateLocal#get.call());
+  self::throws(() → core::int => #lateLocal#set.call(124), "Write value to initialized lateLocal");
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, core::String message) → dynamic {
+  dynamic value;
+  try {
+    value = f.call();
+  }
+  on dynamic catch(final dynamic e) {
+    core::print(e);
+    return;
+  }
+  throw "${message}: ${value}";
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_local_with_initializer.dart b/pkg/front_end/testcases/late_lowering/late_local_with_initializer.dart
new file mode 100644
index 0000000..6363618
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_local_with_initializer.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2019, 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.
+
+main() {
+  late int lateLocal = 123;
+
+  expect(123, lateLocal);
+  expect(124, lateLocal = 124);
+  expect(124, lateLocal);
+}
+
+expect(expected, actual) {
+  if (expected != actual) throw 'Expected $expected, actual $actual';
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_local_with_initializer.dart.outline.expect b/pkg/front_end/testcases/late_lowering/late_local_with_initializer.dart.outline.expect
new file mode 100644
index 0000000..81d34cf
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_local_with_initializer.dart.outline.expect
@@ -0,0 +1,7 @@
+library;
+import self as self;
+
+static method main() → dynamic
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
diff --git a/pkg/front_end/testcases/late_lowering/late_local_with_initializer.dart.strong.expect b/pkg/front_end/testcases/late_lowering/late_local_with_initializer.dart.strong.expect
new file mode 100644
index 0000000..5633dbf
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_local_with_initializer.dart.strong.expect
@@ -0,0 +1,18 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  core::int? lateLocal;
+  function #lateLocal#get() → core::int
+    return let final core::int? #t1 = lateLocal in #t1.==(null) ?{core::int} lateLocal = 123 : #t1{core::int};
+  function #lateLocal#set(core::int #t2) → dynamic
+    return lateLocal = #t2;
+  self::expect(123, #lateLocal#get.call());
+  self::expect(124, #lateLocal#set.call(124));
+  self::expect(124, #lateLocal#get.call());
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_local_with_initializer.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/late_local_with_initializer.dart.strong.transformed.expect
new file mode 100644
index 0000000..5633dbf
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_local_with_initializer.dart.strong.transformed.expect
@@ -0,0 +1,18 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  core::int? lateLocal;
+  function #lateLocal#get() → core::int
+    return let final core::int? #t1 = lateLocal in #t1.==(null) ?{core::int} lateLocal = 123 : #t1{core::int};
+  function #lateLocal#set(core::int #t2) → dynamic
+    return lateLocal = #t2;
+  self::expect(123, #lateLocal#get.call());
+  self::expect(124, #lateLocal#set.call(124));
+  self::expect(124, #lateLocal#get.call());
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_local_without_initializer.dart b/pkg/front_end/testcases/late_lowering/late_local_without_initializer.dart
new file mode 100644
index 0000000..0cb0e98
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_local_without_initializer.dart
@@ -0,0 +1,25 @@
+// Copyright (c) 2019, 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.
+
+main() {
+  late int lateLocal;
+  throws(() => lateLocal, 'Read value from uninitialized lateLocal');
+  expect(123, lateLocal = 123);
+  expect(123, lateLocal);
+}
+
+expect(expected, actual) {
+  if (expected != actual) throw 'Expected $expected, actual $actual';
+}
+
+throws(f(), String message) {
+  dynamic value;
+  try {
+    value = f();
+  } catch (e) {
+    print(e);
+    return;
+  }
+  throw '$message: $value';
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_local_without_initializer.dart.outline.expect b/pkg/front_end/testcases/late_lowering/late_local_without_initializer.dart.outline.expect
new file mode 100644
index 0000000..9cba406
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_local_without_initializer.dart.outline.expect
@@ -0,0 +1,10 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
+static method throws(() → dynamic f, core::String message) → dynamic
+  ;
diff --git a/pkg/front_end/testcases/late_lowering/late_local_without_initializer.dart.strong.expect b/pkg/front_end/testcases/late_lowering/late_local_without_initializer.dart.strong.expect
new file mode 100644
index 0000000..7f10865
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_local_without_initializer.dart.strong.expect
@@ -0,0 +1,29 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  core::int? lateLocal;
+  function #lateLocal#get() → core::int
+    return let final core::int? #t1 = lateLocal in #t1.==(null) ?{core::int} throw "Local 'lateLocal' has not been initialized." : #t1{core::int};
+  function #lateLocal#set(core::int #t2) → dynamic
+    return lateLocal = #t2;
+  self::throws(() → core::int? => #lateLocal#get.call(), "Read value from uninitialized lateLocal");
+  self::expect(123, #lateLocal#set.call(123));
+  self::expect(123, #lateLocal#get.call());
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, core::String message) → dynamic {
+  dynamic value;
+  try {
+    value = f.call();
+  }
+  on dynamic catch(final dynamic e) {
+    core::print(e);
+    return;
+  }
+  throw "${message}: ${value}";
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_local_without_initializer.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/late_local_without_initializer.dart.strong.transformed.expect
new file mode 100644
index 0000000..7f10865
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_local_without_initializer.dart.strong.transformed.expect
@@ -0,0 +1,29 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  core::int? lateLocal;
+  function #lateLocal#get() → core::int
+    return let final core::int? #t1 = lateLocal in #t1.==(null) ?{core::int} throw "Local 'lateLocal' has not been initialized." : #t1{core::int};
+  function #lateLocal#set(core::int #t2) → dynamic
+    return lateLocal = #t2;
+  self::throws(() → core::int? => #lateLocal#get.call(), "Read value from uninitialized lateLocal");
+  self::expect(123, #lateLocal#set.call(123));
+  self::expect(123, #lateLocal#get.call());
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, core::String message) → dynamic {
+  dynamic value;
+  try {
+    value = f.call();
+  }
+  on dynamic catch(final dynamic e) {
+    core::print(e);
+    return;
+  }
+  throw "${message}: ${value}";
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_nullable_field_with_initializer.dart b/pkg/front_end/testcases/late_lowering/late_nullable_field_with_initializer.dart
new file mode 100644
index 0000000..fcb7572
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_nullable_field_with_initializer.dart
@@ -0,0 +1,45 @@
+// Copyright (c) 2019, 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.
+
+int? lateTopLevelField1Init() => 123;
+late int? lateTopLevelField1 = lateTopLevelField1Init();
+
+class Class {
+  static int? lateStaticField1Init() => 87;
+  static late int? lateStaticField1 = lateStaticField1Init();
+  static int? lateStaticField2Init() => 42;
+  static late int? lateStaticField2 = lateStaticField2Init();
+
+  static staticMethod() {
+    expect(42, lateStaticField2);
+    lateStaticField2 = 43;
+    expect(43, lateStaticField2);
+  }
+
+  int? lateInstanceFieldInit() => 16;
+  late int? lateInstanceField = lateInstanceFieldInit();
+
+  instanceMethod() {
+    expect(16, lateInstanceField);
+    lateInstanceField = 17;
+    expect(17, lateInstanceField);
+  }
+}
+
+main() {
+  expect(123, lateTopLevelField1);
+  lateTopLevelField1 = 124;
+  expect(124, lateTopLevelField1);
+
+  expect(87, Class.lateStaticField1);
+  Class.lateStaticField1 = 88;
+  expect(88, Class.lateStaticField1);
+
+  Class.staticMethod();
+  new Class().instanceMethod();
+}
+
+expect(expected, actual) {
+  if (expected != actual) throw 'Expected $expected, actual $actual';
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_nullable_field_with_initializer.dart.outline.expect b/pkg/front_end/testcases/late_lowering/late_nullable_field_with_initializer.dart.outline.expect
new file mode 100644
index 0000000..bc10a9a
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_nullable_field_with_initializer.dart.outline.expect
@@ -0,0 +1,40 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  static field core::int? _#lateStaticField1;
+  static field dynamic _#lateStaticField1#isSet;
+  static field core::int? _#lateStaticField2;
+  static field dynamic _#lateStaticField2#isSet;
+  field core::int? _#lateInstanceField;
+  field dynamic _#lateInstanceField#isSet;
+  synthetic constructor •() → self::Class*
+    ;
+  static method lateStaticField1Init() → core::int?
+    ;
+  static get lateStaticField1() → core::int?;
+  static set lateStaticField1(core::int? #t1) → void;
+  static method lateStaticField2Init() → core::int?
+    ;
+  static get lateStaticField2() → core::int?;
+  static set lateStaticField2(core::int? #t2) → void;
+  static method staticMethod() → dynamic
+    ;
+  method lateInstanceFieldInit() → core::int?
+    ;
+  get lateInstanceField() → core::int?;
+  set lateInstanceField(core::int? #t3) → void;
+  method instanceMethod() → dynamic
+    ;
+}
+static field core::int? _#lateTopLevelField1;
+static field dynamic _#lateTopLevelField1#isSet;
+static method lateTopLevelField1Init() → core::int?
+  ;
+static get lateTopLevelField1() → core::int?;
+static set lateTopLevelField1(core::int? #t4) → void;
+static method main() → dynamic
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
diff --git a/pkg/front_end/testcases/late_lowering/late_nullable_field_with_initializer.dart.strong.expect b/pkg/front_end/testcases/late_lowering/late_nullable_field_with_initializer.dart.strong.expect
new file mode 100644
index 0000000..f0f3d5a
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_nullable_field_with_initializer.dart.strong.expect
@@ -0,0 +1,93 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  static field core::int? _#lateStaticField1 = null;
+  static field dynamic _#lateStaticField1#isSet = false;
+  static field core::int? _#lateStaticField2 = null;
+  static field dynamic _#lateStaticField2#isSet = false;
+  field core::int? _#lateInstanceField = null;
+  field dynamic _#lateInstanceField#isSet = false;
+  synthetic constructor •() → self::Class*
+    : super core::Object::•()
+    ;
+  static method lateStaticField1Init() → core::int?
+    return 87;
+  static get lateStaticField1() → core::int? {
+    if(!self::Class::_#lateStaticField1#isSet) {
+      self::Class::_#lateStaticField1#isSet = true;
+      self::Class::_#lateStaticField1 = self::Class::lateStaticField1Init();
+    }
+    return self::Class::_#lateStaticField1;
+  }
+  static set lateStaticField1(core::int? #t1) → void {
+    self::Class::_#lateStaticField1#isSet = true;
+    self::Class::_#lateStaticField1 = #t1;
+  }
+  static method lateStaticField2Init() → core::int?
+    return 42;
+  static get lateStaticField2() → core::int? {
+    if(!self::Class::_#lateStaticField2#isSet) {
+      self::Class::_#lateStaticField2#isSet = true;
+      self::Class::_#lateStaticField2 = self::Class::lateStaticField2Init();
+    }
+    return self::Class::_#lateStaticField2;
+  }
+  static set lateStaticField2(core::int? #t2) → void {
+    self::Class::_#lateStaticField2#isSet = true;
+    self::Class::_#lateStaticField2 = #t2;
+  }
+  static method staticMethod() → dynamic {
+    self::expect(42, self::Class::lateStaticField2);
+    self::Class::lateStaticField2 = 43;
+    self::expect(43, self::Class::lateStaticField2);
+  }
+  method lateInstanceFieldInit() → core::int?
+    return 16;
+  get lateInstanceField() → core::int? {
+    if(!this.{self::Class::_#lateInstanceField#isSet}) {
+      this.{self::Class::_#lateInstanceField#isSet} = true;
+      this.{self::Class::_#lateInstanceField} = this.{self::Class::lateInstanceFieldInit}();
+    }
+    return this.{self::Class::_#lateInstanceField};
+  }
+  set lateInstanceField(core::int? #t3) → void {
+    this.{self::Class::_#lateInstanceField#isSet} = true;
+    this.{self::Class::_#lateInstanceField} = #t3;
+  }
+  method instanceMethod() → dynamic {
+    self::expect(16, this.{self::Class::lateInstanceField});
+    this.{self::Class::lateInstanceField} = 17;
+    self::expect(17, this.{self::Class::lateInstanceField});
+  }
+}
+static field core::int? _#lateTopLevelField1 = null;
+static field dynamic _#lateTopLevelField1#isSet = false;
+static method lateTopLevelField1Init() → core::int?
+  return 123;
+static get lateTopLevelField1() → core::int? {
+  if(!self::_#lateTopLevelField1#isSet) {
+    self::_#lateTopLevelField1#isSet = true;
+    self::_#lateTopLevelField1 = self::lateTopLevelField1Init();
+  }
+  return self::_#lateTopLevelField1;
+}
+static set lateTopLevelField1(core::int? #t4) → void {
+  self::_#lateTopLevelField1#isSet = true;
+  self::_#lateTopLevelField1 = #t4;
+}
+static method main() → dynamic {
+  self::expect(123, self::lateTopLevelField1);
+  self::lateTopLevelField1 = 124;
+  self::expect(124, self::lateTopLevelField1);
+  self::expect(87, self::Class::lateStaticField1);
+  self::Class::lateStaticField1 = 88;
+  self::expect(88, self::Class::lateStaticField1);
+  self::Class::staticMethod();
+  new self::Class::•().{self::Class::instanceMethod}();
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_nullable_field_with_initializer.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/late_nullable_field_with_initializer.dart.strong.transformed.expect
new file mode 100644
index 0000000..f0f3d5a
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_nullable_field_with_initializer.dart.strong.transformed.expect
@@ -0,0 +1,93 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  static field core::int? _#lateStaticField1 = null;
+  static field dynamic _#lateStaticField1#isSet = false;
+  static field core::int? _#lateStaticField2 = null;
+  static field dynamic _#lateStaticField2#isSet = false;
+  field core::int? _#lateInstanceField = null;
+  field dynamic _#lateInstanceField#isSet = false;
+  synthetic constructor •() → self::Class*
+    : super core::Object::•()
+    ;
+  static method lateStaticField1Init() → core::int?
+    return 87;
+  static get lateStaticField1() → core::int? {
+    if(!self::Class::_#lateStaticField1#isSet) {
+      self::Class::_#lateStaticField1#isSet = true;
+      self::Class::_#lateStaticField1 = self::Class::lateStaticField1Init();
+    }
+    return self::Class::_#lateStaticField1;
+  }
+  static set lateStaticField1(core::int? #t1) → void {
+    self::Class::_#lateStaticField1#isSet = true;
+    self::Class::_#lateStaticField1 = #t1;
+  }
+  static method lateStaticField2Init() → core::int?
+    return 42;
+  static get lateStaticField2() → core::int? {
+    if(!self::Class::_#lateStaticField2#isSet) {
+      self::Class::_#lateStaticField2#isSet = true;
+      self::Class::_#lateStaticField2 = self::Class::lateStaticField2Init();
+    }
+    return self::Class::_#lateStaticField2;
+  }
+  static set lateStaticField2(core::int? #t2) → void {
+    self::Class::_#lateStaticField2#isSet = true;
+    self::Class::_#lateStaticField2 = #t2;
+  }
+  static method staticMethod() → dynamic {
+    self::expect(42, self::Class::lateStaticField2);
+    self::Class::lateStaticField2 = 43;
+    self::expect(43, self::Class::lateStaticField2);
+  }
+  method lateInstanceFieldInit() → core::int?
+    return 16;
+  get lateInstanceField() → core::int? {
+    if(!this.{self::Class::_#lateInstanceField#isSet}) {
+      this.{self::Class::_#lateInstanceField#isSet} = true;
+      this.{self::Class::_#lateInstanceField} = this.{self::Class::lateInstanceFieldInit}();
+    }
+    return this.{self::Class::_#lateInstanceField};
+  }
+  set lateInstanceField(core::int? #t3) → void {
+    this.{self::Class::_#lateInstanceField#isSet} = true;
+    this.{self::Class::_#lateInstanceField} = #t3;
+  }
+  method instanceMethod() → dynamic {
+    self::expect(16, this.{self::Class::lateInstanceField});
+    this.{self::Class::lateInstanceField} = 17;
+    self::expect(17, this.{self::Class::lateInstanceField});
+  }
+}
+static field core::int? _#lateTopLevelField1 = null;
+static field dynamic _#lateTopLevelField1#isSet = false;
+static method lateTopLevelField1Init() → core::int?
+  return 123;
+static get lateTopLevelField1() → core::int? {
+  if(!self::_#lateTopLevelField1#isSet) {
+    self::_#lateTopLevelField1#isSet = true;
+    self::_#lateTopLevelField1 = self::lateTopLevelField1Init();
+  }
+  return self::_#lateTopLevelField1;
+}
+static set lateTopLevelField1(core::int? #t4) → void {
+  self::_#lateTopLevelField1#isSet = true;
+  self::_#lateTopLevelField1 = #t4;
+}
+static method main() → dynamic {
+  self::expect(123, self::lateTopLevelField1);
+  self::lateTopLevelField1 = 124;
+  self::expect(124, self::lateTopLevelField1);
+  self::expect(87, self::Class::lateStaticField1);
+  self::Class::lateStaticField1 = 88;
+  self::expect(88, self::Class::lateStaticField1);
+  self::Class::staticMethod();
+  new self::Class::•().{self::Class::instanceMethod}();
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_nullable_field_without_initializer.dart b/pkg/front_end/testcases/late_lowering/late_nullable_field_without_initializer.dart
new file mode 100644
index 0000000..10543cc
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_nullable_field_without_initializer.dart
@@ -0,0 +1,55 @@
+// Copyright (c) 2019, 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? lateTopLevelField;
+
+class Class {
+  static late int? lateStaticField1;
+  static late int? lateStaticField2;
+
+  static staticMethod() {
+    throws(() => lateStaticField2,
+        'Read value from uninitialized Class.lateStaticField2');
+    lateStaticField2 = 42;
+    expect(42, lateStaticField2);
+  }
+
+  late int? lateInstanceField;
+
+  instanceMethod() {
+    throws(() => lateInstanceField,
+        'Read value from uninitialized Class.lateInstanceField');
+    lateInstanceField = 16;
+    expect(16, lateInstanceField);
+  }
+}
+
+main() {
+  throws(() => lateTopLevelField,
+      'Read value from uninitialized lateTopLevelField');
+  lateTopLevelField = 123;
+  expect(123, lateTopLevelField);
+
+  throws(() => Class.lateStaticField1,
+      'Read value from uninitialized Class.lateStaticField1');
+  Class.lateStaticField1 = 87;
+  expect(87, Class.lateStaticField1);
+
+  Class.staticMethod();
+}
+
+expect(expected, actual) {
+  if (expected != actual) throw 'Expected $expected, actual $actual';
+}
+
+throws(f(), String message) {
+  dynamic value;
+  try {
+    value = f();
+  } catch (e) {
+    print(e);
+    return;
+  }
+  throw '$message: $value';
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_nullable_field_without_initializer.dart.outline.expect b/pkg/front_end/testcases/late_lowering/late_nullable_field_without_initializer.dart.outline.expect
new file mode 100644
index 0000000..9dc7c80
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_nullable_field_without_initializer.dart.outline.expect
@@ -0,0 +1,34 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  static field core::int? _#lateStaticField1;
+  static field dynamic _#lateStaticField1#isSet;
+  static field core::int? _#lateStaticField2;
+  static field dynamic _#lateStaticField2#isSet;
+  field core::int? _#lateInstanceField;
+  field dynamic _#lateInstanceField#isSet;
+  synthetic constructor •() → self::Class*
+    ;
+  static get lateStaticField1() → core::int?;
+  static set lateStaticField1(core::int? #t1) → void;
+  static get lateStaticField2() → core::int?;
+  static set lateStaticField2(core::int? #t2) → void;
+  static method staticMethod() → dynamic
+    ;
+  get lateInstanceField() → core::int?;
+  set lateInstanceField(core::int? #t3) → void;
+  method instanceMethod() → dynamic
+    ;
+}
+static field core::int? _#lateTopLevelField;
+static field dynamic _#lateTopLevelField#isSet;
+static get lateTopLevelField() → core::int?;
+static set lateTopLevelField(core::int? #t4) → void;
+static method main() → dynamic
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
+static method throws(() → dynamic f, core::String message) → dynamic
+  ;
diff --git a/pkg/front_end/testcases/late_lowering/late_nullable_field_without_initializer.dart.strong.expect b/pkg/front_end/testcases/late_lowering/late_nullable_field_without_initializer.dart.strong.expect
new file mode 100644
index 0000000..68e4f55
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_nullable_field_without_initializer.dart.strong.expect
@@ -0,0 +1,75 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  static field core::int? _#lateStaticField1 = null;
+  static field dynamic _#lateStaticField1#isSet = false;
+  static field core::int? _#lateStaticField2 = null;
+  static field dynamic _#lateStaticField2#isSet = false;
+  field core::int? _#lateInstanceField = null;
+  field dynamic _#lateInstanceField#isSet = false;
+  synthetic constructor •() → self::Class*
+    : super core::Object::•()
+    ;
+  static get lateStaticField1() → core::int?
+    return self::Class::_#lateStaticField1#isSet ?{core::int?} self::Class::_#lateStaticField1 : throw "Field 'lateStaticField1' has not been initialized.";
+  static set lateStaticField1(core::int? #t1) → void {
+    self::Class::_#lateStaticField1#isSet = true;
+    self::Class::_#lateStaticField1 = #t1;
+  }
+  static get lateStaticField2() → core::int?
+    return self::Class::_#lateStaticField2#isSet ?{core::int?} self::Class::_#lateStaticField2 : throw "Field 'lateStaticField2' has not been initialized.";
+  static set lateStaticField2(core::int? #t2) → void {
+    self::Class::_#lateStaticField2#isSet = true;
+    self::Class::_#lateStaticField2 = #t2;
+  }
+  static method staticMethod() → dynamic {
+    self::throws(() → core::int? => self::Class::lateStaticField2, "Read value from uninitialized Class.lateStaticField2");
+    self::Class::lateStaticField2 = 42;
+    self::expect(42, self::Class::lateStaticField2);
+  }
+  get lateInstanceField() → core::int?
+    return this.{self::Class::_#lateInstanceField#isSet} ?{core::int?} this.{self::Class::_#lateInstanceField} : throw "Field 'lateInstanceField' has not been initialized.";
+  set lateInstanceField(core::int? #t3) → void {
+    this.{self::Class::_#lateInstanceField#isSet} = true;
+    this.{self::Class::_#lateInstanceField} = #t3;
+  }
+  method instanceMethod() → dynamic {
+    self::throws(() → core::int? => this.{self::Class::lateInstanceField}, "Read value from uninitialized Class.lateInstanceField");
+    this.{self::Class::lateInstanceField} = 16;
+    self::expect(16, this.{self::Class::lateInstanceField});
+  }
+}
+static field core::int? _#lateTopLevelField = null;
+static field dynamic _#lateTopLevelField#isSet = false;
+static get lateTopLevelField() → core::int?
+  return self::_#lateTopLevelField#isSet ?{core::int?} self::_#lateTopLevelField : throw "Field 'lateTopLevelField' has not been initialized.";
+static set lateTopLevelField(core::int? #t4) → void {
+  self::_#lateTopLevelField#isSet = true;
+  self::_#lateTopLevelField = #t4;
+}
+static method main() → dynamic {
+  self::throws(() → core::int? => self::lateTopLevelField, "Read value from uninitialized lateTopLevelField");
+  self::lateTopLevelField = 123;
+  self::expect(123, self::lateTopLevelField);
+  self::throws(() → core::int? => self::Class::lateStaticField1, "Read value from uninitialized Class.lateStaticField1");
+  self::Class::lateStaticField1 = 87;
+  self::expect(87, self::Class::lateStaticField1);
+  self::Class::staticMethod();
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, core::String message) → dynamic {
+  dynamic value;
+  try {
+    value = f.call();
+  }
+  on dynamic catch(final dynamic e) {
+    core::print(e);
+    return;
+  }
+  throw "${message}: ${value}";
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_nullable_field_without_initializer.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/late_nullable_field_without_initializer.dart.strong.transformed.expect
new file mode 100644
index 0000000..68e4f55
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_nullable_field_without_initializer.dart.strong.transformed.expect
@@ -0,0 +1,75 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  static field core::int? _#lateStaticField1 = null;
+  static field dynamic _#lateStaticField1#isSet = false;
+  static field core::int? _#lateStaticField2 = null;
+  static field dynamic _#lateStaticField2#isSet = false;
+  field core::int? _#lateInstanceField = null;
+  field dynamic _#lateInstanceField#isSet = false;
+  synthetic constructor •() → self::Class*
+    : super core::Object::•()
+    ;
+  static get lateStaticField1() → core::int?
+    return self::Class::_#lateStaticField1#isSet ?{core::int?} self::Class::_#lateStaticField1 : throw "Field 'lateStaticField1' has not been initialized.";
+  static set lateStaticField1(core::int? #t1) → void {
+    self::Class::_#lateStaticField1#isSet = true;
+    self::Class::_#lateStaticField1 = #t1;
+  }
+  static get lateStaticField2() → core::int?
+    return self::Class::_#lateStaticField2#isSet ?{core::int?} self::Class::_#lateStaticField2 : throw "Field 'lateStaticField2' has not been initialized.";
+  static set lateStaticField2(core::int? #t2) → void {
+    self::Class::_#lateStaticField2#isSet = true;
+    self::Class::_#lateStaticField2 = #t2;
+  }
+  static method staticMethod() → dynamic {
+    self::throws(() → core::int? => self::Class::lateStaticField2, "Read value from uninitialized Class.lateStaticField2");
+    self::Class::lateStaticField2 = 42;
+    self::expect(42, self::Class::lateStaticField2);
+  }
+  get lateInstanceField() → core::int?
+    return this.{self::Class::_#lateInstanceField#isSet} ?{core::int?} this.{self::Class::_#lateInstanceField} : throw "Field 'lateInstanceField' has not been initialized.";
+  set lateInstanceField(core::int? #t3) → void {
+    this.{self::Class::_#lateInstanceField#isSet} = true;
+    this.{self::Class::_#lateInstanceField} = #t3;
+  }
+  method instanceMethod() → dynamic {
+    self::throws(() → core::int? => this.{self::Class::lateInstanceField}, "Read value from uninitialized Class.lateInstanceField");
+    this.{self::Class::lateInstanceField} = 16;
+    self::expect(16, this.{self::Class::lateInstanceField});
+  }
+}
+static field core::int? _#lateTopLevelField = null;
+static field dynamic _#lateTopLevelField#isSet = false;
+static get lateTopLevelField() → core::int?
+  return self::_#lateTopLevelField#isSet ?{core::int?} self::_#lateTopLevelField : throw "Field 'lateTopLevelField' has not been initialized.";
+static set lateTopLevelField(core::int? #t4) → void {
+  self::_#lateTopLevelField#isSet = true;
+  self::_#lateTopLevelField = #t4;
+}
+static method main() → dynamic {
+  self::throws(() → core::int? => self::lateTopLevelField, "Read value from uninitialized lateTopLevelField");
+  self::lateTopLevelField = 123;
+  self::expect(123, self::lateTopLevelField);
+  self::throws(() → core::int? => self::Class::lateStaticField1, "Read value from uninitialized Class.lateStaticField1");
+  self::Class::lateStaticField1 = 87;
+  self::expect(87, self::Class::lateStaticField1);
+  self::Class::staticMethod();
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, core::String message) → dynamic {
+  dynamic value;
+  try {
+    value = f.call();
+  }
+  on dynamic catch(final dynamic e) {
+    core::print(e);
+    return;
+  }
+  throw "${message}: ${value}";
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_nullable_local_with_initializer.dart b/pkg/front_end/testcases/late_lowering/late_nullable_local_with_initializer.dart
new file mode 100644
index 0000000..a59e3f2
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_nullable_local_with_initializer.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2019, 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.
+
+int? lateLocalInit() => 123;
+
+main() {
+  late int? lateLocal = lateLocalInit();
+
+  expect(123, lateLocal);
+  expect(124, lateLocal = 124);
+  expect(124, lateLocal);
+}
+
+expect(expected, actual) {
+  if (expected != actual) throw 'Expected $expected, actual $actual';
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_nullable_local_with_initializer.dart.outline.expect b/pkg/front_end/testcases/late_lowering/late_nullable_local_with_initializer.dart.outline.expect
new file mode 100644
index 0000000..bccbe28
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_nullable_local_with_initializer.dart.outline.expect
@@ -0,0 +1,10 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method lateLocalInit() → core::int?
+  ;
+static method main() → dynamic
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
diff --git a/pkg/front_end/testcases/late_lowering/late_nullable_local_with_initializer.dart.strong.expect b/pkg/front_end/testcases/late_lowering/late_nullable_local_with_initializer.dart.strong.expect
new file mode 100644
index 0000000..850613c
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_nullable_local_with_initializer.dart.strong.expect
@@ -0,0 +1,28 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method lateLocalInit() → core::int?
+  return 123;
+static method main() → dynamic {
+  core::int? lateLocal;
+  core::bool #lateLocal#isSet = false;
+  function #lateLocal#get() → core::int? {
+    if(!#lateLocal#isSet) {
+      #lateLocal#isSet = true;
+      lateLocal = self::lateLocalInit();
+    }
+    return lateLocal;
+  }
+  function #lateLocal#set(core::int? #t1) → dynamic {
+    #lateLocal#isSet = true;
+    return lateLocal = #t1;
+  }
+  self::expect(123, #lateLocal#get.call());
+  self::expect(124, #lateLocal#set.call(124));
+  self::expect(124, #lateLocal#get.call());
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_nullable_local_with_initializer.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/late_nullable_local_with_initializer.dart.strong.transformed.expect
new file mode 100644
index 0000000..850613c
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_nullable_local_with_initializer.dart.strong.transformed.expect
@@ -0,0 +1,28 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method lateLocalInit() → core::int?
+  return 123;
+static method main() → dynamic {
+  core::int? lateLocal;
+  core::bool #lateLocal#isSet = false;
+  function #lateLocal#get() → core::int? {
+    if(!#lateLocal#isSet) {
+      #lateLocal#isSet = true;
+      lateLocal = self::lateLocalInit();
+    }
+    return lateLocal;
+  }
+  function #lateLocal#set(core::int? #t1) → dynamic {
+    #lateLocal#isSet = true;
+    return lateLocal = #t1;
+  }
+  self::expect(123, #lateLocal#get.call());
+  self::expect(124, #lateLocal#set.call(124));
+  self::expect(124, #lateLocal#get.call());
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_nullable_local_without_initializer.dart b/pkg/front_end/testcases/late_lowering/late_nullable_local_without_initializer.dart
new file mode 100644
index 0000000..d23214d
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_nullable_local_without_initializer.dart
@@ -0,0 +1,25 @@
+// Copyright (c) 2019, 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.
+
+main() {
+  late int? lateLocal;
+  throws(() => lateLocal, 'Read value from uninitialized lateLocal');
+  expect(123, lateLocal = 123);
+  expect(123, lateLocal);
+}
+
+expect(expected, actual) {
+  if (expected != actual) throw 'Expected $expected, actual $actual';
+}
+
+throws(f(), String message) {
+  dynamic value;
+  try {
+    value = f();
+  } catch (e) {
+    print(e);
+    return;
+  }
+  throw '$message: $value';
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_nullable_local_without_initializer.dart.outline.expect b/pkg/front_end/testcases/late_lowering/late_nullable_local_without_initializer.dart.outline.expect
new file mode 100644
index 0000000..9cba406
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_nullable_local_without_initializer.dart.outline.expect
@@ -0,0 +1,10 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
+static method throws(() → dynamic f, core::String message) → dynamic
+  ;
diff --git a/pkg/front_end/testcases/late_lowering/late_nullable_local_without_initializer.dart.strong.expect b/pkg/front_end/testcases/late_lowering/late_nullable_local_without_initializer.dart.strong.expect
new file mode 100644
index 0000000..7a9b940
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_nullable_local_without_initializer.dart.strong.expect
@@ -0,0 +1,32 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  core::int? lateLocal;
+  core::bool #lateLocal#isSet = false;
+  function #lateLocal#get() → core::int?
+    return #lateLocal#isSet ?{core::int?} lateLocal : throw "Local 'lateLocal' has not been initialized.";
+  function #lateLocal#set(core::int? #t1) → dynamic {
+    #lateLocal#isSet = true;
+    return lateLocal = #t1;
+  }
+  self::throws(() → core::int? => #lateLocal#get.call(), "Read value from uninitialized lateLocal");
+  self::expect(123, #lateLocal#set.call(123));
+  self::expect(123, #lateLocal#get.call());
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, core::String message) → dynamic {
+  dynamic value;
+  try {
+    value = f.call();
+  }
+  on dynamic catch(final dynamic e) {
+    core::print(e);
+    return;
+  }
+  throw "${message}: ${value}";
+}
diff --git a/pkg/front_end/testcases/late_lowering/late_nullable_local_without_initializer.dart.strong.transformed.expect b/pkg/front_end/testcases/late_lowering/late_nullable_local_without_initializer.dart.strong.transformed.expect
new file mode 100644
index 0000000..7a9b940
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/late_nullable_local_without_initializer.dart.strong.transformed.expect
@@ -0,0 +1,32 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method main() → dynamic {
+  core::int? lateLocal;
+  core::bool #lateLocal#isSet = false;
+  function #lateLocal#get() → core::int?
+    return #lateLocal#isSet ?{core::int?} lateLocal : throw "Local 'lateLocal' has not been initialized.";
+  function #lateLocal#set(core::int? #t1) → dynamic {
+    #lateLocal#isSet = true;
+    return lateLocal = #t1;
+  }
+  self::throws(() → core::int? => #lateLocal#get.call(), "Read value from uninitialized lateLocal");
+  self::expect(123, #lateLocal#set.call(123));
+  self::expect(123, #lateLocal#get.call());
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual))
+    throw "Expected ${expected}, actual ${actual}";
+}
+static method throws(() → dynamic f, core::String message) → dynamic {
+  dynamic value;
+  try {
+    value = f.call();
+  }
+  on dynamic catch(final dynamic e) {
+    core::print(e);
+    return;
+  }
+  throw "${message}: ${value}";
+}
diff --git a/pkg/front_end/testcases/late_lowering/test.options b/pkg/front_end/testcases/late_lowering/test.options
new file mode 100644
index 0000000..707afaf
--- /dev/null
+++ b/pkg/front_end/testcases/late_lowering/test.options
@@ -0,0 +1,2 @@
+--enable-experiment=non-nullable
+--force-late-lowering
\ No newline at end of file
diff --git a/pkg/front_end/testcases/nnbd/function_types.dart.outline.expect b/pkg/front_end/testcases/nnbd/function_types.dart.outline.expect
index 3579c0d..9ebda38 100644
--- a/pkg/front_end/testcases/nnbd/function_types.dart.outline.expect
+++ b/pkg/front_end/testcases/nnbd/function_types.dart.outline.expect
@@ -4,7 +4,7 @@
 
 typedef F = () → void;
 class A<T extends core::Object? = dynamic> extends core::Object {
-  synthetic constructor •() → self::A<self::A::T*>*
+  synthetic constructor •() → self::A<self::A::T%>*
     ;
 }
 class B extends self::A<() →? dynamic> {
diff --git a/pkg/front_end/testcases/nnbd/function_types.dart.strong.expect b/pkg/front_end/testcases/nnbd/function_types.dart.strong.expect
index 588caa0..8aab301 100644
--- a/pkg/front_end/testcases/nnbd/function_types.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/function_types.dart.strong.expect
@@ -4,7 +4,7 @@
 
 typedef F = () → void;
 class A<T extends core::Object? = dynamic> extends core::Object {
-  synthetic constructor •() → self::A<self::A::T*>*
+  synthetic constructor •() → self::A<self::A::T%>*
     : super core::Object::•()
     ;
 }
diff --git a/pkg/front_end/testcases/nnbd/function_types.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/function_types.dart.strong.transformed.expect
index 588caa0..8aab301 100644
--- a/pkg/front_end/testcases/nnbd/function_types.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/function_types.dart.strong.transformed.expect
@@ -4,7 +4,7 @@
 
 typedef F = () → void;
 class A<T extends core::Object? = dynamic> extends core::Object {
-  synthetic constructor •() → self::A<self::A::T*>*
+  synthetic constructor •() → self::A<self::A::T%>*
     : super core::Object::•()
     ;
 }
diff --git a/pkg/front_end/testcases/nnbd/inheritance_from_opt_out.dart.outline.expect b/pkg/front_end/testcases/nnbd/inheritance_from_opt_out.dart.outline.expect
index b279e44..8d72534 100644
--- a/pkg/front_end/testcases/nnbd/inheritance_from_opt_out.dart.outline.expect
+++ b/pkg/front_end/testcases/nnbd/inheritance_from_opt_out.dart.outline.expect
@@ -23,15 +23,15 @@
     ;
 }
 class Class2<T extends core::Object? = dynamic> extends inh::LegacyClass2<self::Class2::T%> {
-  synthetic constructor •() → self::Class2<self::Class2::T*>*
+  synthetic constructor •() → self::Class2<self::Class2::T%>*
     ;
 }
 class Class3a<T extends core::Object? = dynamic> extends inh::LegacyClass3<self::Class3a::T%> {
-  synthetic constructor •() → self::Class3a<self::Class3a::T*>*
+  synthetic constructor •() → self::Class3a<self::Class3a::T%>*
     ;
 }
 class Class3b<T extends core::Object? = dynamic> extends inh::LegacyClass3<self::Class3b::T%> implements inh::GenericInterface<self::Class3b::T%> {
-  synthetic constructor •() → self::Class3b<self::Class3b::T*>*
+  synthetic constructor •() → self::Class3b<self::Class3b::T%>*
     ;
 }
 class Class4a extends inh::LegacyClass4 {
diff --git a/pkg/front_end/testcases/nnbd/inheritance_from_opt_out.dart.strong.expect b/pkg/front_end/testcases/nnbd/inheritance_from_opt_out.dart.strong.expect
index c729feb..3b75a32 100644
--- a/pkg/front_end/testcases/nnbd/inheritance_from_opt_out.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/inheritance_from_opt_out.dart.strong.expect
@@ -24,17 +24,17 @@
     ;
 }
 class Class2<T extends core::Object? = dynamic> extends inh::LegacyClass2<self::Class2::T%> {
-  synthetic constructor •() → self::Class2<self::Class2::T*>*
+  synthetic constructor •() → self::Class2<self::Class2::T%>*
     : super inh::LegacyClass2::•()
     ;
 }
 class Class3a<T extends core::Object? = dynamic> extends inh::LegacyClass3<self::Class3a::T%> {
-  synthetic constructor •() → self::Class3a<self::Class3a::T*>*
+  synthetic constructor •() → self::Class3a<self::Class3a::T%>*
     : super inh::LegacyClass3::•()
     ;
 }
 class Class3b<T extends core::Object? = dynamic> extends inh::LegacyClass3<self::Class3b::T%> implements inh::GenericInterface<self::Class3b::T%> {
-  synthetic constructor •() → self::Class3b<self::Class3b::T*>*
+  synthetic constructor •() → self::Class3b<self::Class3b::T%>*
     : super inh::LegacyClass3::•()
     ;
 }
diff --git a/pkg/front_end/testcases/nnbd/intersection_types.dart.outline.expect b/pkg/front_end/testcases/nnbd/intersection_types.dart.outline.expect
index 26de83e..a1b7bfb 100644
--- a/pkg/front_end/testcases/nnbd/intersection_types.dart.outline.expect
+++ b/pkg/front_end/testcases/nnbd/intersection_types.dart.outline.expect
@@ -15,7 +15,7 @@
     ;
 }
 class Foo<T extends self::A? = self::A?> extends core::Object {
-  synthetic constructor •() → self::Foo<self::Foo::T*>*
+  synthetic constructor •() → self::Foo<self::Foo::T%>*
     ;
   method doPromotionsToNullable(generic-covariant-impl self::Foo::T% t) → dynamic
     ;
diff --git a/pkg/front_end/testcases/nnbd/intersection_types.dart.strong.expect b/pkg/front_end/testcases/nnbd/intersection_types.dart.strong.expect
index a65870d3..4f137d3 100644
--- a/pkg/front_end/testcases/nnbd/intersection_types.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/intersection_types.dart.strong.expect
@@ -18,7 +18,7 @@
     ;
 }
 class Foo<T extends self::A? = self::A?> extends core::Object {
-  synthetic constructor •() → self::Foo<self::Foo::T*>*
+  synthetic constructor •() → self::Foo<self::Foo::T%>*
     : super core::Object::•()
     ;
   method doPromotionsToNullable(generic-covariant-impl self::Foo::T% t) → dynamic {
diff --git a/pkg/front_end/testcases/nnbd/intersection_types.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/intersection_types.dart.strong.transformed.expect
index a65870d3..4f137d3 100644
--- a/pkg/front_end/testcases/nnbd/intersection_types.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/intersection_types.dart.strong.transformed.expect
@@ -18,7 +18,7 @@
     ;
 }
 class Foo<T extends self::A? = self::A?> extends core::Object {
-  synthetic constructor •() → self::Foo<self::Foo::T*>*
+  synthetic constructor •() → self::Foo<self::Foo::T%>*
     : super core::Object::•()
     ;
   method doPromotionsToNullable(generic-covariant-impl self::Foo::T% t) → dynamic {
diff --git a/pkg/front_end/testcases/nnbd/late.dart.strong.expect b/pkg/front_end/testcases/nnbd/late.dart.strong.expect
index 190ad8e..f22251a 100644
--- a/pkg/front_end/testcases/nnbd/late.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/late.dart.strong.expect
@@ -80,9 +80,9 @@
 static method noErrors() → dynamic {
   self::lateTopLevelField = 0;
   self::lateFinalTopLevelField = 0;
-  self::Class* c1 = new self::Class::•();
+  self::Class c1 = new self::Class::•();
   c1.{self::Class::method}();
-  self::Class* c2 = new self::Class::•();
+  self::Class c2 = new self::Class::•();
   c2.{self::Class::lateInstanceField} = 0;
   c2.{self::Class::lateFinalInstanceField2} = 0;
   self::Class::lateStaticField = 0;
@@ -92,7 +92,7 @@
   invalid-expression "pkg/front_end/testcases/nnbd/late.dart:63:3: Error: Setter not found: 'lateFinalTopLevelFieldWithInit'.
   lateFinalTopLevelFieldWithInit = 0;
   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^";
-  self::Class* c = new self::Class::•();
+  self::Class c = new self::Class::•();
   invalid-expression "pkg/front_end/testcases/nnbd/late.dart:65:5: Error: The setter 'lateFinalInstanceFieldWithInit' isn't defined for the class 'Class'.
  - 'Class' is from 'pkg/front_end/testcases/nnbd/late.dart'.
 Try correcting the name to the name of an existing setter, or defining a setter or field named 'lateFinalInstanceFieldWithInit'.
diff --git a/pkg/front_end/testcases/nnbd/late.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/late.dart.strong.transformed.expect
index 190ad8e..f22251a 100644
--- a/pkg/front_end/testcases/nnbd/late.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/late.dart.strong.transformed.expect
@@ -80,9 +80,9 @@
 static method noErrors() → dynamic {
   self::lateTopLevelField = 0;
   self::lateFinalTopLevelField = 0;
-  self::Class* c1 = new self::Class::•();
+  self::Class c1 = new self::Class::•();
   c1.{self::Class::method}();
-  self::Class* c2 = new self::Class::•();
+  self::Class c2 = new self::Class::•();
   c2.{self::Class::lateInstanceField} = 0;
   c2.{self::Class::lateFinalInstanceField2} = 0;
   self::Class::lateStaticField = 0;
@@ -92,7 +92,7 @@
   invalid-expression "pkg/front_end/testcases/nnbd/late.dart:63:3: Error: Setter not found: 'lateFinalTopLevelFieldWithInit'.
   lateFinalTopLevelFieldWithInit = 0;
   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^";
-  self::Class* c = new self::Class::•();
+  self::Class c = new self::Class::•();
   invalid-expression "pkg/front_end/testcases/nnbd/late.dart:65:5: Error: The setter 'lateFinalInstanceFieldWithInit' isn't defined for the class 'Class'.
  - 'Class' is from 'pkg/front_end/testcases/nnbd/late.dart'.
 Try correcting the name to the name of an existing setter, or defining a setter or field named 'lateFinalInstanceFieldWithInit'.
diff --git a/pkg/front_end/testcases/nnbd/null_shorting.dart b/pkg/front_end/testcases/nnbd/null_shorting.dart
index 681c577..edf2bda 100644
--- a/pkg/front_end/testcases/nnbd/null_shorting.dart
+++ b/pkg/front_end/testcases/nnbd/null_shorting.dart
@@ -95,10 +95,9 @@
 }
 
 void indexAccess(Class? c) {
-  // TODO(johnniwinther): Handle null aware index access.
-  //c?.[c];
-  //c?.[c] = new Class();
-  //c?.[c].method();
+  c?.[c];
+  c?.[c] = new Class();
+  c?.[c].method();
   c?.field[c];
   c?.field[c] = new Class();
   c = c?.field[c] = new Class();
diff --git a/pkg/front_end/testcases/nnbd/null_shorting.dart.strong.expect b/pkg/front_end/testcases/nnbd/null_shorting.dart.strong.expect
index e1af1bb..d50fc22 100644
--- a/pkg/front_end/testcases/nnbd/null_shorting.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/null_shorting.dart.strong.expect
@@ -27,98 +27,101 @@
 }
 static method propertyAccess(self::Class? c) → void {
   let final self::Class? #t1 = c in #t1.{core::Object::==}(null) ?{self::Class?} null : #t1.{self::Class::field};
-  let final self::Class? #t2 = c in #t2.{core::Object::==}(null) ?{self::Class*} null : #t2.{self::Class::field} = new self::Class::•();
-  c = let final self::Class? #t3 = c in #t3.{core::Object::==}(null) ?{self::Class*} null : #t3.{self::Class::field} = new self::Class::•();
+  let final self::Class? #t2 = c in #t2.{core::Object::==}(null) ?{self::Class} null : #t2.{self::Class::field} = new self::Class::•();
+  c = let final self::Class? #t3 = c in #t3.{core::Object::==}(null) ?{self::Class} null : #t3.{self::Class::field} = new self::Class::•();
   let final self::Class? #t4 = c in #t4.{core::Object::==}(null) ?{self::Class?} null : #t4.{self::Class::method}();
   let final self::Class? #t5 = c in #t5.{core::Object::==}(null) ?{self::Class?} null : #t5.{self::Class::field}.{self::Class::field};
-  let final self::Class? #t6 = c in #t6.{core::Object::==}(null) ?{self::Class*} null : #t6.{self::Class::field}.{self::Class::field} = new self::Class::•();
+  let final self::Class? #t6 = c in #t6.{core::Object::==}(null) ?{self::Class} null : #t6.{self::Class::field}.{self::Class::field} = new self::Class::•();
   self::throws(() → self::Class? => (let final self::Class? #t7 = c in #t7.{core::Object::==}(null) ?{self::Class?} null : #t7.{self::Class::field}).{self::Class::field});
-  self::throws(() → self::Class? => (let final self::Class? #t8 = c in #t8.{core::Object::==}(null) ?{self::Class*} null : #t8.{self::Class::field} = new self::Class::•()).{self::Class::field});
+  self::throws(() → self::Class? => (let final self::Class? #t8 = c in #t8.{core::Object::==}(null) ?{self::Class} null : #t8.{self::Class::field} = new self::Class::•()).{self::Class::field});
   self::throws(() → self::Class? => (let final self::Class? #t9 = c in #t9.{core::Object::==}(null) ?{self::Class?} null : #t9.{self::Class::method}()).{self::Class::field});
-  c = let final self::Class? #t10 = c in #t10.{core::Object::==}(null) ?{self::Class*} null : #t10.{self::Class::field}.{self::Class::field} = new self::Class::•();
+  c = let final self::Class? #t10 = c in #t10.{core::Object::==}(null) ?{self::Class} null : #t10.{self::Class::field}.{self::Class::field} = new self::Class::•();
   let final self::Class? #t11 = c in #t11.{core::Object::==}(null) ?{self::Class?} null : #t11.{self::Class::field}.{self::Class::method}();
   let final self::Class? #t12 = c in #t12.{core::Object::==}(null) ?{self::Class?} null : #t12.{self::Class::field} = new self::Class::•().{self::Class::field};
   c = let final self::Class? #t13 = c in #t13.{core::Object::==}(null) ?{self::Class?} null : #t13.{self::Class::field} = new self::Class::•().{self::Class::field};
-  let final self::Class? #t14 = c in #t14.{core::Object::==}(null) ?{self::Class*} null : #t14.{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•();
-  c = let final self::Class? #t15 = c in #t15.{core::Object::==}(null) ?{self::Class*} null : #t15.{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•();
+  let final self::Class? #t14 = c in #t14.{core::Object::==}(null) ?{self::Class} null : #t14.{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•();
+  c = let final self::Class? #t15 = c in #t15.{core::Object::==}(null) ?{self::Class} null : #t15.{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•();
   let final self::Class? #t16 = c in #t16.{core::Object::==}(null) ?{self::Class?} null : #t16.{self::Class::field} = new self::Class::•().{self::Class::method}();
   c = let final self::Class? #t17 = c in #t17.{core::Object::==}(null) ?{self::Class?} null : #t17.{self::Class::field} = new self::Class::•().{self::Class::method}();
   let final self::Class? #t18 = c in #t18.{core::Object::==}(null) ?{self::Class?} null : #t18.{self::Class::method}().{self::Class::field};
-  let final self::Class? #t19 = c in #t19.{core::Object::==}(null) ?{self::Class*} null : #t19.{self::Class::method}().{self::Class::field} = new self::Class::•();
+  let final self::Class? #t19 = c in #t19.{core::Object::==}(null) ?{self::Class} null : #t19.{self::Class::method}().{self::Class::field} = new self::Class::•();
   let final self::Class? #t20 = c in #t20.{core::Object::==}(null) ?{self::Class?} null : #t20.{self::Class::method}().{self::Class::method}();
   let final self::Class? #t21 = c in #t21.{core::Object::==}(null) ?{self::Class?} null : #t21.{self::Class::field}.{self::Class::field}.{self::Class::field};
-  let final self::Class? #t22 = c in #t22.{core::Object::==}(null) ?{self::Class*} null : #t22.{self::Class::field}.{self::Class::field}.{self::Class::field} = new self::Class::•();
-  c = let final self::Class? #t23 = c in #t23.{core::Object::==}(null) ?{self::Class*} null : #t23.{self::Class::field}.{self::Class::field}.{self::Class::field} = new self::Class::•();
+  let final self::Class? #t22 = c in #t22.{core::Object::==}(null) ?{self::Class} null : #t22.{self::Class::field}.{self::Class::field}.{self::Class::field} = new self::Class::•();
+  c = let final self::Class? #t23 = c in #t23.{core::Object::==}(null) ?{self::Class} null : #t23.{self::Class::field}.{self::Class::field}.{self::Class::field} = new self::Class::•();
   let final self::Class? #t24 = c in #t24.{core::Object::==}(null) ?{self::Class?} null : #t24.{self::Class::field}.{self::Class::field}.{self::Class::method}();
   let final self::Class? #t25 = c in #t25.{core::Object::==}(null) ?{self::Class?} null : #t25.{self::Class::field} = new self::Class::•().{self::Class::field}.{self::Class::field};
   c = let final self::Class? #t26 = c in #t26.{core::Object::==}(null) ?{self::Class?} null : #t26.{self::Class::field} = new self::Class::•().{self::Class::field}.{self::Class::field};
-  let final self::Class? #t27 = c in #t27.{core::Object::==}(null) ?{self::Class*} null : #t27.{self::Class::field} = new self::Class::•().{self::Class::field}.{self::Class::field} = new self::Class::•();
-  c = let final self::Class? #t28 = c in #t28.{core::Object::==}(null) ?{self::Class*} null : #t28.{self::Class::field} = new self::Class::•().{self::Class::field}.{self::Class::field} = new self::Class::•();
+  let final self::Class? #t27 = c in #t27.{core::Object::==}(null) ?{self::Class} null : #t27.{self::Class::field} = new self::Class::•().{self::Class::field}.{self::Class::field} = new self::Class::•();
+  c = let final self::Class? #t28 = c in #t28.{core::Object::==}(null) ?{self::Class} null : #t28.{self::Class::field} = new self::Class::•().{self::Class::field}.{self::Class::field} = new self::Class::•();
   let final self::Class? #t29 = c in #t29.{core::Object::==}(null) ?{self::Class?} null : #t29.{self::Class::field} = new self::Class::•().{self::Class::field}.{self::Class::method}();
   c = let final self::Class? #t30 = c in #t30.{core::Object::==}(null) ?{self::Class?} null : #t30.{self::Class::field} = new self::Class::•().{self::Class::field}.{self::Class::method}();
   let final self::Class? #t31 = c in #t31.{core::Object::==}(null) ?{self::Class?} null : #t31.{self::Class::method}().{self::Class::field}.{self::Class::field};
-  let final self::Class? #t32 = c in #t32.{core::Object::==}(null) ?{self::Class*} null : #t32.{self::Class::method}().{self::Class::field}.{self::Class::field} = new self::Class::•();
+  let final self::Class? #t32 = c in #t32.{core::Object::==}(null) ?{self::Class} null : #t32.{self::Class::method}().{self::Class::field}.{self::Class::field} = new self::Class::•();
   let final self::Class? #t33 = c in #t33.{core::Object::==}(null) ?{self::Class?} null : #t33.{self::Class::method}().{self::Class::field}.{self::Class::method}();
   let final self::Class? #t34 = c in #t34.{core::Object::==}(null) ?{self::Class?} null : #t34.{self::Class::field}.{self::Class::field} = new self::Class::•().{self::Class::field};
   c = let final self::Class? #t35 = c in #t35.{core::Object::==}(null) ?{self::Class?} null : #t35.{self::Class::field}.{self::Class::field} = new self::Class::•().{self::Class::field};
-  let final self::Class? #t36 = c in #t36.{core::Object::==}(null) ?{self::Class*} null : #t36.{self::Class::field}.{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•();
-  c = let final self::Class? #t37 = c in #t37.{core::Object::==}(null) ?{self::Class*} null : #t37.{self::Class::field}.{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•();
+  let final self::Class? #t36 = c in #t36.{core::Object::==}(null) ?{self::Class} null : #t36.{self::Class::field}.{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•();
+  c = let final self::Class? #t37 = c in #t37.{core::Object::==}(null) ?{self::Class} null : #t37.{self::Class::field}.{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•();
   let final self::Class? #t38 = c in #t38.{core::Object::==}(null) ?{self::Class?} null : #t38.{self::Class::field}.{self::Class::field} = new self::Class::•().{self::Class::method}();
   c = let final self::Class? #t39 = c in #t39.{core::Object::==}(null) ?{self::Class?} null : #t39.{self::Class::field}.{self::Class::field} = new self::Class::•().{self::Class::method}();
   let final self::Class? #t40 = c in #t40.{core::Object::==}(null) ?{self::Class?} null : #t40.{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•().{self::Class::field};
   c = let final self::Class? #t41 = c in #t41.{core::Object::==}(null) ?{self::Class?} null : #t41.{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•().{self::Class::field};
-  let final self::Class? #t42 = c in #t42.{core::Object::==}(null) ?{self::Class*} null : #t42.{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•();
-  c = let final self::Class? #t43 = c in #t43.{core::Object::==}(null) ?{self::Class*} null : #t43.{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•();
+  let final self::Class? #t42 = c in #t42.{core::Object::==}(null) ?{self::Class} null : #t42.{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•();
+  c = let final self::Class? #t43 = c in #t43.{core::Object::==}(null) ?{self::Class} null : #t43.{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•();
   let final self::Class? #t44 = c in #t44.{core::Object::==}(null) ?{self::Class?} null : #t44.{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•().{self::Class::method}();
   c = let final self::Class? #t45 = c in #t45.{core::Object::==}(null) ?{self::Class?} null : #t45.{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•().{self::Class::method}();
   let final self::Class? #t46 = c in #t46.{core::Object::==}(null) ?{self::Class?} null : #t46.{self::Class::method}().{self::Class::field} = new self::Class::•().{self::Class::field};
   c = let final self::Class? #t47 = c in #t47.{core::Object::==}(null) ?{self::Class?} null : #t47.{self::Class::method}().{self::Class::field} = new self::Class::•().{self::Class::field};
-  let final self::Class? #t48 = c in #t48.{core::Object::==}(null) ?{self::Class*} null : #t48.{self::Class::method}().{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•();
-  c = let final self::Class? #t49 = c in #t49.{core::Object::==}(null) ?{self::Class*} null : #t49.{self::Class::method}().{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•();
+  let final self::Class? #t48 = c in #t48.{core::Object::==}(null) ?{self::Class} null : #t48.{self::Class::method}().{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•();
+  c = let final self::Class? #t49 = c in #t49.{core::Object::==}(null) ?{self::Class} null : #t49.{self::Class::method}().{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•();
   let final self::Class? #t50 = c in #t50.{core::Object::==}(null) ?{self::Class?} null : #t50.{self::Class::method}().{self::Class::field} = new self::Class::•().{self::Class::method}();
   c = let final self::Class? #t51 = c in #t51.{core::Object::==}(null) ?{self::Class?} null : #t51.{self::Class::method}().{self::Class::field} = new self::Class::•().{self::Class::method}();
   let final self::Class? #t52 = c in #t52.{core::Object::==}(null) ?{self::Class?} null : #t52.{self::Class::field}.{self::Class::method}().{self::Class::field};
-  let final self::Class? #t53 = c in #t53.{core::Object::==}(null) ?{self::Class*} null : #t53.{self::Class::field}.{self::Class::method}().{self::Class::field} = new self::Class::•();
-  c = let final self::Class? #t54 = c in #t54.{core::Object::==}(null) ?{self::Class*} null : #t54.{self::Class::field}.{self::Class::method}().{self::Class::field} = new self::Class::•();
+  let final self::Class? #t53 = c in #t53.{core::Object::==}(null) ?{self::Class} null : #t53.{self::Class::field}.{self::Class::method}().{self::Class::field} = new self::Class::•();
+  c = let final self::Class? #t54 = c in #t54.{core::Object::==}(null) ?{self::Class} null : #t54.{self::Class::field}.{self::Class::method}().{self::Class::field} = new self::Class::•();
   let final self::Class? #t55 = c in #t55.{core::Object::==}(null) ?{self::Class?} null : #t55.{self::Class::field}.{self::Class::method}().{self::Class::method}();
   let final self::Class? #t56 = c in #t56.{core::Object::==}(null) ?{self::Class?} null : #t56.{self::Class::field} = new self::Class::•().{self::Class::method}().{self::Class::field};
   c = let final self::Class? #t57 = c in #t57.{core::Object::==}(null) ?{self::Class?} null : #t57.{self::Class::field} = new self::Class::•().{self::Class::method}().{self::Class::field};
-  let final self::Class? #t58 = c in #t58.{core::Object::==}(null) ?{self::Class*} null : #t58.{self::Class::field} = new self::Class::•().{self::Class::method}().{self::Class::field} = new self::Class::•();
-  c = let final self::Class? #t59 = c in #t59.{core::Object::==}(null) ?{self::Class*} null : #t59.{self::Class::field} = new self::Class::•().{self::Class::method}().{self::Class::field} = new self::Class::•();
+  let final self::Class? #t58 = c in #t58.{core::Object::==}(null) ?{self::Class} null : #t58.{self::Class::field} = new self::Class::•().{self::Class::method}().{self::Class::field} = new self::Class::•();
+  c = let final self::Class? #t59 = c in #t59.{core::Object::==}(null) ?{self::Class} null : #t59.{self::Class::field} = new self::Class::•().{self::Class::method}().{self::Class::field} = new self::Class::•();
   let final self::Class? #t60 = c in #t60.{core::Object::==}(null) ?{self::Class?} null : #t60.{self::Class::field} = new self::Class::•().{self::Class::method}().{self::Class::method}();
   c = let final self::Class? #t61 = c in #t61.{core::Object::==}(null) ?{self::Class?} null : #t61.{self::Class::field} = new self::Class::•().{self::Class::method}().{self::Class::method}();
   let final self::Class? #t62 = c in #t62.{core::Object::==}(null) ?{self::Class?} null : #t62.{self::Class::method}().{self::Class::method}().{self::Class::field};
-  let final self::Class? #t63 = c in #t63.{core::Object::==}(null) ?{self::Class*} null : #t63.{self::Class::method}().{self::Class::method}().{self::Class::field} = new self::Class::•();
+  let final self::Class? #t63 = c in #t63.{core::Object::==}(null) ?{self::Class} null : #t63.{self::Class::method}().{self::Class::method}().{self::Class::field} = new self::Class::•();
   let final self::Class? #t64 = c in #t64.{core::Object::==}(null) ?{self::Class?} null : #t64.{self::Class::method}().{self::Class::method}().{self::Class::method}();
 }
 static method indexAccess(self::Class? c) → void {
-  let final self::Class? #t65 = c in #t65.{core::Object::==}(null) ?{self::Class?} null : #t65.{self::Class::field}.{self::Class::[]}(c);
-  let final self::Class? #t66 = c in #t66.{core::Object::==}(null) ?{self::Class*} null : #t66.{self::Class::field}.{self::Class::[]=}(c, new self::Class::•());
-  c = let final self::Class? #t67 = c in #t67.{core::Object::==}(null) ?{self::Class*} null : let final self::Class? #t68 = #t67.{self::Class::field} in let final self::Class? #t69 = c in let final self::Class* #t70 = new self::Class::•() in let final void #t71 = #t68.{self::Class::[]=}(#t69, #t70) in #t70;
-  let final self::Class? #t72 = c in #t72.{core::Object::==}(null) ?{self::Class?} null : #t72.{self::Class::field}.{self::Class::[]}(c).{self::Class::method}();
-  let final self::Class? #t73 = c in #t73.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t74 = #t73.{self::Class::field} in let final self::Class? #t75 = c in #t74.{self::Class::[]=}(#t75, #t74.{self::Class::[]}(#t75).{self::Class::+}(0));
-  c = let final self::Class? #t76 = c in #t76.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t77 = #t76.{self::Class::field} in let final self::Class? #t78 = c in let final self::Class? #t79 = #t77.{self::Class::[]}(#t78).{self::Class::+}(0) in let final void #t80 = #t77.{self::Class::[]=}(#t78, #t79) in #t79;
-  let final self::Class? #t81 = c in #t81.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t82 = #t81.{self::Class::field} in let final self::Class? #t83 = c in #t82.{self::Class::[]=}(#t83, #t82.{self::Class::[]}(#t83).{self::Class::+}(1));
-  c = let final self::Class? #t84 = c in #t84.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t85 = #t84.{self::Class::field} in let final self::Class? #t86 = c in let final self::Class? #t87 = #t85.{self::Class::[]}(#t86) in let final void #t88 = #t85.{self::Class::[]=}(#t86, #t87.{self::Class::+}(1)) in #t87;
-  let final self::Class? #t89 = c in #t89.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t90 = #t89.{self::Class::field} in let final self::Class? #t91 = c in let final self::Class? #t92 = #t90.{self::Class::[]}(#t91).{self::Class::+}(1) in let final void #t93 = #t90.{self::Class::[]=}(#t91, #t92) in #t92;
-  c = let final self::Class? #t94 = c in #t94.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t95 = #t94.{self::Class::field} in let final self::Class? #t96 = c in let final self::Class? #t97 = #t95.{self::Class::[]}(#t96).{self::Class::+}(1) in let final void #t98 = #t95.{self::Class::[]=}(#t96, #t97) in #t97;
+  let final self::Class? #t65 = c in #t65.{core::Object::==}(null) ?{self::Class?} null : #t65.{self::Class::[]}(c);
+  let final self::Class? #t66 = c in #t66.{core::Object::==}(null) ?{self::Class} null : #t66.{self::Class::[]=}(c, new self::Class::•());
+  let final self::Class? #t67 = c in #t67.{core::Object::==}(null) ?{self::Class?} null : #t67.{self::Class::[]}(c).{self::Class::method}();
+  let final self::Class? #t68 = c in #t68.{core::Object::==}(null) ?{self::Class?} null : #t68.{self::Class::field}.{self::Class::[]}(c);
+  let final self::Class? #t69 = c in #t69.{core::Object::==}(null) ?{self::Class} null : #t69.{self::Class::field}.{self::Class::[]=}(c, new self::Class::•());
+  c = let final self::Class? #t70 = c in #t70.{core::Object::==}(null) ?{self::Class} null : let final self::Class? #t71 = #t70.{self::Class::field} in let final self::Class? #t72 = c in let final self::Class #t73 = new self::Class::•() in let final void #t74 = #t71.{self::Class::[]=}(#t72, #t73) in #t73;
+  let final self::Class? #t75 = c in #t75.{core::Object::==}(null) ?{self::Class?} null : #t75.{self::Class::field}.{self::Class::[]}(c).{self::Class::method}();
+  let final self::Class? #t76 = c in #t76.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t77 = #t76.{self::Class::field} in let final self::Class? #t78 = c in #t77.{self::Class::[]=}(#t78, #t77.{self::Class::[]}(#t78).{self::Class::+}(0));
+  c = let final self::Class? #t79 = c in #t79.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t80 = #t79.{self::Class::field} in let final self::Class? #t81 = c in let final self::Class? #t82 = #t80.{self::Class::[]}(#t81).{self::Class::+}(0) in let final void #t83 = #t80.{self::Class::[]=}(#t81, #t82) in #t82;
+  let final self::Class? #t84 = c in #t84.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t85 = #t84.{self::Class::field} in let final self::Class? #t86 = c in #t85.{self::Class::[]=}(#t86, #t85.{self::Class::[]}(#t86).{self::Class::+}(1));
+  c = let final self::Class? #t87 = c in #t87.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t88 = #t87.{self::Class::field} in let final self::Class? #t89 = c in let final self::Class? #t90 = #t88.{self::Class::[]}(#t89) in let final void #t91 = #t88.{self::Class::[]=}(#t89, #t90.{self::Class::+}(1)) in #t90;
+  let final self::Class? #t92 = c in #t92.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t93 = #t92.{self::Class::field} in let final self::Class? #t94 = c in let final self::Class? #t95 = #t93.{self::Class::[]}(#t94).{self::Class::+}(1) in let final void #t96 = #t93.{self::Class::[]=}(#t94, #t95) in #t95;
+  c = let final self::Class? #t97 = c in #t97.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t98 = #t97.{self::Class::field} in let final self::Class? #t99 = c in let final self::Class? #t100 = #t98.{self::Class::[]}(#t99).{self::Class::+}(1) in let final void #t101 = #t98.{self::Class::[]=}(#t99, #t100) in #t100;
 }
 static method operatorAccess(self::Class? c) → void {
-  self::throws(() → self::Class? => (let final self::Class? #t99 = c in #t99.{core::Object::==}(null) ?{self::Class?} null : #t99.{self::Class::field}).{self::Class::+}(0));
-  self::throws(() → self::Class? => (let final self::Class? #t100 = c in #t100.{core::Object::==}(null) ?{self::Class?} null : #t100.{self::Class::field}).{self::Class::unary-}());
-  let final self::Class? #t101 = c in #t101.{core::Object::==}(null) ?{self::Class?} null : #t101.{self::Class::field} = #t101.{self::Class::field}.{self::Class::+}(0);
-  c = let final self::Class? #t102 = c in #t102.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t103 = #t102.{self::Class::field}.{self::Class::+}(0) in let final void #t104 = #t102.{self::Class::field} = #t103 in #t103;
-  let final self::Class? #t105 = c in #t105.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t106 = #t105.{self::Class::field} in #t106.{self::Class::field} = #t106.{self::Class::field}.{self::Class::+}(0);
-  c = let final self::Class? #t107 = c in #t107.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t108 = #t107.{self::Class::field} in #t108.{self::Class::field} = #t108.{self::Class::field}.{self::Class::+}(0);
-  let final self::Class? #t109 = c in #t109.{core::Object::==}(null) ?{self::Class?} null : #t109.{self::Class::field} = #t109.{self::Class::field}.{self::Class::+}(1);
-  c = let final self::Class? #t110 = c in #t110.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t111 = #t110.{self::Class::field} in let final void #t112 = #t110.{self::Class::field} = #t111.{self::Class::+}(1) in #t111;
-  let final self::Class? #t113 = c in #t113.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t114 = #t113.{self::Class::field}.{self::Class::+}(1) in let final void #t115 = #t113.{self::Class::field} = #t114 in #t114;
-  c = let final self::Class? #t116 = c in #t116.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t117 = #t116.{self::Class::field}.{self::Class::+}(1) in let final void #t118 = #t116.{self::Class::field} = #t117 in #t117;
+  self::throws(() → self::Class? => (let final self::Class? #t102 = c in #t102.{core::Object::==}(null) ?{self::Class?} null : #t102.{self::Class::field}).{self::Class::+}(0));
+  self::throws(() → self::Class? => (let final self::Class? #t103 = c in #t103.{core::Object::==}(null) ?{self::Class?} null : #t103.{self::Class::field}).{self::Class::unary-}());
+  let final self::Class? #t104 = c in #t104.{core::Object::==}(null) ?{self::Class?} null : #t104.{self::Class::field} = #t104.{self::Class::field}.{self::Class::+}(0);
+  c = let final self::Class? #t105 = c in #t105.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t106 = #t105.{self::Class::field}.{self::Class::+}(0) in let final void #t107 = #t105.{self::Class::field} = #t106 in #t106;
+  let final self::Class? #t108 = c in #t108.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t109 = #t108.{self::Class::field} in #t109.{self::Class::field} = #t109.{self::Class::field}.{self::Class::+}(0);
+  c = let final self::Class? #t110 = c in #t110.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t111 = #t110.{self::Class::field} in #t111.{self::Class::field} = #t111.{self::Class::field}.{self::Class::+}(0);
+  let final self::Class? #t112 = c in #t112.{core::Object::==}(null) ?{self::Class?} null : #t112.{self::Class::field} = #t112.{self::Class::field}.{self::Class::+}(1);
+  c = let final self::Class? #t113 = c in #t113.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t114 = #t113.{self::Class::field} in let final void #t115 = #t113.{self::Class::field} = #t114.{self::Class::+}(1) in #t114;
+  let final self::Class? #t116 = c in #t116.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t117 = #t116.{self::Class::field}.{self::Class::+}(1) in let final void #t118 = #t116.{self::Class::field} = #t117 in #t117;
+  c = let final self::Class? #t119 = c in #t119.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t120 = #t119.{self::Class::field}.{self::Class::+}(1) in let final void #t121 = #t119.{self::Class::field} = #t120 in #t120;
 }
 static method ifNull(self::Class? c) → void {
-  let final self::Class? #t119 = c in #t119.{core::Object::==}(null) ?{self::Class?} null : #t119.{self::Class::field}.{core::Object::==}(null) ?{self::Class?} #t119.{self::Class::field} = c : null;
-  c = let final self::Class? #t120 = c in #t120.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t121 = #t120.{self::Class::field} in #t121.{core::Object::==}(null) ?{self::Class?} #t120.{self::Class::field} = c : #t121;
-  let final self::Class? #t122 = c in #t122.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t123 = #t122.{self::Class::field} in let final self::Class? #t124 = c in #t123.{self::Class::[]}(#t124).{core::Object::==}(null) ?{self::Class?} #t123.{self::Class::[]=}(#t124, c) : null;
+  let final self::Class? #t122 = c in #t122.{core::Object::==}(null) ?{self::Class?} null : #t122.{self::Class::field}.{core::Object::==}(null) ?{self::Class?} #t122.{self::Class::field} = c : null;
+  c = let final self::Class? #t123 = c in #t123.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t124 = #t123.{self::Class::field} in #t124.{core::Object::==}(null) ?{self::Class?} #t123.{self::Class::field} = c : #t124;
+  let final self::Class? #t125 = c in #t125.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t126 = #t125.{self::Class::field} in let final self::Class? #t127 = c in #t126.{self::Class::[]}(#t127).{core::Object::==}(null) ?{self::Class?} #t126.{self::Class::[]=}(#t127, c) : null;
 }
 static method throws(() → void f) → void {
   try {
diff --git a/pkg/front_end/testcases/nnbd/null_shorting.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/null_shorting.dart.strong.transformed.expect
index e1af1bb..d50fc22 100644
--- a/pkg/front_end/testcases/nnbd/null_shorting.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/null_shorting.dart.strong.transformed.expect
@@ -27,98 +27,101 @@
 }
 static method propertyAccess(self::Class? c) → void {
   let final self::Class? #t1 = c in #t1.{core::Object::==}(null) ?{self::Class?} null : #t1.{self::Class::field};
-  let final self::Class? #t2 = c in #t2.{core::Object::==}(null) ?{self::Class*} null : #t2.{self::Class::field} = new self::Class::•();
-  c = let final self::Class? #t3 = c in #t3.{core::Object::==}(null) ?{self::Class*} null : #t3.{self::Class::field} = new self::Class::•();
+  let final self::Class? #t2 = c in #t2.{core::Object::==}(null) ?{self::Class} null : #t2.{self::Class::field} = new self::Class::•();
+  c = let final self::Class? #t3 = c in #t3.{core::Object::==}(null) ?{self::Class} null : #t3.{self::Class::field} = new self::Class::•();
   let final self::Class? #t4 = c in #t4.{core::Object::==}(null) ?{self::Class?} null : #t4.{self::Class::method}();
   let final self::Class? #t5 = c in #t5.{core::Object::==}(null) ?{self::Class?} null : #t5.{self::Class::field}.{self::Class::field};
-  let final self::Class? #t6 = c in #t6.{core::Object::==}(null) ?{self::Class*} null : #t6.{self::Class::field}.{self::Class::field} = new self::Class::•();
+  let final self::Class? #t6 = c in #t6.{core::Object::==}(null) ?{self::Class} null : #t6.{self::Class::field}.{self::Class::field} = new self::Class::•();
   self::throws(() → self::Class? => (let final self::Class? #t7 = c in #t7.{core::Object::==}(null) ?{self::Class?} null : #t7.{self::Class::field}).{self::Class::field});
-  self::throws(() → self::Class? => (let final self::Class? #t8 = c in #t8.{core::Object::==}(null) ?{self::Class*} null : #t8.{self::Class::field} = new self::Class::•()).{self::Class::field});
+  self::throws(() → self::Class? => (let final self::Class? #t8 = c in #t8.{core::Object::==}(null) ?{self::Class} null : #t8.{self::Class::field} = new self::Class::•()).{self::Class::field});
   self::throws(() → self::Class? => (let final self::Class? #t9 = c in #t9.{core::Object::==}(null) ?{self::Class?} null : #t9.{self::Class::method}()).{self::Class::field});
-  c = let final self::Class? #t10 = c in #t10.{core::Object::==}(null) ?{self::Class*} null : #t10.{self::Class::field}.{self::Class::field} = new self::Class::•();
+  c = let final self::Class? #t10 = c in #t10.{core::Object::==}(null) ?{self::Class} null : #t10.{self::Class::field}.{self::Class::field} = new self::Class::•();
   let final self::Class? #t11 = c in #t11.{core::Object::==}(null) ?{self::Class?} null : #t11.{self::Class::field}.{self::Class::method}();
   let final self::Class? #t12 = c in #t12.{core::Object::==}(null) ?{self::Class?} null : #t12.{self::Class::field} = new self::Class::•().{self::Class::field};
   c = let final self::Class? #t13 = c in #t13.{core::Object::==}(null) ?{self::Class?} null : #t13.{self::Class::field} = new self::Class::•().{self::Class::field};
-  let final self::Class? #t14 = c in #t14.{core::Object::==}(null) ?{self::Class*} null : #t14.{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•();
-  c = let final self::Class? #t15 = c in #t15.{core::Object::==}(null) ?{self::Class*} null : #t15.{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•();
+  let final self::Class? #t14 = c in #t14.{core::Object::==}(null) ?{self::Class} null : #t14.{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•();
+  c = let final self::Class? #t15 = c in #t15.{core::Object::==}(null) ?{self::Class} null : #t15.{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•();
   let final self::Class? #t16 = c in #t16.{core::Object::==}(null) ?{self::Class?} null : #t16.{self::Class::field} = new self::Class::•().{self::Class::method}();
   c = let final self::Class? #t17 = c in #t17.{core::Object::==}(null) ?{self::Class?} null : #t17.{self::Class::field} = new self::Class::•().{self::Class::method}();
   let final self::Class? #t18 = c in #t18.{core::Object::==}(null) ?{self::Class?} null : #t18.{self::Class::method}().{self::Class::field};
-  let final self::Class? #t19 = c in #t19.{core::Object::==}(null) ?{self::Class*} null : #t19.{self::Class::method}().{self::Class::field} = new self::Class::•();
+  let final self::Class? #t19 = c in #t19.{core::Object::==}(null) ?{self::Class} null : #t19.{self::Class::method}().{self::Class::field} = new self::Class::•();
   let final self::Class? #t20 = c in #t20.{core::Object::==}(null) ?{self::Class?} null : #t20.{self::Class::method}().{self::Class::method}();
   let final self::Class? #t21 = c in #t21.{core::Object::==}(null) ?{self::Class?} null : #t21.{self::Class::field}.{self::Class::field}.{self::Class::field};
-  let final self::Class? #t22 = c in #t22.{core::Object::==}(null) ?{self::Class*} null : #t22.{self::Class::field}.{self::Class::field}.{self::Class::field} = new self::Class::•();
-  c = let final self::Class? #t23 = c in #t23.{core::Object::==}(null) ?{self::Class*} null : #t23.{self::Class::field}.{self::Class::field}.{self::Class::field} = new self::Class::•();
+  let final self::Class? #t22 = c in #t22.{core::Object::==}(null) ?{self::Class} null : #t22.{self::Class::field}.{self::Class::field}.{self::Class::field} = new self::Class::•();
+  c = let final self::Class? #t23 = c in #t23.{core::Object::==}(null) ?{self::Class} null : #t23.{self::Class::field}.{self::Class::field}.{self::Class::field} = new self::Class::•();
   let final self::Class? #t24 = c in #t24.{core::Object::==}(null) ?{self::Class?} null : #t24.{self::Class::field}.{self::Class::field}.{self::Class::method}();
   let final self::Class? #t25 = c in #t25.{core::Object::==}(null) ?{self::Class?} null : #t25.{self::Class::field} = new self::Class::•().{self::Class::field}.{self::Class::field};
   c = let final self::Class? #t26 = c in #t26.{core::Object::==}(null) ?{self::Class?} null : #t26.{self::Class::field} = new self::Class::•().{self::Class::field}.{self::Class::field};
-  let final self::Class? #t27 = c in #t27.{core::Object::==}(null) ?{self::Class*} null : #t27.{self::Class::field} = new self::Class::•().{self::Class::field}.{self::Class::field} = new self::Class::•();
-  c = let final self::Class? #t28 = c in #t28.{core::Object::==}(null) ?{self::Class*} null : #t28.{self::Class::field} = new self::Class::•().{self::Class::field}.{self::Class::field} = new self::Class::•();
+  let final self::Class? #t27 = c in #t27.{core::Object::==}(null) ?{self::Class} null : #t27.{self::Class::field} = new self::Class::•().{self::Class::field}.{self::Class::field} = new self::Class::•();
+  c = let final self::Class? #t28 = c in #t28.{core::Object::==}(null) ?{self::Class} null : #t28.{self::Class::field} = new self::Class::•().{self::Class::field}.{self::Class::field} = new self::Class::•();
   let final self::Class? #t29 = c in #t29.{core::Object::==}(null) ?{self::Class?} null : #t29.{self::Class::field} = new self::Class::•().{self::Class::field}.{self::Class::method}();
   c = let final self::Class? #t30 = c in #t30.{core::Object::==}(null) ?{self::Class?} null : #t30.{self::Class::field} = new self::Class::•().{self::Class::field}.{self::Class::method}();
   let final self::Class? #t31 = c in #t31.{core::Object::==}(null) ?{self::Class?} null : #t31.{self::Class::method}().{self::Class::field}.{self::Class::field};
-  let final self::Class? #t32 = c in #t32.{core::Object::==}(null) ?{self::Class*} null : #t32.{self::Class::method}().{self::Class::field}.{self::Class::field} = new self::Class::•();
+  let final self::Class? #t32 = c in #t32.{core::Object::==}(null) ?{self::Class} null : #t32.{self::Class::method}().{self::Class::field}.{self::Class::field} = new self::Class::•();
   let final self::Class? #t33 = c in #t33.{core::Object::==}(null) ?{self::Class?} null : #t33.{self::Class::method}().{self::Class::field}.{self::Class::method}();
   let final self::Class? #t34 = c in #t34.{core::Object::==}(null) ?{self::Class?} null : #t34.{self::Class::field}.{self::Class::field} = new self::Class::•().{self::Class::field};
   c = let final self::Class? #t35 = c in #t35.{core::Object::==}(null) ?{self::Class?} null : #t35.{self::Class::field}.{self::Class::field} = new self::Class::•().{self::Class::field};
-  let final self::Class? #t36 = c in #t36.{core::Object::==}(null) ?{self::Class*} null : #t36.{self::Class::field}.{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•();
-  c = let final self::Class? #t37 = c in #t37.{core::Object::==}(null) ?{self::Class*} null : #t37.{self::Class::field}.{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•();
+  let final self::Class? #t36 = c in #t36.{core::Object::==}(null) ?{self::Class} null : #t36.{self::Class::field}.{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•();
+  c = let final self::Class? #t37 = c in #t37.{core::Object::==}(null) ?{self::Class} null : #t37.{self::Class::field}.{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•();
   let final self::Class? #t38 = c in #t38.{core::Object::==}(null) ?{self::Class?} null : #t38.{self::Class::field}.{self::Class::field} = new self::Class::•().{self::Class::method}();
   c = let final self::Class? #t39 = c in #t39.{core::Object::==}(null) ?{self::Class?} null : #t39.{self::Class::field}.{self::Class::field} = new self::Class::•().{self::Class::method}();
   let final self::Class? #t40 = c in #t40.{core::Object::==}(null) ?{self::Class?} null : #t40.{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•().{self::Class::field};
   c = let final self::Class? #t41 = c in #t41.{core::Object::==}(null) ?{self::Class?} null : #t41.{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•().{self::Class::field};
-  let final self::Class? #t42 = c in #t42.{core::Object::==}(null) ?{self::Class*} null : #t42.{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•();
-  c = let final self::Class? #t43 = c in #t43.{core::Object::==}(null) ?{self::Class*} null : #t43.{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•();
+  let final self::Class? #t42 = c in #t42.{core::Object::==}(null) ?{self::Class} null : #t42.{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•();
+  c = let final self::Class? #t43 = c in #t43.{core::Object::==}(null) ?{self::Class} null : #t43.{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•();
   let final self::Class? #t44 = c in #t44.{core::Object::==}(null) ?{self::Class?} null : #t44.{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•().{self::Class::method}();
   c = let final self::Class? #t45 = c in #t45.{core::Object::==}(null) ?{self::Class?} null : #t45.{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•().{self::Class::method}();
   let final self::Class? #t46 = c in #t46.{core::Object::==}(null) ?{self::Class?} null : #t46.{self::Class::method}().{self::Class::field} = new self::Class::•().{self::Class::field};
   c = let final self::Class? #t47 = c in #t47.{core::Object::==}(null) ?{self::Class?} null : #t47.{self::Class::method}().{self::Class::field} = new self::Class::•().{self::Class::field};
-  let final self::Class? #t48 = c in #t48.{core::Object::==}(null) ?{self::Class*} null : #t48.{self::Class::method}().{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•();
-  c = let final self::Class? #t49 = c in #t49.{core::Object::==}(null) ?{self::Class*} null : #t49.{self::Class::method}().{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•();
+  let final self::Class? #t48 = c in #t48.{core::Object::==}(null) ?{self::Class} null : #t48.{self::Class::method}().{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•();
+  c = let final self::Class? #t49 = c in #t49.{core::Object::==}(null) ?{self::Class} null : #t49.{self::Class::method}().{self::Class::field} = new self::Class::•().{self::Class::field} = new self::Class::•();
   let final self::Class? #t50 = c in #t50.{core::Object::==}(null) ?{self::Class?} null : #t50.{self::Class::method}().{self::Class::field} = new self::Class::•().{self::Class::method}();
   c = let final self::Class? #t51 = c in #t51.{core::Object::==}(null) ?{self::Class?} null : #t51.{self::Class::method}().{self::Class::field} = new self::Class::•().{self::Class::method}();
   let final self::Class? #t52 = c in #t52.{core::Object::==}(null) ?{self::Class?} null : #t52.{self::Class::field}.{self::Class::method}().{self::Class::field};
-  let final self::Class? #t53 = c in #t53.{core::Object::==}(null) ?{self::Class*} null : #t53.{self::Class::field}.{self::Class::method}().{self::Class::field} = new self::Class::•();
-  c = let final self::Class? #t54 = c in #t54.{core::Object::==}(null) ?{self::Class*} null : #t54.{self::Class::field}.{self::Class::method}().{self::Class::field} = new self::Class::•();
+  let final self::Class? #t53 = c in #t53.{core::Object::==}(null) ?{self::Class} null : #t53.{self::Class::field}.{self::Class::method}().{self::Class::field} = new self::Class::•();
+  c = let final self::Class? #t54 = c in #t54.{core::Object::==}(null) ?{self::Class} null : #t54.{self::Class::field}.{self::Class::method}().{self::Class::field} = new self::Class::•();
   let final self::Class? #t55 = c in #t55.{core::Object::==}(null) ?{self::Class?} null : #t55.{self::Class::field}.{self::Class::method}().{self::Class::method}();
   let final self::Class? #t56 = c in #t56.{core::Object::==}(null) ?{self::Class?} null : #t56.{self::Class::field} = new self::Class::•().{self::Class::method}().{self::Class::field};
   c = let final self::Class? #t57 = c in #t57.{core::Object::==}(null) ?{self::Class?} null : #t57.{self::Class::field} = new self::Class::•().{self::Class::method}().{self::Class::field};
-  let final self::Class? #t58 = c in #t58.{core::Object::==}(null) ?{self::Class*} null : #t58.{self::Class::field} = new self::Class::•().{self::Class::method}().{self::Class::field} = new self::Class::•();
-  c = let final self::Class? #t59 = c in #t59.{core::Object::==}(null) ?{self::Class*} null : #t59.{self::Class::field} = new self::Class::•().{self::Class::method}().{self::Class::field} = new self::Class::•();
+  let final self::Class? #t58 = c in #t58.{core::Object::==}(null) ?{self::Class} null : #t58.{self::Class::field} = new self::Class::•().{self::Class::method}().{self::Class::field} = new self::Class::•();
+  c = let final self::Class? #t59 = c in #t59.{core::Object::==}(null) ?{self::Class} null : #t59.{self::Class::field} = new self::Class::•().{self::Class::method}().{self::Class::field} = new self::Class::•();
   let final self::Class? #t60 = c in #t60.{core::Object::==}(null) ?{self::Class?} null : #t60.{self::Class::field} = new self::Class::•().{self::Class::method}().{self::Class::method}();
   c = let final self::Class? #t61 = c in #t61.{core::Object::==}(null) ?{self::Class?} null : #t61.{self::Class::field} = new self::Class::•().{self::Class::method}().{self::Class::method}();
   let final self::Class? #t62 = c in #t62.{core::Object::==}(null) ?{self::Class?} null : #t62.{self::Class::method}().{self::Class::method}().{self::Class::field};
-  let final self::Class? #t63 = c in #t63.{core::Object::==}(null) ?{self::Class*} null : #t63.{self::Class::method}().{self::Class::method}().{self::Class::field} = new self::Class::•();
+  let final self::Class? #t63 = c in #t63.{core::Object::==}(null) ?{self::Class} null : #t63.{self::Class::method}().{self::Class::method}().{self::Class::field} = new self::Class::•();
   let final self::Class? #t64 = c in #t64.{core::Object::==}(null) ?{self::Class?} null : #t64.{self::Class::method}().{self::Class::method}().{self::Class::method}();
 }
 static method indexAccess(self::Class? c) → void {
-  let final self::Class? #t65 = c in #t65.{core::Object::==}(null) ?{self::Class?} null : #t65.{self::Class::field}.{self::Class::[]}(c);
-  let final self::Class? #t66 = c in #t66.{core::Object::==}(null) ?{self::Class*} null : #t66.{self::Class::field}.{self::Class::[]=}(c, new self::Class::•());
-  c = let final self::Class? #t67 = c in #t67.{core::Object::==}(null) ?{self::Class*} null : let final self::Class? #t68 = #t67.{self::Class::field} in let final self::Class? #t69 = c in let final self::Class* #t70 = new self::Class::•() in let final void #t71 = #t68.{self::Class::[]=}(#t69, #t70) in #t70;
-  let final self::Class? #t72 = c in #t72.{core::Object::==}(null) ?{self::Class?} null : #t72.{self::Class::field}.{self::Class::[]}(c).{self::Class::method}();
-  let final self::Class? #t73 = c in #t73.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t74 = #t73.{self::Class::field} in let final self::Class? #t75 = c in #t74.{self::Class::[]=}(#t75, #t74.{self::Class::[]}(#t75).{self::Class::+}(0));
-  c = let final self::Class? #t76 = c in #t76.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t77 = #t76.{self::Class::field} in let final self::Class? #t78 = c in let final self::Class? #t79 = #t77.{self::Class::[]}(#t78).{self::Class::+}(0) in let final void #t80 = #t77.{self::Class::[]=}(#t78, #t79) in #t79;
-  let final self::Class? #t81 = c in #t81.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t82 = #t81.{self::Class::field} in let final self::Class? #t83 = c in #t82.{self::Class::[]=}(#t83, #t82.{self::Class::[]}(#t83).{self::Class::+}(1));
-  c = let final self::Class? #t84 = c in #t84.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t85 = #t84.{self::Class::field} in let final self::Class? #t86 = c in let final self::Class? #t87 = #t85.{self::Class::[]}(#t86) in let final void #t88 = #t85.{self::Class::[]=}(#t86, #t87.{self::Class::+}(1)) in #t87;
-  let final self::Class? #t89 = c in #t89.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t90 = #t89.{self::Class::field} in let final self::Class? #t91 = c in let final self::Class? #t92 = #t90.{self::Class::[]}(#t91).{self::Class::+}(1) in let final void #t93 = #t90.{self::Class::[]=}(#t91, #t92) in #t92;
-  c = let final self::Class? #t94 = c in #t94.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t95 = #t94.{self::Class::field} in let final self::Class? #t96 = c in let final self::Class? #t97 = #t95.{self::Class::[]}(#t96).{self::Class::+}(1) in let final void #t98 = #t95.{self::Class::[]=}(#t96, #t97) in #t97;
+  let final self::Class? #t65 = c in #t65.{core::Object::==}(null) ?{self::Class?} null : #t65.{self::Class::[]}(c);
+  let final self::Class? #t66 = c in #t66.{core::Object::==}(null) ?{self::Class} null : #t66.{self::Class::[]=}(c, new self::Class::•());
+  let final self::Class? #t67 = c in #t67.{core::Object::==}(null) ?{self::Class?} null : #t67.{self::Class::[]}(c).{self::Class::method}();
+  let final self::Class? #t68 = c in #t68.{core::Object::==}(null) ?{self::Class?} null : #t68.{self::Class::field}.{self::Class::[]}(c);
+  let final self::Class? #t69 = c in #t69.{core::Object::==}(null) ?{self::Class} null : #t69.{self::Class::field}.{self::Class::[]=}(c, new self::Class::•());
+  c = let final self::Class? #t70 = c in #t70.{core::Object::==}(null) ?{self::Class} null : let final self::Class? #t71 = #t70.{self::Class::field} in let final self::Class? #t72 = c in let final self::Class #t73 = new self::Class::•() in let final void #t74 = #t71.{self::Class::[]=}(#t72, #t73) in #t73;
+  let final self::Class? #t75 = c in #t75.{core::Object::==}(null) ?{self::Class?} null : #t75.{self::Class::field}.{self::Class::[]}(c).{self::Class::method}();
+  let final self::Class? #t76 = c in #t76.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t77 = #t76.{self::Class::field} in let final self::Class? #t78 = c in #t77.{self::Class::[]=}(#t78, #t77.{self::Class::[]}(#t78).{self::Class::+}(0));
+  c = let final self::Class? #t79 = c in #t79.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t80 = #t79.{self::Class::field} in let final self::Class? #t81 = c in let final self::Class? #t82 = #t80.{self::Class::[]}(#t81).{self::Class::+}(0) in let final void #t83 = #t80.{self::Class::[]=}(#t81, #t82) in #t82;
+  let final self::Class? #t84 = c in #t84.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t85 = #t84.{self::Class::field} in let final self::Class? #t86 = c in #t85.{self::Class::[]=}(#t86, #t85.{self::Class::[]}(#t86).{self::Class::+}(1));
+  c = let final self::Class? #t87 = c in #t87.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t88 = #t87.{self::Class::field} in let final self::Class? #t89 = c in let final self::Class? #t90 = #t88.{self::Class::[]}(#t89) in let final void #t91 = #t88.{self::Class::[]=}(#t89, #t90.{self::Class::+}(1)) in #t90;
+  let final self::Class? #t92 = c in #t92.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t93 = #t92.{self::Class::field} in let final self::Class? #t94 = c in let final self::Class? #t95 = #t93.{self::Class::[]}(#t94).{self::Class::+}(1) in let final void #t96 = #t93.{self::Class::[]=}(#t94, #t95) in #t95;
+  c = let final self::Class? #t97 = c in #t97.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t98 = #t97.{self::Class::field} in let final self::Class? #t99 = c in let final self::Class? #t100 = #t98.{self::Class::[]}(#t99).{self::Class::+}(1) in let final void #t101 = #t98.{self::Class::[]=}(#t99, #t100) in #t100;
 }
 static method operatorAccess(self::Class? c) → void {
-  self::throws(() → self::Class? => (let final self::Class? #t99 = c in #t99.{core::Object::==}(null) ?{self::Class?} null : #t99.{self::Class::field}).{self::Class::+}(0));
-  self::throws(() → self::Class? => (let final self::Class? #t100 = c in #t100.{core::Object::==}(null) ?{self::Class?} null : #t100.{self::Class::field}).{self::Class::unary-}());
-  let final self::Class? #t101 = c in #t101.{core::Object::==}(null) ?{self::Class?} null : #t101.{self::Class::field} = #t101.{self::Class::field}.{self::Class::+}(0);
-  c = let final self::Class? #t102 = c in #t102.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t103 = #t102.{self::Class::field}.{self::Class::+}(0) in let final void #t104 = #t102.{self::Class::field} = #t103 in #t103;
-  let final self::Class? #t105 = c in #t105.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t106 = #t105.{self::Class::field} in #t106.{self::Class::field} = #t106.{self::Class::field}.{self::Class::+}(0);
-  c = let final self::Class? #t107 = c in #t107.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t108 = #t107.{self::Class::field} in #t108.{self::Class::field} = #t108.{self::Class::field}.{self::Class::+}(0);
-  let final self::Class? #t109 = c in #t109.{core::Object::==}(null) ?{self::Class?} null : #t109.{self::Class::field} = #t109.{self::Class::field}.{self::Class::+}(1);
-  c = let final self::Class? #t110 = c in #t110.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t111 = #t110.{self::Class::field} in let final void #t112 = #t110.{self::Class::field} = #t111.{self::Class::+}(1) in #t111;
-  let final self::Class? #t113 = c in #t113.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t114 = #t113.{self::Class::field}.{self::Class::+}(1) in let final void #t115 = #t113.{self::Class::field} = #t114 in #t114;
-  c = let final self::Class? #t116 = c in #t116.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t117 = #t116.{self::Class::field}.{self::Class::+}(1) in let final void #t118 = #t116.{self::Class::field} = #t117 in #t117;
+  self::throws(() → self::Class? => (let final self::Class? #t102 = c in #t102.{core::Object::==}(null) ?{self::Class?} null : #t102.{self::Class::field}).{self::Class::+}(0));
+  self::throws(() → self::Class? => (let final self::Class? #t103 = c in #t103.{core::Object::==}(null) ?{self::Class?} null : #t103.{self::Class::field}).{self::Class::unary-}());
+  let final self::Class? #t104 = c in #t104.{core::Object::==}(null) ?{self::Class?} null : #t104.{self::Class::field} = #t104.{self::Class::field}.{self::Class::+}(0);
+  c = let final self::Class? #t105 = c in #t105.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t106 = #t105.{self::Class::field}.{self::Class::+}(0) in let final void #t107 = #t105.{self::Class::field} = #t106 in #t106;
+  let final self::Class? #t108 = c in #t108.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t109 = #t108.{self::Class::field} in #t109.{self::Class::field} = #t109.{self::Class::field}.{self::Class::+}(0);
+  c = let final self::Class? #t110 = c in #t110.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t111 = #t110.{self::Class::field} in #t111.{self::Class::field} = #t111.{self::Class::field}.{self::Class::+}(0);
+  let final self::Class? #t112 = c in #t112.{core::Object::==}(null) ?{self::Class?} null : #t112.{self::Class::field} = #t112.{self::Class::field}.{self::Class::+}(1);
+  c = let final self::Class? #t113 = c in #t113.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t114 = #t113.{self::Class::field} in let final void #t115 = #t113.{self::Class::field} = #t114.{self::Class::+}(1) in #t114;
+  let final self::Class? #t116 = c in #t116.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t117 = #t116.{self::Class::field}.{self::Class::+}(1) in let final void #t118 = #t116.{self::Class::field} = #t117 in #t117;
+  c = let final self::Class? #t119 = c in #t119.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t120 = #t119.{self::Class::field}.{self::Class::+}(1) in let final void #t121 = #t119.{self::Class::field} = #t120 in #t120;
 }
 static method ifNull(self::Class? c) → void {
-  let final self::Class? #t119 = c in #t119.{core::Object::==}(null) ?{self::Class?} null : #t119.{self::Class::field}.{core::Object::==}(null) ?{self::Class?} #t119.{self::Class::field} = c : null;
-  c = let final self::Class? #t120 = c in #t120.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t121 = #t120.{self::Class::field} in #t121.{core::Object::==}(null) ?{self::Class?} #t120.{self::Class::field} = c : #t121;
-  let final self::Class? #t122 = c in #t122.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t123 = #t122.{self::Class::field} in let final self::Class? #t124 = c in #t123.{self::Class::[]}(#t124).{core::Object::==}(null) ?{self::Class?} #t123.{self::Class::[]=}(#t124, c) : null;
+  let final self::Class? #t122 = c in #t122.{core::Object::==}(null) ?{self::Class?} null : #t122.{self::Class::field}.{core::Object::==}(null) ?{self::Class?} #t122.{self::Class::field} = c : null;
+  c = let final self::Class? #t123 = c in #t123.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t124 = #t123.{self::Class::field} in #t124.{core::Object::==}(null) ?{self::Class?} #t123.{self::Class::field} = c : #t124;
+  let final self::Class? #t125 = c in #t125.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t126 = #t125.{self::Class::field} in let final self::Class? #t127 = c in #t126.{self::Class::[]}(#t127).{core::Object::==}(null) ?{self::Class?} #t126.{self::Class::[]=}(#t127, c) : null;
 }
 static method throws(() → void f) → void {
   try {
diff --git a/pkg/front_end/testcases/nnbd/null_shorting_cascade.dart b/pkg/front_end/testcases/nnbd/null_shorting_cascade.dart
new file mode 100644
index 0000000..5fc73745
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/null_shorting_cascade.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2019, 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 Class {
+  Class method() => this;
+}
+
+extension Extension on Class {
+  Class extensionMethod() => this;
+}
+
+main() {
+  Class? c;
+  c?..method();
+  c?..method()..method();
+  c?..extensionMethod();
+  c?..extensionMethod()..extensionMethod();
+}
diff --git a/pkg/front_end/testcases/nnbd/null_shorting_cascade.dart.outline.expect b/pkg/front_end/testcases/nnbd/null_shorting_cascade.dart.outline.expect
new file mode 100644
index 0000000..3538ffe
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/null_shorting_cascade.dart.outline.expect
@@ -0,0 +1,20 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  synthetic constructor •() → self::Class*
+    ;
+  method method() → self::Class
+    ;
+}
+extension Extension on self::Class {
+  method extensionMethod = self::Extension|extensionMethod;
+  tearoff extensionMethod = self::Extension|get#extensionMethod;
+}
+static method Extension|extensionMethod(final self::Class #this) → self::Class
+  ;
+static method Extension|get#extensionMethod(final self::Class #this) → () →* self::Class
+  return () → self::Class => self::Extension|extensionMethod(#this);
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/nnbd/null_shorting_cascade.dart.strong.expect b/pkg/front_end/testcases/nnbd/null_shorting_cascade.dart.strong.expect
new file mode 100644
index 0000000..d51a286
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/null_shorting_cascade.dart.strong.expect
@@ -0,0 +1,26 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  synthetic constructor •() → self::Class*
+    : super core::Object::•()
+    ;
+  method method() → self::Class
+    return this;
+}
+extension Extension on self::Class {
+  method extensionMethod = self::Extension|extensionMethod;
+  tearoff extensionMethod = self::Extension|get#extensionMethod;
+}
+static method Extension|extensionMethod(final self::Class #this) → self::Class
+  return #this;
+static method Extension|get#extensionMethod(final self::Class #this) → () →* self::Class
+  return () → self::Class => self::Extension|extensionMethod(#this);
+static method main() → dynamic {
+  self::Class? c;
+  let final self::Class? #t1 = c in #t1.{core::Object::==}(null) ?{self::Class?} null : let final void #t2 = #t1.{self::Class::method}() in #t1;
+  let final self::Class? #t3 = c in #t3.{core::Object::==}(null) ?{self::Class?} null : let final void #t4 = #t3.{self::Class::method}() in let final void #t5 = #t3.{self::Class::method}() in #t3;
+  let final self::Class? #t6 = c in #t6.{core::Object::==}(null) ?{self::Class?} null : let final void #t7 = self::Extension|extensionMethod(#t6) in #t6;
+  let final self::Class? #t8 = c in #t8.{core::Object::==}(null) ?{self::Class?} null : let final void #t9 = self::Extension|extensionMethod(#t8) in let final void #t10 = self::Extension|extensionMethod(#t8) in #t8;
+}
diff --git a/pkg/front_end/testcases/nnbd/null_shorting_cascade.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/null_shorting_cascade.dart.strong.transformed.expect
new file mode 100644
index 0000000..d51a286
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/null_shorting_cascade.dart.strong.transformed.expect
@@ -0,0 +1,26 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class extends core::Object {
+  synthetic constructor •() → self::Class*
+    : super core::Object::•()
+    ;
+  method method() → self::Class
+    return this;
+}
+extension Extension on self::Class {
+  method extensionMethod = self::Extension|extensionMethod;
+  tearoff extensionMethod = self::Extension|get#extensionMethod;
+}
+static method Extension|extensionMethod(final self::Class #this) → self::Class
+  return #this;
+static method Extension|get#extensionMethod(final self::Class #this) → () →* self::Class
+  return () → self::Class => self::Extension|extensionMethod(#this);
+static method main() → dynamic {
+  self::Class? c;
+  let final self::Class? #t1 = c in #t1.{core::Object::==}(null) ?{self::Class?} null : let final void #t2 = #t1.{self::Class::method}() in #t1;
+  let final self::Class? #t3 = c in #t3.{core::Object::==}(null) ?{self::Class?} null : let final void #t4 = #t3.{self::Class::method}() in let final void #t5 = #t3.{self::Class::method}() in #t3;
+  let final self::Class? #t6 = c in #t6.{core::Object::==}(null) ?{self::Class?} null : let final void #t7 = self::Extension|extensionMethod(#t6) in #t6;
+  let final self::Class? #t8 = c in #t8.{core::Object::==}(null) ?{self::Class?} null : let final void #t9 = self::Extension|extensionMethod(#t8) in let final void #t10 = self::Extension|extensionMethod(#t8) in #t8;
+}
diff --git a/pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart b/pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart
index 68821f8..0ea13c5 100644
--- a/pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart
+++ b/pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart
@@ -103,10 +103,9 @@
 }
 
 void indexAccess(Class? c) {
-  // TODO(johnniwinther): Handle null aware index access.
-  //Extension(c)?.[c];
-  //Extension(c)?.[c] = new Class();
-  //Extension(c)?.[c].method();
+  Extension(c)?.[c];
+  Extension(c)?.[c] = new Class();
+  Extension(c)?.[c].method();
   Extension(c)?.field[c];
   Extension(c)?.field[c] = new Class();
   c = Extension(c)?.field[c] = new Class();
diff --git a/pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart.strong.expect b/pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart.strong.expect
index a988b01..fc4fcc8 100644
--- a/pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart.strong.expect
@@ -44,98 +44,101 @@
 }
 static method propertyAccess(self::Class? c) → void {
   let final self::Class? #t1 = c in #t1.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(#t1);
-  let final self::Class? #t2 = c in #t2.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(#t2, new self::Class::•());
-  c = let final self::Class? #t3 = c in #t3.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t4 = new self::Class::•() in let final void #t5 = self::Extension|set#field(#t3, #t4) in #t4;
+  let final self::Class? #t2 = c in #t2.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(#t2, new self::Class::•());
+  c = let final self::Class? #t3 = c in #t3.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t4 = new self::Class::•() in let final void #t5 = self::Extension|set#field(#t3, #t4) in #t4;
   let final self::Class? #t6 = c in #t6.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(#t6);
   let final self::Class? #t7 = c in #t7.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(self::Extension|get#field(#t7));
-  let final self::Class? #t8 = c in #t8.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(self::Extension|get#field(#t8), new self::Class::•());
+  let final self::Class? #t8 = c in #t8.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(self::Extension|get#field(#t8), new self::Class::•());
   self::throws(() → self::Class? => self::Extension|get#field(let final self::Class? #t9 = c in #t9.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(#t9)));
-  self::throws(() → self::Class? => self::Extension|get#field(let final self::Class? #t10 = c in #t10.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t11 = new self::Class::•() in let final void #t12 = self::Extension|set#field(#t10, #t11) in #t11));
+  self::throws(() → self::Class? => self::Extension|get#field(let final self::Class? #t10 = c in #t10.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t11 = new self::Class::•() in let final void #t12 = self::Extension|set#field(#t10, #t11) in #t11));
   self::throws(() → self::Class? => self::Extension|get#field(let final self::Class? #t13 = c in #t13.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(#t13)));
-  c = let final self::Class? #t14 = c in #t14.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t15 = new self::Class::•() in let final void #t16 = self::Extension|set#field(self::Extension|get#field(#t14), #t15) in #t15;
+  c = let final self::Class? #t14 = c in #t14.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t15 = new self::Class::•() in let final void #t16 = self::Extension|set#field(self::Extension|get#field(#t14), #t15) in #t15;
   let final self::Class? #t17 = c in #t17.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(self::Extension|get#field(#t17));
   let final self::Class? #t18 = c in #t18.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t18, self::Extension|get#field(new self::Class::•()));
   c = let final self::Class? #t19 = c in #t19.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t20 = self::Extension|get#field(new self::Class::•()) in let final void #t21 = self::Extension|set#field(#t19, #t20) in #t20;
-  let final self::Class? #t22 = c in #t22.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(#t22, let final self::Class* #t23 = new self::Class::•() in let final void #t24 = self::Extension|set#field(new self::Class::•(), #t23) in #t23);
-  c = let final self::Class? #t25 = c in #t25.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t26 = let final self::Class* #t27 = new self::Class::•() in let final void #t28 = self::Extension|set#field(new self::Class::•(), #t27) in #t27 in let final void #t29 = self::Extension|set#field(#t25, #t26) in #t26;
+  let final self::Class? #t22 = c in #t22.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(#t22, let final self::Class #t23 = new self::Class::•() in let final void #t24 = self::Extension|set#field(new self::Class::•(), #t23) in #t23);
+  c = let final self::Class? #t25 = c in #t25.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t26 = let final self::Class #t27 = new self::Class::•() in let final void #t28 = self::Extension|set#field(new self::Class::•(), #t27) in #t27 in let final void #t29 = self::Extension|set#field(#t25, #t26) in #t26;
   let final self::Class? #t30 = c in #t30.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t30, self::Extension|method(new self::Class::•()));
   c = let final self::Class? #t31 = c in #t31.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t32 = self::Extension|method(new self::Class::•()) in let final void #t33 = self::Extension|set#field(#t31, #t32) in #t32;
   let final self::Class? #t34 = c in #t34.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(self::Extension|method(#t34));
-  let final self::Class? #t35 = c in #t35.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(self::Extension|method(#t35), new self::Class::•());
+  let final self::Class? #t35 = c in #t35.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(self::Extension|method(#t35), new self::Class::•());
   let final self::Class? #t36 = c in #t36.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(self::Extension|method(#t36));
   let final self::Class? #t37 = c in #t37.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(self::Extension|get#field(self::Extension|get#field(#t37)));
-  let final self::Class? #t38 = c in #t38.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(self::Extension|get#field(self::Extension|get#field(#t38)), new self::Class::•());
-  c = let final self::Class? #t39 = c in #t39.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t40 = new self::Class::•() in let final void #t41 = self::Extension|set#field(self::Extension|get#field(self::Extension|get#field(#t39)), #t40) in #t40;
+  let final self::Class? #t38 = c in #t38.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(self::Extension|get#field(self::Extension|get#field(#t38)), new self::Class::•());
+  c = let final self::Class? #t39 = c in #t39.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t40 = new self::Class::•() in let final void #t41 = self::Extension|set#field(self::Extension|get#field(self::Extension|get#field(#t39)), #t40) in #t40;
   let final self::Class? #t42 = c in #t42.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(self::Extension|get#field(self::Extension|get#field(#t42)));
   let final self::Class? #t43 = c in #t43.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t43, self::Extension|get#field(self::Extension|get#field(new self::Class::•())));
   c = let final self::Class? #t44 = c in #t44.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t45 = self::Extension|get#field(self::Extension|get#field(new self::Class::•())) in let final void #t46 = self::Extension|set#field(#t44, #t45) in #t45;
-  let final self::Class? #t47 = c in #t47.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(#t47, let final self::Class* #t48 = new self::Class::•() in let final void #t49 = self::Extension|set#field(self::Extension|get#field(new self::Class::•()), #t48) in #t48);
-  c = let final self::Class? #t50 = c in #t50.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t51 = let final self::Class* #t52 = new self::Class::•() in let final void #t53 = self::Extension|set#field(self::Extension|get#field(new self::Class::•()), #t52) in #t52 in let final void #t54 = self::Extension|set#field(#t50, #t51) in #t51;
+  let final self::Class? #t47 = c in #t47.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(#t47, let final self::Class #t48 = new self::Class::•() in let final void #t49 = self::Extension|set#field(self::Extension|get#field(new self::Class::•()), #t48) in #t48);
+  c = let final self::Class? #t50 = c in #t50.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t51 = let final self::Class #t52 = new self::Class::•() in let final void #t53 = self::Extension|set#field(self::Extension|get#field(new self::Class::•()), #t52) in #t52 in let final void #t54 = self::Extension|set#field(#t50, #t51) in #t51;
   let final self::Class? #t55 = c in #t55.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t55, self::Extension|method(self::Extension|get#field(new self::Class::•())));
   c = let final self::Class? #t56 = c in #t56.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t57 = self::Extension|method(self::Extension|get#field(new self::Class::•())) in let final void #t58 = self::Extension|set#field(#t56, #t57) in #t57;
   let final self::Class? #t59 = c in #t59.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(self::Extension|get#field(self::Extension|method(#t59)));
-  let final self::Class? #t60 = c in #t60.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(self::Extension|get#field(self::Extension|method(#t60)), new self::Class::•());
+  let final self::Class? #t60 = c in #t60.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(self::Extension|get#field(self::Extension|method(#t60)), new self::Class::•());
   let final self::Class? #t61 = c in #t61.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(self::Extension|get#field(self::Extension|method(#t61)));
   let final self::Class? #t62 = c in #t62.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(self::Extension|get#field(#t62), self::Extension|get#field(new self::Class::•()));
   c = let final self::Class? #t63 = c in #t63.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t64 = self::Extension|get#field(new self::Class::•()) in let final void #t65 = self::Extension|set#field(self::Extension|get#field(#t63), #t64) in #t64;
-  let final self::Class? #t66 = c in #t66.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(self::Extension|get#field(#t66), let final self::Class* #t67 = new self::Class::•() in let final void #t68 = self::Extension|set#field(new self::Class::•(), #t67) in #t67);
-  c = let final self::Class? #t69 = c in #t69.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t70 = let final self::Class* #t71 = new self::Class::•() in let final void #t72 = self::Extension|set#field(new self::Class::•(), #t71) in #t71 in let final void #t73 = self::Extension|set#field(self::Extension|get#field(#t69), #t70) in #t70;
+  let final self::Class? #t66 = c in #t66.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(self::Extension|get#field(#t66), let final self::Class #t67 = new self::Class::•() in let final void #t68 = self::Extension|set#field(new self::Class::•(), #t67) in #t67);
+  c = let final self::Class? #t69 = c in #t69.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t70 = let final self::Class #t71 = new self::Class::•() in let final void #t72 = self::Extension|set#field(new self::Class::•(), #t71) in #t71 in let final void #t73 = self::Extension|set#field(self::Extension|get#field(#t69), #t70) in #t70;
   let final self::Class? #t74 = c in #t74.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(self::Extension|get#field(#t74), self::Extension|method(new self::Class::•()));
   c = let final self::Class? #t75 = c in #t75.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t76 = self::Extension|method(new self::Class::•()) in let final void #t77 = self::Extension|set#field(self::Extension|get#field(#t75), #t76) in #t76;
   let final self::Class? #t78 = c in #t78.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t78, let final self::Class? #t79 = self::Extension|get#field(new self::Class::•()) in let final void #t80 = self::Extension|set#field(new self::Class::•(), #t79) in #t79);
   c = let final self::Class? #t81 = c in #t81.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t82 = let final self::Class? #t83 = self::Extension|get#field(new self::Class::•()) in let final void #t84 = self::Extension|set#field(new self::Class::•(), #t83) in #t83 in let final void #t85 = self::Extension|set#field(#t81, #t82) in #t82;
-  let final self::Class? #t86 = c in #t86.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(#t86, let final self::Class* #t87 = let final self::Class* #t88 = new self::Class::•() in let final void #t89 = self::Extension|set#field(new self::Class::•(), #t88) in #t88 in let final void #t90 = self::Extension|set#field(new self::Class::•(), #t87) in #t87);
-  c = let final self::Class? #t91 = c in #t91.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t92 = let final self::Class* #t93 = let final self::Class* #t94 = new self::Class::•() in let final void #t95 = self::Extension|set#field(new self::Class::•(), #t94) in #t94 in let final void #t96 = self::Extension|set#field(new self::Class::•(), #t93) in #t93 in let final void #t97 = self::Extension|set#field(#t91, #t92) in #t92;
+  let final self::Class? #t86 = c in #t86.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(#t86, let final self::Class #t87 = let final self::Class #t88 = new self::Class::•() in let final void #t89 = self::Extension|set#field(new self::Class::•(), #t88) in #t88 in let final void #t90 = self::Extension|set#field(new self::Class::•(), #t87) in #t87);
+  c = let final self::Class? #t91 = c in #t91.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t92 = let final self::Class #t93 = let final self::Class #t94 = new self::Class::•() in let final void #t95 = self::Extension|set#field(new self::Class::•(), #t94) in #t94 in let final void #t96 = self::Extension|set#field(new self::Class::•(), #t93) in #t93 in let final void #t97 = self::Extension|set#field(#t91, #t92) in #t92;
   let final self::Class? #t98 = c in #t98.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t98, let final self::Class? #t99 = self::Extension|method(new self::Class::•()) in let final void #t100 = self::Extension|set#field(new self::Class::•(), #t99) in #t99);
   c = let final self::Class? #t101 = c in #t101.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t102 = let final self::Class? #t103 = self::Extension|method(new self::Class::•()) in let final void #t104 = self::Extension|set#field(new self::Class::•(), #t103) in #t103 in let final void #t105 = self::Extension|set#field(#t101, #t102) in #t102;
   let final self::Class? #t106 = c in #t106.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(self::Extension|method(#t106), self::Extension|get#field(new self::Class::•()));
   c = let final self::Class? #t107 = c in #t107.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t108 = self::Extension|get#field(new self::Class::•()) in let final void #t109 = self::Extension|set#field(self::Extension|method(#t107), #t108) in #t108;
-  let final self::Class? #t110 = c in #t110.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(self::Extension|method(#t110), let final self::Class* #t111 = new self::Class::•() in let final void #t112 = self::Extension|set#field(new self::Class::•(), #t111) in #t111);
-  c = let final self::Class? #t113 = c in #t113.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t114 = let final self::Class* #t115 = new self::Class::•() in let final void #t116 = self::Extension|set#field(new self::Class::•(), #t115) in #t115 in let final void #t117 = self::Extension|set#field(self::Extension|method(#t113), #t114) in #t114;
+  let final self::Class? #t110 = c in #t110.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(self::Extension|method(#t110), let final self::Class #t111 = new self::Class::•() in let final void #t112 = self::Extension|set#field(new self::Class::•(), #t111) in #t111);
+  c = let final self::Class? #t113 = c in #t113.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t114 = let final self::Class #t115 = new self::Class::•() in let final void #t116 = self::Extension|set#field(new self::Class::•(), #t115) in #t115 in let final void #t117 = self::Extension|set#field(self::Extension|method(#t113), #t114) in #t114;
   let final self::Class? #t118 = c in #t118.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(self::Extension|method(#t118), self::Extension|method(new self::Class::•()));
   c = let final self::Class? #t119 = c in #t119.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t120 = self::Extension|method(new self::Class::•()) in let final void #t121 = self::Extension|set#field(self::Extension|method(#t119), #t120) in #t120;
   let final self::Class? #t122 = c in #t122.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(self::Extension|method(self::Extension|get#field(#t122)));
-  let final self::Class? #t123 = c in #t123.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(self::Extension|method(self::Extension|get#field(#t123)), new self::Class::•());
-  c = let final self::Class? #t124 = c in #t124.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t125 = new self::Class::•() in let final void #t126 = self::Extension|set#field(self::Extension|method(self::Extension|get#field(#t124)), #t125) in #t125;
+  let final self::Class? #t123 = c in #t123.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(self::Extension|method(self::Extension|get#field(#t123)), new self::Class::•());
+  c = let final self::Class? #t124 = c in #t124.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t125 = new self::Class::•() in let final void #t126 = self::Extension|set#field(self::Extension|method(self::Extension|get#field(#t124)), #t125) in #t125;
   let final self::Class? #t127 = c in #t127.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(self::Extension|method(self::Extension|get#field(#t127)));
   let final self::Class? #t128 = c in #t128.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t128, self::Extension|get#field(self::Extension|method(new self::Class::•())));
   c = let final self::Class? #t129 = c in #t129.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t130 = self::Extension|get#field(self::Extension|method(new self::Class::•())) in let final void #t131 = self::Extension|set#field(#t129, #t130) in #t130;
-  let final self::Class? #t132 = c in #t132.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(#t132, let final self::Class* #t133 = new self::Class::•() in let final void #t134 = self::Extension|set#field(self::Extension|method(new self::Class::•()), #t133) in #t133);
-  c = let final self::Class? #t135 = c in #t135.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t136 = let final self::Class* #t137 = new self::Class::•() in let final void #t138 = self::Extension|set#field(self::Extension|method(new self::Class::•()), #t137) in #t137 in let final void #t139 = self::Extension|set#field(#t135, #t136) in #t136;
+  let final self::Class? #t132 = c in #t132.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(#t132, let final self::Class #t133 = new self::Class::•() in let final void #t134 = self::Extension|set#field(self::Extension|method(new self::Class::•()), #t133) in #t133);
+  c = let final self::Class? #t135 = c in #t135.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t136 = let final self::Class #t137 = new self::Class::•() in let final void #t138 = self::Extension|set#field(self::Extension|method(new self::Class::•()), #t137) in #t137 in let final void #t139 = self::Extension|set#field(#t135, #t136) in #t136;
   let final self::Class? #t140 = c in #t140.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t140, self::Extension|method(self::Extension|method(new self::Class::•())));
   c = let final self::Class? #t141 = c in #t141.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t142 = self::Extension|method(self::Extension|method(new self::Class::•())) in let final void #t143 = self::Extension|set#field(#t141, #t142) in #t142;
   let final self::Class? #t144 = c in #t144.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(self::Extension|method(self::Extension|method(#t144)));
-  let final self::Class? #t145 = c in #t145.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(self::Extension|method(self::Extension|method(#t145)), new self::Class::•());
+  let final self::Class? #t145 = c in #t145.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(self::Extension|method(self::Extension|method(#t145)), new self::Class::•());
   let final self::Class? #t146 = c in #t146.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(self::Extension|method(self::Extension|method(#t146)));
 }
 static method indexAccess(self::Class? c) → void {
-  let final self::Class? #t147 = c in #t147.{core::Object::==}(null) ?{self::Class?} null : self::Extension|[](self::Extension|get#field(#t147), c);
-  let final self::Class? #t148 = c in #t148.{core::Object::==}(null) ?{self::Class*} null : self::Extension|[]=(self::Extension|get#field(#t148), c, new self::Class::•());
-  c = let final self::Class? #t149 = c in #t149.{core::Object::==}(null) ?{self::Class*} null : let final self::Class? #t150 = self::Extension|get#field(#t149) in let final self::Class? #t151 = c in let final self::Class* #t152 = new self::Class::•() in let final void #t153 = self::Extension|[]=(#t150, #t151, #t152) in #t152;
-  let final self::Class? #t154 = c in #t154.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(self::Extension|[](self::Extension|get#field(#t154), c));
-  let final self::Class? #t155 = c in #t155.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t156 = self::Extension|get#field(#t155) in let final self::Class? #t157 = c in self::Extension|[]=(#t156, #t157, self::Extension|+(self::Extension|[](#t156, #t157), 0));
-  c = let final self::Class? #t158 = c in #t158.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t159 = self::Extension|get#field(#t158) in let final self::Class? #t160 = c in let final self::Class? #t161 = self::Extension|+(self::Extension|[](#t159, #t160), 0) in let final void #t162 = self::Extension|[]=(#t159, #t160, #t161) in #t161;
-  let final self::Class? #t163 = c in #t163.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t164 = self::Extension|get#field(#t163) in let final self::Class? #t165 = c in self::Extension|[]=(#t164, #t165, self::Extension|+(self::Extension|[](#t164, #t165), 1));
-  c = let final self::Class? #t166 = c in #t166.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t167 = self::Extension|get#field(#t166) in let final self::Class? #t168 = c in let final self::Class? #t169 = self::Extension|[](#t167, #t168) in let final void #t170 = self::Extension|[]=(#t167, #t168, self::Extension|+(#t169, 1)) in #t169;
-  let final self::Class? #t171 = c in #t171.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t172 = self::Extension|get#field(#t171) in let final self::Class? #t173 = c in let final self::Class? #t174 = self::Extension|+(self::Extension|[](#t172, #t173), 1) in let final void #t175 = self::Extension|[]=(#t172, #t173, #t174) in #t174;
-  c = let final self::Class? #t176 = c in #t176.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t177 = self::Extension|get#field(#t176) in let final self::Class? #t178 = c in let final self::Class? #t179 = self::Extension|+(self::Extension|[](#t177, #t178), 1) in let final void #t180 = self::Extension|[]=(#t177, #t178, #t179) in #t179;
+  let final self::Class? #t147 = c in #t147.{core::Object::==}(null) ?{self::Class?} null : self::Extension|[](#t147, c);
+  let final self::Class? #t148 = c in #t148.{core::Object::==}(null) ?{void} null : self::Extension|[]=(#t148, c, new self::Class::•());
+  let final self::Class? #t149 = c in #t149.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(self::Extension|[](#t149, c));
+  let final self::Class? #t150 = c in #t150.{core::Object::==}(null) ?{self::Class?} null : self::Extension|[](self::Extension|get#field(#t150), c);
+  let final self::Class? #t151 = c in #t151.{core::Object::==}(null) ?{self::Class} null : self::Extension|[]=(self::Extension|get#field(#t151), c, new self::Class::•());
+  c = let final self::Class? #t152 = c in #t152.{core::Object::==}(null) ?{self::Class} null : let final self::Class? #t153 = self::Extension|get#field(#t152) in let final self::Class? #t154 = c in let final self::Class #t155 = new self::Class::•() in let final void #t156 = self::Extension|[]=(#t153, #t154, #t155) in #t155;
+  let final self::Class? #t157 = c in #t157.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(self::Extension|[](self::Extension|get#field(#t157), c));
+  let final self::Class? #t158 = c in #t158.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t159 = self::Extension|get#field(#t158) in let final self::Class? #t160 = c in self::Extension|[]=(#t159, #t160, self::Extension|+(self::Extension|[](#t159, #t160), 0));
+  c = let final self::Class? #t161 = c in #t161.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t162 = self::Extension|get#field(#t161) in let final self::Class? #t163 = c in let final self::Class? #t164 = self::Extension|+(self::Extension|[](#t162, #t163), 0) in let final void #t165 = self::Extension|[]=(#t162, #t163, #t164) in #t164;
+  let final self::Class? #t166 = c in #t166.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t167 = self::Extension|get#field(#t166) in let final self::Class? #t168 = c in self::Extension|[]=(#t167, #t168, self::Extension|+(self::Extension|[](#t167, #t168), 1));
+  c = let final self::Class? #t169 = c in #t169.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t170 = self::Extension|get#field(#t169) in let final self::Class? #t171 = c in let final self::Class? #t172 = self::Extension|[](#t170, #t171) in let final void #t173 = self::Extension|[]=(#t170, #t171, self::Extension|+(#t172, 1)) in #t172;
+  let final self::Class? #t174 = c in #t174.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t175 = self::Extension|get#field(#t174) in let final self::Class? #t176 = c in let final self::Class? #t177 = self::Extension|+(self::Extension|[](#t175, #t176), 1) in let final void #t178 = self::Extension|[]=(#t175, #t176, #t177) in #t177;
+  c = let final self::Class? #t179 = c in #t179.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t180 = self::Extension|get#field(#t179) in let final self::Class? #t181 = c in let final self::Class? #t182 = self::Extension|+(self::Extension|[](#t180, #t181), 1) in let final void #t183 = self::Extension|[]=(#t180, #t181, #t182) in #t182;
 }
 static method operatorAccess(self::Class? c) → void {
-  self::throws(() → self::Class? => self::Extension|+(let final self::Class? #t181 = c in #t181.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(#t181), 0));
-  self::throws(() → self::Class? => self::Extension|unary-(let final self::Class? #t182 = c in #t182.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(#t182)));
-  let final self::Class? #t183 = c in #t183.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t183, self::Extension|+(self::Extension|get#field(#t183), 0));
-  c = let final self::Class? #t184 = c in #t184.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t185 = self::Extension|+(self::Extension|get#field(#t184), 0) in let final void #t186 = self::Extension|set#field(#t184, #t185) in #t185;
-  let final self::Class? #t187 = c in #t187.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t188 = self::Extension|get#field(#t187) in self::Extension|set#field(#t188, self::Extension|+(self::Extension|get#field(#t188), 0));
-  c = let final self::Class? #t189 = c in #t189.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t190 = self::Extension|get#field(#t189) in let final self::Class? #t191 = self::Extension|+(self::Extension|get#field(#t190), 0) in let final void #t192 = self::Extension|set#field(#t190, #t191) in #t191;
-  let final self::Class? #t193 = c in #t193.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t193, self::Extension|+(self::Extension|get#field(#t193), 1));
-  c = let final self::Class? #t194 = c in #t194.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t195 = self::Extension|get#field(#t194) in let final self::Class? #t196 = let final self::Class? #t197 = self::Extension|+(#t195, 1) in let final void #t198 = self::Extension|set#field(#t194, #t197) in #t197 in #t195;
-  let final self::Class? #t199 = c in #t199.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t200 = self::Extension|+(self::Extension|get#field(#t199), 1) in let final void #t201 = self::Extension|set#field(#t199, #t200) in #t200;
-  c = let final self::Class? #t202 = c in #t202.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t203 = self::Extension|+(self::Extension|get#field(#t202), 1) in let final void #t204 = self::Extension|set#field(#t202, #t203) in #t203;
+  self::throws(() → self::Class? => self::Extension|+(let final self::Class? #t184 = c in #t184.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(#t184), 0));
+  self::throws(() → self::Class? => self::Extension|unary-(let final self::Class? #t185 = c in #t185.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(#t185)));
+  let final self::Class? #t186 = c in #t186.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t186, self::Extension|+(self::Extension|get#field(#t186), 0));
+  c = let final self::Class? #t187 = c in #t187.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t188 = self::Extension|+(self::Extension|get#field(#t187), 0) in let final void #t189 = self::Extension|set#field(#t187, #t188) in #t188;
+  let final self::Class? #t190 = c in #t190.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t191 = self::Extension|get#field(#t190) in self::Extension|set#field(#t191, self::Extension|+(self::Extension|get#field(#t191), 0));
+  c = let final self::Class? #t192 = c in #t192.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t193 = self::Extension|get#field(#t192) in let final self::Class? #t194 = self::Extension|+(self::Extension|get#field(#t193), 0) in let final void #t195 = self::Extension|set#field(#t193, #t194) in #t194;
+  let final self::Class? #t196 = c in #t196.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t196, self::Extension|+(self::Extension|get#field(#t196), 1));
+  c = let final self::Class? #t197 = c in #t197.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t198 = self::Extension|get#field(#t197) in let final self::Class? #t199 = let final self::Class? #t200 = self::Extension|+(#t198, 1) in let final void #t201 = self::Extension|set#field(#t197, #t200) in #t200 in #t198;
+  let final self::Class? #t202 = c in #t202.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t203 = self::Extension|+(self::Extension|get#field(#t202), 1) in let final void #t204 = self::Extension|set#field(#t202, #t203) in #t203;
+  c = let final self::Class? #t205 = c in #t205.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t206 = self::Extension|+(self::Extension|get#field(#t205), 1) in let final void #t207 = self::Extension|set#field(#t205, #t206) in #t206;
 }
 static method ifNull(self::Class? c) → void {
-  let final self::Class? #t205 = c in #t205.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(#t205).{core::Object::==}(null) ?{self::Class?} self::Extension|set#field(#t205, c) : null;
-  c = let final self::Class? #t206 = c in #t206.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t207 = self::Extension|get#field(#t206) in #t207.{core::Object::==}(null) ?{self::Class?} let final self::Class? #t208 = c in let final void #t209 = self::Extension|set#field(#t206, #t208) in #t208 : #t207;
-  let final self::Class? #t210 = c in #t210.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t211 = self::Extension|get#field(#t210) in let final self::Class? #t212 = c in self::Extension|[](#t211, #t212).{core::Object::==}(null) ?{self::Class?} self::Extension|[]=(#t211, #t212, c) : null;
+  let final self::Class? #t208 = c in #t208.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(#t208).{core::Object::==}(null) ?{self::Class?} self::Extension|set#field(#t208, c) : null;
+  c = let final self::Class? #t209 = c in #t209.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t210 = self::Extension|get#field(#t209) in #t210.{core::Object::==}(null) ?{self::Class?} let final self::Class? #t211 = c in let final void #t212 = self::Extension|set#field(#t209, #t211) in #t211 : #t210;
+  let final self::Class? #t213 = c in #t213.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t214 = self::Extension|get#field(#t213) in let final self::Class? #t215 = c in self::Extension|[](#t214, #t215).{core::Object::==}(null) ?{self::Class?} self::Extension|[]=(#t214, #t215, c) : null;
 }
 static method throws(() → void f) → void {
   try {
diff --git a/pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart.strong.transformed.expect
index a988b01..fc4fcc8 100644
--- a/pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/null_shorting_explicit_extension.dart.strong.transformed.expect
@@ -44,98 +44,101 @@
 }
 static method propertyAccess(self::Class? c) → void {
   let final self::Class? #t1 = c in #t1.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(#t1);
-  let final self::Class? #t2 = c in #t2.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(#t2, new self::Class::•());
-  c = let final self::Class? #t3 = c in #t3.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t4 = new self::Class::•() in let final void #t5 = self::Extension|set#field(#t3, #t4) in #t4;
+  let final self::Class? #t2 = c in #t2.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(#t2, new self::Class::•());
+  c = let final self::Class? #t3 = c in #t3.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t4 = new self::Class::•() in let final void #t5 = self::Extension|set#field(#t3, #t4) in #t4;
   let final self::Class? #t6 = c in #t6.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(#t6);
   let final self::Class? #t7 = c in #t7.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(self::Extension|get#field(#t7));
-  let final self::Class? #t8 = c in #t8.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(self::Extension|get#field(#t8), new self::Class::•());
+  let final self::Class? #t8 = c in #t8.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(self::Extension|get#field(#t8), new self::Class::•());
   self::throws(() → self::Class? => self::Extension|get#field(let final self::Class? #t9 = c in #t9.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(#t9)));
-  self::throws(() → self::Class? => self::Extension|get#field(let final self::Class? #t10 = c in #t10.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t11 = new self::Class::•() in let final void #t12 = self::Extension|set#field(#t10, #t11) in #t11));
+  self::throws(() → self::Class? => self::Extension|get#field(let final self::Class? #t10 = c in #t10.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t11 = new self::Class::•() in let final void #t12 = self::Extension|set#field(#t10, #t11) in #t11));
   self::throws(() → self::Class? => self::Extension|get#field(let final self::Class? #t13 = c in #t13.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(#t13)));
-  c = let final self::Class? #t14 = c in #t14.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t15 = new self::Class::•() in let final void #t16 = self::Extension|set#field(self::Extension|get#field(#t14), #t15) in #t15;
+  c = let final self::Class? #t14 = c in #t14.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t15 = new self::Class::•() in let final void #t16 = self::Extension|set#field(self::Extension|get#field(#t14), #t15) in #t15;
   let final self::Class? #t17 = c in #t17.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(self::Extension|get#field(#t17));
   let final self::Class? #t18 = c in #t18.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t18, self::Extension|get#field(new self::Class::•()));
   c = let final self::Class? #t19 = c in #t19.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t20 = self::Extension|get#field(new self::Class::•()) in let final void #t21 = self::Extension|set#field(#t19, #t20) in #t20;
-  let final self::Class? #t22 = c in #t22.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(#t22, let final self::Class* #t23 = new self::Class::•() in let final void #t24 = self::Extension|set#field(new self::Class::•(), #t23) in #t23);
-  c = let final self::Class? #t25 = c in #t25.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t26 = let final self::Class* #t27 = new self::Class::•() in let final void #t28 = self::Extension|set#field(new self::Class::•(), #t27) in #t27 in let final void #t29 = self::Extension|set#field(#t25, #t26) in #t26;
+  let final self::Class? #t22 = c in #t22.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(#t22, let final self::Class #t23 = new self::Class::•() in let final void #t24 = self::Extension|set#field(new self::Class::•(), #t23) in #t23);
+  c = let final self::Class? #t25 = c in #t25.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t26 = let final self::Class #t27 = new self::Class::•() in let final void #t28 = self::Extension|set#field(new self::Class::•(), #t27) in #t27 in let final void #t29 = self::Extension|set#field(#t25, #t26) in #t26;
   let final self::Class? #t30 = c in #t30.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t30, self::Extension|method(new self::Class::•()));
   c = let final self::Class? #t31 = c in #t31.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t32 = self::Extension|method(new self::Class::•()) in let final void #t33 = self::Extension|set#field(#t31, #t32) in #t32;
   let final self::Class? #t34 = c in #t34.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(self::Extension|method(#t34));
-  let final self::Class? #t35 = c in #t35.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(self::Extension|method(#t35), new self::Class::•());
+  let final self::Class? #t35 = c in #t35.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(self::Extension|method(#t35), new self::Class::•());
   let final self::Class? #t36 = c in #t36.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(self::Extension|method(#t36));
   let final self::Class? #t37 = c in #t37.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(self::Extension|get#field(self::Extension|get#field(#t37)));
-  let final self::Class? #t38 = c in #t38.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(self::Extension|get#field(self::Extension|get#field(#t38)), new self::Class::•());
-  c = let final self::Class? #t39 = c in #t39.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t40 = new self::Class::•() in let final void #t41 = self::Extension|set#field(self::Extension|get#field(self::Extension|get#field(#t39)), #t40) in #t40;
+  let final self::Class? #t38 = c in #t38.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(self::Extension|get#field(self::Extension|get#field(#t38)), new self::Class::•());
+  c = let final self::Class? #t39 = c in #t39.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t40 = new self::Class::•() in let final void #t41 = self::Extension|set#field(self::Extension|get#field(self::Extension|get#field(#t39)), #t40) in #t40;
   let final self::Class? #t42 = c in #t42.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(self::Extension|get#field(self::Extension|get#field(#t42)));
   let final self::Class? #t43 = c in #t43.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t43, self::Extension|get#field(self::Extension|get#field(new self::Class::•())));
   c = let final self::Class? #t44 = c in #t44.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t45 = self::Extension|get#field(self::Extension|get#field(new self::Class::•())) in let final void #t46 = self::Extension|set#field(#t44, #t45) in #t45;
-  let final self::Class? #t47 = c in #t47.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(#t47, let final self::Class* #t48 = new self::Class::•() in let final void #t49 = self::Extension|set#field(self::Extension|get#field(new self::Class::•()), #t48) in #t48);
-  c = let final self::Class? #t50 = c in #t50.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t51 = let final self::Class* #t52 = new self::Class::•() in let final void #t53 = self::Extension|set#field(self::Extension|get#field(new self::Class::•()), #t52) in #t52 in let final void #t54 = self::Extension|set#field(#t50, #t51) in #t51;
+  let final self::Class? #t47 = c in #t47.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(#t47, let final self::Class #t48 = new self::Class::•() in let final void #t49 = self::Extension|set#field(self::Extension|get#field(new self::Class::•()), #t48) in #t48);
+  c = let final self::Class? #t50 = c in #t50.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t51 = let final self::Class #t52 = new self::Class::•() in let final void #t53 = self::Extension|set#field(self::Extension|get#field(new self::Class::•()), #t52) in #t52 in let final void #t54 = self::Extension|set#field(#t50, #t51) in #t51;
   let final self::Class? #t55 = c in #t55.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t55, self::Extension|method(self::Extension|get#field(new self::Class::•())));
   c = let final self::Class? #t56 = c in #t56.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t57 = self::Extension|method(self::Extension|get#field(new self::Class::•())) in let final void #t58 = self::Extension|set#field(#t56, #t57) in #t57;
   let final self::Class? #t59 = c in #t59.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(self::Extension|get#field(self::Extension|method(#t59)));
-  let final self::Class? #t60 = c in #t60.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(self::Extension|get#field(self::Extension|method(#t60)), new self::Class::•());
+  let final self::Class? #t60 = c in #t60.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(self::Extension|get#field(self::Extension|method(#t60)), new self::Class::•());
   let final self::Class? #t61 = c in #t61.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(self::Extension|get#field(self::Extension|method(#t61)));
   let final self::Class? #t62 = c in #t62.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(self::Extension|get#field(#t62), self::Extension|get#field(new self::Class::•()));
   c = let final self::Class? #t63 = c in #t63.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t64 = self::Extension|get#field(new self::Class::•()) in let final void #t65 = self::Extension|set#field(self::Extension|get#field(#t63), #t64) in #t64;
-  let final self::Class? #t66 = c in #t66.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(self::Extension|get#field(#t66), let final self::Class* #t67 = new self::Class::•() in let final void #t68 = self::Extension|set#field(new self::Class::•(), #t67) in #t67);
-  c = let final self::Class? #t69 = c in #t69.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t70 = let final self::Class* #t71 = new self::Class::•() in let final void #t72 = self::Extension|set#field(new self::Class::•(), #t71) in #t71 in let final void #t73 = self::Extension|set#field(self::Extension|get#field(#t69), #t70) in #t70;
+  let final self::Class? #t66 = c in #t66.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(self::Extension|get#field(#t66), let final self::Class #t67 = new self::Class::•() in let final void #t68 = self::Extension|set#field(new self::Class::•(), #t67) in #t67);
+  c = let final self::Class? #t69 = c in #t69.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t70 = let final self::Class #t71 = new self::Class::•() in let final void #t72 = self::Extension|set#field(new self::Class::•(), #t71) in #t71 in let final void #t73 = self::Extension|set#field(self::Extension|get#field(#t69), #t70) in #t70;
   let final self::Class? #t74 = c in #t74.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(self::Extension|get#field(#t74), self::Extension|method(new self::Class::•()));
   c = let final self::Class? #t75 = c in #t75.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t76 = self::Extension|method(new self::Class::•()) in let final void #t77 = self::Extension|set#field(self::Extension|get#field(#t75), #t76) in #t76;
   let final self::Class? #t78 = c in #t78.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t78, let final self::Class? #t79 = self::Extension|get#field(new self::Class::•()) in let final void #t80 = self::Extension|set#field(new self::Class::•(), #t79) in #t79);
   c = let final self::Class? #t81 = c in #t81.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t82 = let final self::Class? #t83 = self::Extension|get#field(new self::Class::•()) in let final void #t84 = self::Extension|set#field(new self::Class::•(), #t83) in #t83 in let final void #t85 = self::Extension|set#field(#t81, #t82) in #t82;
-  let final self::Class? #t86 = c in #t86.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(#t86, let final self::Class* #t87 = let final self::Class* #t88 = new self::Class::•() in let final void #t89 = self::Extension|set#field(new self::Class::•(), #t88) in #t88 in let final void #t90 = self::Extension|set#field(new self::Class::•(), #t87) in #t87);
-  c = let final self::Class? #t91 = c in #t91.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t92 = let final self::Class* #t93 = let final self::Class* #t94 = new self::Class::•() in let final void #t95 = self::Extension|set#field(new self::Class::•(), #t94) in #t94 in let final void #t96 = self::Extension|set#field(new self::Class::•(), #t93) in #t93 in let final void #t97 = self::Extension|set#field(#t91, #t92) in #t92;
+  let final self::Class? #t86 = c in #t86.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(#t86, let final self::Class #t87 = let final self::Class #t88 = new self::Class::•() in let final void #t89 = self::Extension|set#field(new self::Class::•(), #t88) in #t88 in let final void #t90 = self::Extension|set#field(new self::Class::•(), #t87) in #t87);
+  c = let final self::Class? #t91 = c in #t91.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t92 = let final self::Class #t93 = let final self::Class #t94 = new self::Class::•() in let final void #t95 = self::Extension|set#field(new self::Class::•(), #t94) in #t94 in let final void #t96 = self::Extension|set#field(new self::Class::•(), #t93) in #t93 in let final void #t97 = self::Extension|set#field(#t91, #t92) in #t92;
   let final self::Class? #t98 = c in #t98.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t98, let final self::Class? #t99 = self::Extension|method(new self::Class::•()) in let final void #t100 = self::Extension|set#field(new self::Class::•(), #t99) in #t99);
   c = let final self::Class? #t101 = c in #t101.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t102 = let final self::Class? #t103 = self::Extension|method(new self::Class::•()) in let final void #t104 = self::Extension|set#field(new self::Class::•(), #t103) in #t103 in let final void #t105 = self::Extension|set#field(#t101, #t102) in #t102;
   let final self::Class? #t106 = c in #t106.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(self::Extension|method(#t106), self::Extension|get#field(new self::Class::•()));
   c = let final self::Class? #t107 = c in #t107.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t108 = self::Extension|get#field(new self::Class::•()) in let final void #t109 = self::Extension|set#field(self::Extension|method(#t107), #t108) in #t108;
-  let final self::Class? #t110 = c in #t110.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(self::Extension|method(#t110), let final self::Class* #t111 = new self::Class::•() in let final void #t112 = self::Extension|set#field(new self::Class::•(), #t111) in #t111);
-  c = let final self::Class? #t113 = c in #t113.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t114 = let final self::Class* #t115 = new self::Class::•() in let final void #t116 = self::Extension|set#field(new self::Class::•(), #t115) in #t115 in let final void #t117 = self::Extension|set#field(self::Extension|method(#t113), #t114) in #t114;
+  let final self::Class? #t110 = c in #t110.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(self::Extension|method(#t110), let final self::Class #t111 = new self::Class::•() in let final void #t112 = self::Extension|set#field(new self::Class::•(), #t111) in #t111);
+  c = let final self::Class? #t113 = c in #t113.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t114 = let final self::Class #t115 = new self::Class::•() in let final void #t116 = self::Extension|set#field(new self::Class::•(), #t115) in #t115 in let final void #t117 = self::Extension|set#field(self::Extension|method(#t113), #t114) in #t114;
   let final self::Class? #t118 = c in #t118.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(self::Extension|method(#t118), self::Extension|method(new self::Class::•()));
   c = let final self::Class? #t119 = c in #t119.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t120 = self::Extension|method(new self::Class::•()) in let final void #t121 = self::Extension|set#field(self::Extension|method(#t119), #t120) in #t120;
   let final self::Class? #t122 = c in #t122.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(self::Extension|method(self::Extension|get#field(#t122)));
-  let final self::Class? #t123 = c in #t123.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(self::Extension|method(self::Extension|get#field(#t123)), new self::Class::•());
-  c = let final self::Class? #t124 = c in #t124.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t125 = new self::Class::•() in let final void #t126 = self::Extension|set#field(self::Extension|method(self::Extension|get#field(#t124)), #t125) in #t125;
+  let final self::Class? #t123 = c in #t123.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(self::Extension|method(self::Extension|get#field(#t123)), new self::Class::•());
+  c = let final self::Class? #t124 = c in #t124.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t125 = new self::Class::•() in let final void #t126 = self::Extension|set#field(self::Extension|method(self::Extension|get#field(#t124)), #t125) in #t125;
   let final self::Class? #t127 = c in #t127.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(self::Extension|method(self::Extension|get#field(#t127)));
   let final self::Class? #t128 = c in #t128.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t128, self::Extension|get#field(self::Extension|method(new self::Class::•())));
   c = let final self::Class? #t129 = c in #t129.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t130 = self::Extension|get#field(self::Extension|method(new self::Class::•())) in let final void #t131 = self::Extension|set#field(#t129, #t130) in #t130;
-  let final self::Class? #t132 = c in #t132.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(#t132, let final self::Class* #t133 = new self::Class::•() in let final void #t134 = self::Extension|set#field(self::Extension|method(new self::Class::•()), #t133) in #t133);
-  c = let final self::Class? #t135 = c in #t135.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t136 = let final self::Class* #t137 = new self::Class::•() in let final void #t138 = self::Extension|set#field(self::Extension|method(new self::Class::•()), #t137) in #t137 in let final void #t139 = self::Extension|set#field(#t135, #t136) in #t136;
+  let final self::Class? #t132 = c in #t132.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(#t132, let final self::Class #t133 = new self::Class::•() in let final void #t134 = self::Extension|set#field(self::Extension|method(new self::Class::•()), #t133) in #t133);
+  c = let final self::Class? #t135 = c in #t135.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t136 = let final self::Class #t137 = new self::Class::•() in let final void #t138 = self::Extension|set#field(self::Extension|method(new self::Class::•()), #t137) in #t137 in let final void #t139 = self::Extension|set#field(#t135, #t136) in #t136;
   let final self::Class? #t140 = c in #t140.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t140, self::Extension|method(self::Extension|method(new self::Class::•())));
   c = let final self::Class? #t141 = c in #t141.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t142 = self::Extension|method(self::Extension|method(new self::Class::•())) in let final void #t143 = self::Extension|set#field(#t141, #t142) in #t142;
   let final self::Class? #t144 = c in #t144.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(self::Extension|method(self::Extension|method(#t144)));
-  let final self::Class? #t145 = c in #t145.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(self::Extension|method(self::Extension|method(#t145)), new self::Class::•());
+  let final self::Class? #t145 = c in #t145.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(self::Extension|method(self::Extension|method(#t145)), new self::Class::•());
   let final self::Class? #t146 = c in #t146.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(self::Extension|method(self::Extension|method(#t146)));
 }
 static method indexAccess(self::Class? c) → void {
-  let final self::Class? #t147 = c in #t147.{core::Object::==}(null) ?{self::Class?} null : self::Extension|[](self::Extension|get#field(#t147), c);
-  let final self::Class? #t148 = c in #t148.{core::Object::==}(null) ?{self::Class*} null : self::Extension|[]=(self::Extension|get#field(#t148), c, new self::Class::•());
-  c = let final self::Class? #t149 = c in #t149.{core::Object::==}(null) ?{self::Class*} null : let final self::Class? #t150 = self::Extension|get#field(#t149) in let final self::Class? #t151 = c in let final self::Class* #t152 = new self::Class::•() in let final void #t153 = self::Extension|[]=(#t150, #t151, #t152) in #t152;
-  let final self::Class? #t154 = c in #t154.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(self::Extension|[](self::Extension|get#field(#t154), c));
-  let final self::Class? #t155 = c in #t155.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t156 = self::Extension|get#field(#t155) in let final self::Class? #t157 = c in self::Extension|[]=(#t156, #t157, self::Extension|+(self::Extension|[](#t156, #t157), 0));
-  c = let final self::Class? #t158 = c in #t158.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t159 = self::Extension|get#field(#t158) in let final self::Class? #t160 = c in let final self::Class? #t161 = self::Extension|+(self::Extension|[](#t159, #t160), 0) in let final void #t162 = self::Extension|[]=(#t159, #t160, #t161) in #t161;
-  let final self::Class? #t163 = c in #t163.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t164 = self::Extension|get#field(#t163) in let final self::Class? #t165 = c in self::Extension|[]=(#t164, #t165, self::Extension|+(self::Extension|[](#t164, #t165), 1));
-  c = let final self::Class? #t166 = c in #t166.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t167 = self::Extension|get#field(#t166) in let final self::Class? #t168 = c in let final self::Class? #t169 = self::Extension|[](#t167, #t168) in let final void #t170 = self::Extension|[]=(#t167, #t168, self::Extension|+(#t169, 1)) in #t169;
-  let final self::Class? #t171 = c in #t171.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t172 = self::Extension|get#field(#t171) in let final self::Class? #t173 = c in let final self::Class? #t174 = self::Extension|+(self::Extension|[](#t172, #t173), 1) in let final void #t175 = self::Extension|[]=(#t172, #t173, #t174) in #t174;
-  c = let final self::Class? #t176 = c in #t176.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t177 = self::Extension|get#field(#t176) in let final self::Class? #t178 = c in let final self::Class? #t179 = self::Extension|+(self::Extension|[](#t177, #t178), 1) in let final void #t180 = self::Extension|[]=(#t177, #t178, #t179) in #t179;
+  let final self::Class? #t147 = c in #t147.{core::Object::==}(null) ?{self::Class?} null : self::Extension|[](#t147, c);
+  let final self::Class? #t148 = c in #t148.{core::Object::==}(null) ?{void} null : self::Extension|[]=(#t148, c, new self::Class::•());
+  let final self::Class? #t149 = c in #t149.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(self::Extension|[](#t149, c));
+  let final self::Class? #t150 = c in #t150.{core::Object::==}(null) ?{self::Class?} null : self::Extension|[](self::Extension|get#field(#t150), c);
+  let final self::Class? #t151 = c in #t151.{core::Object::==}(null) ?{self::Class} null : self::Extension|[]=(self::Extension|get#field(#t151), c, new self::Class::•());
+  c = let final self::Class? #t152 = c in #t152.{core::Object::==}(null) ?{self::Class} null : let final self::Class? #t153 = self::Extension|get#field(#t152) in let final self::Class? #t154 = c in let final self::Class #t155 = new self::Class::•() in let final void #t156 = self::Extension|[]=(#t153, #t154, #t155) in #t155;
+  let final self::Class? #t157 = c in #t157.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(self::Extension|[](self::Extension|get#field(#t157), c));
+  let final self::Class? #t158 = c in #t158.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t159 = self::Extension|get#field(#t158) in let final self::Class? #t160 = c in self::Extension|[]=(#t159, #t160, self::Extension|+(self::Extension|[](#t159, #t160), 0));
+  c = let final self::Class? #t161 = c in #t161.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t162 = self::Extension|get#field(#t161) in let final self::Class? #t163 = c in let final self::Class? #t164 = self::Extension|+(self::Extension|[](#t162, #t163), 0) in let final void #t165 = self::Extension|[]=(#t162, #t163, #t164) in #t164;
+  let final self::Class? #t166 = c in #t166.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t167 = self::Extension|get#field(#t166) in let final self::Class? #t168 = c in self::Extension|[]=(#t167, #t168, self::Extension|+(self::Extension|[](#t167, #t168), 1));
+  c = let final self::Class? #t169 = c in #t169.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t170 = self::Extension|get#field(#t169) in let final self::Class? #t171 = c in let final self::Class? #t172 = self::Extension|[](#t170, #t171) in let final void #t173 = self::Extension|[]=(#t170, #t171, self::Extension|+(#t172, 1)) in #t172;
+  let final self::Class? #t174 = c in #t174.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t175 = self::Extension|get#field(#t174) in let final self::Class? #t176 = c in let final self::Class? #t177 = self::Extension|+(self::Extension|[](#t175, #t176), 1) in let final void #t178 = self::Extension|[]=(#t175, #t176, #t177) in #t177;
+  c = let final self::Class? #t179 = c in #t179.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t180 = self::Extension|get#field(#t179) in let final self::Class? #t181 = c in let final self::Class? #t182 = self::Extension|+(self::Extension|[](#t180, #t181), 1) in let final void #t183 = self::Extension|[]=(#t180, #t181, #t182) in #t182;
 }
 static method operatorAccess(self::Class? c) → void {
-  self::throws(() → self::Class? => self::Extension|+(let final self::Class? #t181 = c in #t181.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(#t181), 0));
-  self::throws(() → self::Class? => self::Extension|unary-(let final self::Class? #t182 = c in #t182.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(#t182)));
-  let final self::Class? #t183 = c in #t183.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t183, self::Extension|+(self::Extension|get#field(#t183), 0));
-  c = let final self::Class? #t184 = c in #t184.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t185 = self::Extension|+(self::Extension|get#field(#t184), 0) in let final void #t186 = self::Extension|set#field(#t184, #t185) in #t185;
-  let final self::Class? #t187 = c in #t187.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t188 = self::Extension|get#field(#t187) in self::Extension|set#field(#t188, self::Extension|+(self::Extension|get#field(#t188), 0));
-  c = let final self::Class? #t189 = c in #t189.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t190 = self::Extension|get#field(#t189) in let final self::Class? #t191 = self::Extension|+(self::Extension|get#field(#t190), 0) in let final void #t192 = self::Extension|set#field(#t190, #t191) in #t191;
-  let final self::Class? #t193 = c in #t193.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t193, self::Extension|+(self::Extension|get#field(#t193), 1));
-  c = let final self::Class? #t194 = c in #t194.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t195 = self::Extension|get#field(#t194) in let final self::Class? #t196 = let final self::Class? #t197 = self::Extension|+(#t195, 1) in let final void #t198 = self::Extension|set#field(#t194, #t197) in #t197 in #t195;
-  let final self::Class? #t199 = c in #t199.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t200 = self::Extension|+(self::Extension|get#field(#t199), 1) in let final void #t201 = self::Extension|set#field(#t199, #t200) in #t200;
-  c = let final self::Class? #t202 = c in #t202.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t203 = self::Extension|+(self::Extension|get#field(#t202), 1) in let final void #t204 = self::Extension|set#field(#t202, #t203) in #t203;
+  self::throws(() → self::Class? => self::Extension|+(let final self::Class? #t184 = c in #t184.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(#t184), 0));
+  self::throws(() → self::Class? => self::Extension|unary-(let final self::Class? #t185 = c in #t185.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(#t185)));
+  let final self::Class? #t186 = c in #t186.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t186, self::Extension|+(self::Extension|get#field(#t186), 0));
+  c = let final self::Class? #t187 = c in #t187.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t188 = self::Extension|+(self::Extension|get#field(#t187), 0) in let final void #t189 = self::Extension|set#field(#t187, #t188) in #t188;
+  let final self::Class? #t190 = c in #t190.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t191 = self::Extension|get#field(#t190) in self::Extension|set#field(#t191, self::Extension|+(self::Extension|get#field(#t191), 0));
+  c = let final self::Class? #t192 = c in #t192.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t193 = self::Extension|get#field(#t192) in let final self::Class? #t194 = self::Extension|+(self::Extension|get#field(#t193), 0) in let final void #t195 = self::Extension|set#field(#t193, #t194) in #t194;
+  let final self::Class? #t196 = c in #t196.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t196, self::Extension|+(self::Extension|get#field(#t196), 1));
+  c = let final self::Class? #t197 = c in #t197.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t198 = self::Extension|get#field(#t197) in let final self::Class? #t199 = let final self::Class? #t200 = self::Extension|+(#t198, 1) in let final void #t201 = self::Extension|set#field(#t197, #t200) in #t200 in #t198;
+  let final self::Class? #t202 = c in #t202.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t203 = self::Extension|+(self::Extension|get#field(#t202), 1) in let final void #t204 = self::Extension|set#field(#t202, #t203) in #t203;
+  c = let final self::Class? #t205 = c in #t205.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t206 = self::Extension|+(self::Extension|get#field(#t205), 1) in let final void #t207 = self::Extension|set#field(#t205, #t206) in #t206;
 }
 static method ifNull(self::Class? c) → void {
-  let final self::Class? #t205 = c in #t205.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(#t205).{core::Object::==}(null) ?{self::Class?} self::Extension|set#field(#t205, c) : null;
-  c = let final self::Class? #t206 = c in #t206.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t207 = self::Extension|get#field(#t206) in #t207.{core::Object::==}(null) ?{self::Class?} let final self::Class? #t208 = c in let final void #t209 = self::Extension|set#field(#t206, #t208) in #t208 : #t207;
-  let final self::Class? #t210 = c in #t210.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t211 = self::Extension|get#field(#t210) in let final self::Class? #t212 = c in self::Extension|[](#t211, #t212).{core::Object::==}(null) ?{self::Class?} self::Extension|[]=(#t211, #t212, c) : null;
+  let final self::Class? #t208 = c in #t208.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(#t208).{core::Object::==}(null) ?{self::Class?} self::Extension|set#field(#t208, c) : null;
+  c = let final self::Class? #t209 = c in #t209.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t210 = self::Extension|get#field(#t209) in #t210.{core::Object::==}(null) ?{self::Class?} let final self::Class? #t211 = c in let final void #t212 = self::Extension|set#field(#t209, #t211) in #t211 : #t210;
+  let final self::Class? #t213 = c in #t213.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t214 = self::Extension|get#field(#t213) in let final self::Class? #t215 = c in self::Extension|[](#t214, #t215).{core::Object::==}(null) ?{self::Class?} self::Extension|[]=(#t214, #t215, c) : null;
 }
 static method throws(() → void f) → void {
   try {
diff --git a/pkg/front_end/testcases/nnbd/null_shorting_extension.dart b/pkg/front_end/testcases/nnbd/null_shorting_extension.dart
index 25f6e4e..f7a2f33 100644
--- a/pkg/front_end/testcases/nnbd/null_shorting_extension.dart
+++ b/pkg/front_end/testcases/nnbd/null_shorting_extension.dart
@@ -103,10 +103,9 @@
 }
 
 void indexAccess(Class? c) {
-  // TODO(johnniwinther): Handle null aware index access.
-  //c?.[c];
-  //c?.[c] = new Class();
-  //c?.[c].method();
+  c?.[c];
+  c?.[c] = new Class();
+  c?.[c].method();
   c?.field[c];
   c?.field[c] = new Class();
   c = c?.field[c] = new Class();
diff --git a/pkg/front_end/testcases/nnbd/null_shorting_extension.dart.strong.expect b/pkg/front_end/testcases/nnbd/null_shorting_extension.dart.strong.expect
index ac7b6fb..e45d0bc 100644
--- a/pkg/front_end/testcases/nnbd/null_shorting_extension.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/null_shorting_extension.dart.strong.expect
@@ -44,98 +44,101 @@
 }
 static method propertyAccess(self::Class? c) → void {
   let final self::Class? #t1 = c in #t1.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(#t1);
-  let final self::Class? #t2 = c in #t2.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(#t2, new self::Class::•());
-  c = let final self::Class? #t3 = c in #t3.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t4 = new self::Class::•() in let final void #t5 = self::Extension|set#field(#t3, #t4) in #t4;
+  let final self::Class? #t2 = c in #t2.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(#t2, new self::Class::•());
+  c = let final self::Class? #t3 = c in #t3.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t4 = new self::Class::•() in let final void #t5 = self::Extension|set#field(#t3, #t4) in #t4;
   let final self::Class? #t6 = c in #t6.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(#t6);
   let final self::Class? #t7 = c in #t7.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(self::Extension|get#field(#t7));
-  let final self::Class? #t8 = c in #t8.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(self::Extension|get#field(#t8), new self::Class::•());
+  let final self::Class? #t8 = c in #t8.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(self::Extension|get#field(#t8), new self::Class::•());
   self::throws(() → self::Class? => self::Extension|get#field(let final self::Class? #t9 = c in #t9.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(#t9)));
-  self::throws(() → self::Class? => self::Extension|get#field(let final self::Class? #t10 = c in #t10.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t11 = new self::Class::•() in let final void #t12 = self::Extension|set#field(#t10, #t11) in #t11));
+  self::throws(() → self::Class? => self::Extension|get#field(let final self::Class? #t10 = c in #t10.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t11 = new self::Class::•() in let final void #t12 = self::Extension|set#field(#t10, #t11) in #t11));
   self::throws(() → self::Class? => self::Extension|get#field(let final self::Class? #t13 = c in #t13.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(#t13)));
-  c = let final self::Class? #t14 = c in #t14.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t15 = new self::Class::•() in let final void #t16 = self::Extension|set#field(self::Extension|get#field(#t14), #t15) in #t15;
+  c = let final self::Class? #t14 = c in #t14.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t15 = new self::Class::•() in let final void #t16 = self::Extension|set#field(self::Extension|get#field(#t14), #t15) in #t15;
   let final self::Class? #t17 = c in #t17.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(self::Extension|get#field(#t17));
   let final self::Class? #t18 = c in #t18.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t18, self::Extension|get#field(new self::Class::•()));
   c = let final self::Class? #t19 = c in #t19.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t20 = self::Extension|get#field(new self::Class::•()) in let final void #t21 = self::Extension|set#field(#t19, #t20) in #t20;
-  let final self::Class? #t22 = c in #t22.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(#t22, let final self::Class* #t23 = new self::Class::•() in let final void #t24 = self::Extension|set#field(new self::Class::•(), #t23) in #t23);
-  c = let final self::Class? #t25 = c in #t25.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t26 = let final self::Class* #t27 = new self::Class::•() in let final void #t28 = self::Extension|set#field(new self::Class::•(), #t27) in #t27 in let final void #t29 = self::Extension|set#field(#t25, #t26) in #t26;
+  let final self::Class? #t22 = c in #t22.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(#t22, let final self::Class #t23 = new self::Class::•() in let final void #t24 = self::Extension|set#field(new self::Class::•(), #t23) in #t23);
+  c = let final self::Class? #t25 = c in #t25.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t26 = let final self::Class #t27 = new self::Class::•() in let final void #t28 = self::Extension|set#field(new self::Class::•(), #t27) in #t27 in let final void #t29 = self::Extension|set#field(#t25, #t26) in #t26;
   let final self::Class? #t30 = c in #t30.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t30, self::Extension|method(new self::Class::•()));
   c = let final self::Class? #t31 = c in #t31.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t32 = self::Extension|method(new self::Class::•()) in let final void #t33 = self::Extension|set#field(#t31, #t32) in #t32;
   let final self::Class? #t34 = c in #t34.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(self::Extension|method(#t34));
-  let final self::Class? #t35 = c in #t35.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(self::Extension|method(#t35), new self::Class::•());
+  let final self::Class? #t35 = c in #t35.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(self::Extension|method(#t35), new self::Class::•());
   let final self::Class? #t36 = c in #t36.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(self::Extension|method(#t36));
   let final self::Class? #t37 = c in #t37.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(self::Extension|get#field(self::Extension|get#field(#t37)));
-  let final self::Class? #t38 = c in #t38.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(self::Extension|get#field(self::Extension|get#field(#t38)), new self::Class::•());
-  c = let final self::Class? #t39 = c in #t39.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t40 = new self::Class::•() in let final void #t41 = self::Extension|set#field(self::Extension|get#field(self::Extension|get#field(#t39)), #t40) in #t40;
+  let final self::Class? #t38 = c in #t38.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(self::Extension|get#field(self::Extension|get#field(#t38)), new self::Class::•());
+  c = let final self::Class? #t39 = c in #t39.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t40 = new self::Class::•() in let final void #t41 = self::Extension|set#field(self::Extension|get#field(self::Extension|get#field(#t39)), #t40) in #t40;
   let final self::Class? #t42 = c in #t42.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(self::Extension|get#field(self::Extension|get#field(#t42)));
   let final self::Class? #t43 = c in #t43.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t43, self::Extension|get#field(self::Extension|get#field(new self::Class::•())));
   c = let final self::Class? #t44 = c in #t44.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t45 = self::Extension|get#field(self::Extension|get#field(new self::Class::•())) in let final void #t46 = self::Extension|set#field(#t44, #t45) in #t45;
-  let final self::Class? #t47 = c in #t47.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(#t47, let final self::Class* #t48 = new self::Class::•() in let final void #t49 = self::Extension|set#field(self::Extension|get#field(new self::Class::•()), #t48) in #t48);
-  c = let final self::Class? #t50 = c in #t50.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t51 = let final self::Class* #t52 = new self::Class::•() in let final void #t53 = self::Extension|set#field(self::Extension|get#field(new self::Class::•()), #t52) in #t52 in let final void #t54 = self::Extension|set#field(#t50, #t51) in #t51;
+  let final self::Class? #t47 = c in #t47.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(#t47, let final self::Class #t48 = new self::Class::•() in let final void #t49 = self::Extension|set#field(self::Extension|get#field(new self::Class::•()), #t48) in #t48);
+  c = let final self::Class? #t50 = c in #t50.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t51 = let final self::Class #t52 = new self::Class::•() in let final void #t53 = self::Extension|set#field(self::Extension|get#field(new self::Class::•()), #t52) in #t52 in let final void #t54 = self::Extension|set#field(#t50, #t51) in #t51;
   let final self::Class? #t55 = c in #t55.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t55, self::Extension|method(self::Extension|get#field(new self::Class::•())));
   c = let final self::Class? #t56 = c in #t56.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t57 = self::Extension|method(self::Extension|get#field(new self::Class::•())) in let final void #t58 = self::Extension|set#field(#t56, #t57) in #t57;
   let final self::Class? #t59 = c in #t59.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(self::Extension|get#field(self::Extension|method(#t59)));
-  let final self::Class? #t60 = c in #t60.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(self::Extension|get#field(self::Extension|method(#t60)), new self::Class::•());
+  let final self::Class? #t60 = c in #t60.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(self::Extension|get#field(self::Extension|method(#t60)), new self::Class::•());
   let final self::Class? #t61 = c in #t61.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(self::Extension|get#field(self::Extension|method(#t61)));
   let final self::Class? #t62 = c in #t62.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(self::Extension|get#field(#t62), self::Extension|get#field(new self::Class::•()));
   c = let final self::Class? #t63 = c in #t63.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t64 = self::Extension|get#field(new self::Class::•()) in let final void #t65 = self::Extension|set#field(self::Extension|get#field(#t63), #t64) in #t64;
-  let final self::Class? #t66 = c in #t66.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(self::Extension|get#field(#t66), let final self::Class* #t67 = new self::Class::•() in let final void #t68 = self::Extension|set#field(new self::Class::•(), #t67) in #t67);
-  c = let final self::Class? #t69 = c in #t69.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t70 = let final self::Class* #t71 = new self::Class::•() in let final void #t72 = self::Extension|set#field(new self::Class::•(), #t71) in #t71 in let final void #t73 = self::Extension|set#field(self::Extension|get#field(#t69), #t70) in #t70;
+  let final self::Class? #t66 = c in #t66.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(self::Extension|get#field(#t66), let final self::Class #t67 = new self::Class::•() in let final void #t68 = self::Extension|set#field(new self::Class::•(), #t67) in #t67);
+  c = let final self::Class? #t69 = c in #t69.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t70 = let final self::Class #t71 = new self::Class::•() in let final void #t72 = self::Extension|set#field(new self::Class::•(), #t71) in #t71 in let final void #t73 = self::Extension|set#field(self::Extension|get#field(#t69), #t70) in #t70;
   let final self::Class? #t74 = c in #t74.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(self::Extension|get#field(#t74), self::Extension|method(new self::Class::•()));
   c = let final self::Class? #t75 = c in #t75.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t76 = self::Extension|method(new self::Class::•()) in let final void #t77 = self::Extension|set#field(self::Extension|get#field(#t75), #t76) in #t76;
   let final self::Class? #t78 = c in #t78.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t78, let final self::Class? #t79 = self::Extension|get#field(new self::Class::•()) in let final void #t80 = self::Extension|set#field(new self::Class::•(), #t79) in #t79);
   c = let final self::Class? #t81 = c in #t81.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t82 = let final self::Class? #t83 = self::Extension|get#field(new self::Class::•()) in let final void #t84 = self::Extension|set#field(new self::Class::•(), #t83) in #t83 in let final void #t85 = self::Extension|set#field(#t81, #t82) in #t82;
-  let final self::Class? #t86 = c in #t86.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(#t86, let final self::Class* #t87 = let final self::Class* #t88 = new self::Class::•() in let final void #t89 = self::Extension|set#field(new self::Class::•(), #t88) in #t88 in let final void #t90 = self::Extension|set#field(new self::Class::•(), #t87) in #t87);
-  c = let final self::Class? #t91 = c in #t91.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t92 = let final self::Class* #t93 = let final self::Class* #t94 = new self::Class::•() in let final void #t95 = self::Extension|set#field(new self::Class::•(), #t94) in #t94 in let final void #t96 = self::Extension|set#field(new self::Class::•(), #t93) in #t93 in let final void #t97 = self::Extension|set#field(#t91, #t92) in #t92;
+  let final self::Class? #t86 = c in #t86.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(#t86, let final self::Class #t87 = let final self::Class #t88 = new self::Class::•() in let final void #t89 = self::Extension|set#field(new self::Class::•(), #t88) in #t88 in let final void #t90 = self::Extension|set#field(new self::Class::•(), #t87) in #t87);
+  c = let final self::Class? #t91 = c in #t91.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t92 = let final self::Class #t93 = let final self::Class #t94 = new self::Class::•() in let final void #t95 = self::Extension|set#field(new self::Class::•(), #t94) in #t94 in let final void #t96 = self::Extension|set#field(new self::Class::•(), #t93) in #t93 in let final void #t97 = self::Extension|set#field(#t91, #t92) in #t92;
   let final self::Class? #t98 = c in #t98.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t98, let final self::Class? #t99 = self::Extension|method(new self::Class::•()) in let final void #t100 = self::Extension|set#field(new self::Class::•(), #t99) in #t99);
   c = let final self::Class? #t101 = c in #t101.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t102 = let final self::Class? #t103 = self::Extension|method(new self::Class::•()) in let final void #t104 = self::Extension|set#field(new self::Class::•(), #t103) in #t103 in let final void #t105 = self::Extension|set#field(#t101, #t102) in #t102;
   let final self::Class? #t106 = c in #t106.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(self::Extension|method(#t106), self::Extension|get#field(new self::Class::•()));
   c = let final self::Class? #t107 = c in #t107.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t108 = self::Extension|get#field(new self::Class::•()) in let final void #t109 = self::Extension|set#field(self::Extension|method(#t107), #t108) in #t108;
-  let final self::Class? #t110 = c in #t110.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(self::Extension|method(#t110), let final self::Class* #t111 = new self::Class::•() in let final void #t112 = self::Extension|set#field(new self::Class::•(), #t111) in #t111);
-  c = let final self::Class? #t113 = c in #t113.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t114 = let final self::Class* #t115 = new self::Class::•() in let final void #t116 = self::Extension|set#field(new self::Class::•(), #t115) in #t115 in let final void #t117 = self::Extension|set#field(self::Extension|method(#t113), #t114) in #t114;
+  let final self::Class? #t110 = c in #t110.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(self::Extension|method(#t110), let final self::Class #t111 = new self::Class::•() in let final void #t112 = self::Extension|set#field(new self::Class::•(), #t111) in #t111);
+  c = let final self::Class? #t113 = c in #t113.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t114 = let final self::Class #t115 = new self::Class::•() in let final void #t116 = self::Extension|set#field(new self::Class::•(), #t115) in #t115 in let final void #t117 = self::Extension|set#field(self::Extension|method(#t113), #t114) in #t114;
   let final self::Class? #t118 = c in #t118.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(self::Extension|method(#t118), self::Extension|method(new self::Class::•()));
   c = let final self::Class? #t119 = c in #t119.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t120 = self::Extension|method(new self::Class::•()) in let final void #t121 = self::Extension|set#field(self::Extension|method(#t119), #t120) in #t120;
   let final self::Class? #t122 = c in #t122.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(self::Extension|method(self::Extension|get#field(#t122)));
-  let final self::Class? #t123 = c in #t123.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(self::Extension|method(self::Extension|get#field(#t123)), new self::Class::•());
-  c = let final self::Class? #t124 = c in #t124.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t125 = new self::Class::•() in let final void #t126 = self::Extension|set#field(self::Extension|method(self::Extension|get#field(#t124)), #t125) in #t125;
+  let final self::Class? #t123 = c in #t123.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(self::Extension|method(self::Extension|get#field(#t123)), new self::Class::•());
+  c = let final self::Class? #t124 = c in #t124.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t125 = new self::Class::•() in let final void #t126 = self::Extension|set#field(self::Extension|method(self::Extension|get#field(#t124)), #t125) in #t125;
   let final self::Class? #t127 = c in #t127.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(self::Extension|method(self::Extension|get#field(#t127)));
   let final self::Class? #t128 = c in #t128.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t128, self::Extension|get#field(self::Extension|method(new self::Class::•())));
   c = let final self::Class? #t129 = c in #t129.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t130 = self::Extension|get#field(self::Extension|method(new self::Class::•())) in let final void #t131 = self::Extension|set#field(#t129, #t130) in #t130;
-  let final self::Class? #t132 = c in #t132.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(#t132, let final self::Class* #t133 = new self::Class::•() in let final void #t134 = self::Extension|set#field(self::Extension|method(new self::Class::•()), #t133) in #t133);
-  c = let final self::Class? #t135 = c in #t135.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t136 = let final self::Class* #t137 = new self::Class::•() in let final void #t138 = self::Extension|set#field(self::Extension|method(new self::Class::•()), #t137) in #t137 in let final void #t139 = self::Extension|set#field(#t135, #t136) in #t136;
+  let final self::Class? #t132 = c in #t132.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(#t132, let final self::Class #t133 = new self::Class::•() in let final void #t134 = self::Extension|set#field(self::Extension|method(new self::Class::•()), #t133) in #t133);
+  c = let final self::Class? #t135 = c in #t135.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t136 = let final self::Class #t137 = new self::Class::•() in let final void #t138 = self::Extension|set#field(self::Extension|method(new self::Class::•()), #t137) in #t137 in let final void #t139 = self::Extension|set#field(#t135, #t136) in #t136;
   let final self::Class? #t140 = c in #t140.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t140, self::Extension|method(self::Extension|method(new self::Class::•())));
   c = let final self::Class? #t141 = c in #t141.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t142 = self::Extension|method(self::Extension|method(new self::Class::•())) in let final void #t143 = self::Extension|set#field(#t141, #t142) in #t142;
   let final self::Class? #t144 = c in #t144.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(self::Extension|method(self::Extension|method(#t144)));
-  let final self::Class? #t145 = c in #t145.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(self::Extension|method(self::Extension|method(#t145)), new self::Class::•());
+  let final self::Class? #t145 = c in #t145.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(self::Extension|method(self::Extension|method(#t145)), new self::Class::•());
   let final self::Class? #t146 = c in #t146.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(self::Extension|method(self::Extension|method(#t146)));
 }
 static method indexAccess(self::Class? c) → void {
-  let final self::Class? #t147 = c in #t147.{core::Object::==}(null) ?{self::Class?} null : self::Extension|[](self::Extension|get#field(#t147), c);
-  let final self::Class? #t148 = c in #t148.{core::Object::==}(null) ?{self::Class*} null : self::Extension|[]=(self::Extension|get#field(#t148), c, new self::Class::•());
-  c = let final self::Class? #t149 = c in #t149.{core::Object::==}(null) ?{self::Class*} null : let final self::Class? #t150 = self::Extension|get#field(#t149) in let final self::Class? #t151 = c in let final self::Class* #t152 = new self::Class::•() in let final void #t153 = self::Extension|[]=(#t150, #t151, #t152) in #t152;
-  let final self::Class? #t154 = c in #t154.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(self::Extension|[](self::Extension|get#field(#t154), c));
-  let final self::Class? #t155 = c in #t155.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t156 = self::Extension|get#field(#t155) in let final self::Class? #t157 = c in self::Extension|[]=(#t156, #t157, self::Extension|+(self::Extension|[](#t156, #t157), 0));
-  c = let final self::Class? #t158 = c in #t158.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t159 = self::Extension|get#field(#t158) in let final self::Class? #t160 = c in let final self::Class? #t161 = self::Extension|+(self::Extension|[](#t159, #t160), 0) in let final void #t162 = self::Extension|[]=(#t159, #t160, #t161) in #t161;
-  let final self::Class? #t163 = c in #t163.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t164 = self::Extension|get#field(#t163) in let final self::Class? #t165 = c in self::Extension|[]=(#t164, #t165, self::Extension|+(self::Extension|[](#t164, #t165), 1));
-  c = let final self::Class? #t166 = c in #t166.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t167 = self::Extension|get#field(#t166) in let final self::Class? #t168 = c in let final self::Class? #t169 = self::Extension|[](#t167, #t168) in let final void #t170 = self::Extension|[]=(#t167, #t168, self::Extension|+(#t169, 1)) in #t169;
-  let final self::Class? #t171 = c in #t171.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t172 = self::Extension|get#field(#t171) in let final self::Class? #t173 = c in let final self::Class? #t174 = self::Extension|+(self::Extension|[](#t172, #t173), 1) in let final void #t175 = self::Extension|[]=(#t172, #t173, #t174) in #t174;
-  c = let final self::Class? #t176 = c in #t176.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t177 = self::Extension|get#field(#t176) in let final self::Class? #t178 = c in let final self::Class? #t179 = self::Extension|+(self::Extension|[](#t177, #t178), 1) in let final void #t180 = self::Extension|[]=(#t177, #t178, #t179) in #t179;
+  let final self::Class? #t147 = c in #t147.{core::Object::==}(null) ?{self::Class?} null : self::Extension|[](#t147, c);
+  let final self::Class? #t148 = c in #t148.{core::Object::==}(null) ?{self::Class} null : self::Extension|[]=(#t148, c, new self::Class::•());
+  let final self::Class? #t149 = c in #t149.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(self::Extension|[](#t149, c));
+  let final self::Class? #t150 = c in #t150.{core::Object::==}(null) ?{self::Class?} null : self::Extension|[](self::Extension|get#field(#t150), c);
+  let final self::Class? #t151 = c in #t151.{core::Object::==}(null) ?{self::Class} null : self::Extension|[]=(self::Extension|get#field(#t151), c, new self::Class::•());
+  c = let final self::Class? #t152 = c in #t152.{core::Object::==}(null) ?{self::Class} null : let final self::Class? #t153 = self::Extension|get#field(#t152) in let final self::Class? #t154 = c in let final self::Class #t155 = new self::Class::•() in let final void #t156 = self::Extension|[]=(#t153, #t154, #t155) in #t155;
+  let final self::Class? #t157 = c in #t157.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(self::Extension|[](self::Extension|get#field(#t157), c));
+  let final self::Class? #t158 = c in #t158.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t159 = self::Extension|get#field(#t158) in let final self::Class? #t160 = c in self::Extension|[]=(#t159, #t160, self::Extension|+(self::Extension|[](#t159, #t160), 0));
+  c = let final self::Class? #t161 = c in #t161.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t162 = self::Extension|get#field(#t161) in let final self::Class? #t163 = c in let final self::Class? #t164 = self::Extension|+(self::Extension|[](#t162, #t163), 0) in let final void #t165 = self::Extension|[]=(#t162, #t163, #t164) in #t164;
+  let final self::Class? #t166 = c in #t166.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t167 = self::Extension|get#field(#t166) in let final self::Class? #t168 = c in self::Extension|[]=(#t167, #t168, self::Extension|+(self::Extension|[](#t167, #t168), 1));
+  c = let final self::Class? #t169 = c in #t169.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t170 = self::Extension|get#field(#t169) in let final self::Class? #t171 = c in let final self::Class? #t172 = self::Extension|[](#t170, #t171) in let final void #t173 = self::Extension|[]=(#t170, #t171, self::Extension|+(#t172, 1)) in #t172;
+  let final self::Class? #t174 = c in #t174.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t175 = self::Extension|get#field(#t174) in let final self::Class? #t176 = c in let final self::Class? #t177 = self::Extension|+(self::Extension|[](#t175, #t176), 1) in let final void #t178 = self::Extension|[]=(#t175, #t176, #t177) in #t177;
+  c = let final self::Class? #t179 = c in #t179.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t180 = self::Extension|get#field(#t179) in let final self::Class? #t181 = c in let final self::Class? #t182 = self::Extension|+(self::Extension|[](#t180, #t181), 1) in let final void #t183 = self::Extension|[]=(#t180, #t181, #t182) in #t182;
 }
 static method operatorAccess(self::Class? c) → void {
-  self::throws(() → self::Class? => self::Extension|+(let final self::Class? #t181 = c in #t181.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(#t181), 0));
-  self::throws(() → self::Class? => self::Extension|unary-(let final self::Class? #t182 = c in #t182.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(#t182)));
-  let final self::Class? #t183 = c in #t183.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t183, self::Extension|+(self::Extension|get#field(#t183), 0));
-  c = let final self::Class? #t184 = c in #t184.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t185 = self::Extension|+(self::Extension|get#field(#t184), 0) in let final void #t186 = self::Extension|set#field(#t184, #t185) in #t185;
-  let final self::Class? #t187 = c in #t187.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t188 = self::Extension|get#field(#t187) in self::Extension|set#field(#t188, self::Extension|+(self::Extension|get#field(#t188), 0));
-  c = let final self::Class? #t189 = c in #t189.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t190 = self::Extension|get#field(#t189) in let final self::Class? #t191 = self::Extension|+(self::Extension|get#field(#t190), 0) in let final void #t192 = self::Extension|set#field(#t190, #t191) in #t191;
-  let final self::Class? #t193 = c in #t193.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t193, self::Extension|+(self::Extension|get#field(#t193), 1));
-  c = let final self::Class? #t194 = c in #t194.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t195 = self::Extension|get#field(#t194) in let final void #t196 = self::Extension|set#field(#t194, self::Extension|+(#t195, 1)) in #t195;
-  let final self::Class? #t197 = c in #t197.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t198 = self::Extension|+(self::Extension|get#field(#t197), 1) in let final void #t199 = self::Extension|set#field(#t197, #t198) in #t198;
-  c = let final self::Class? #t200 = c in #t200.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t201 = self::Extension|+(self::Extension|get#field(#t200), 1) in let final void #t202 = self::Extension|set#field(#t200, #t201) in #t201;
+  self::throws(() → self::Class? => self::Extension|+(let final self::Class? #t184 = c in #t184.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(#t184), 0));
+  self::throws(() → self::Class? => self::Extension|unary-(let final self::Class? #t185 = c in #t185.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(#t185)));
+  let final self::Class? #t186 = c in #t186.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t186, self::Extension|+(self::Extension|get#field(#t186), 0));
+  c = let final self::Class? #t187 = c in #t187.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t188 = self::Extension|+(self::Extension|get#field(#t187), 0) in let final void #t189 = self::Extension|set#field(#t187, #t188) in #t188;
+  let final self::Class? #t190 = c in #t190.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t191 = self::Extension|get#field(#t190) in self::Extension|set#field(#t191, self::Extension|+(self::Extension|get#field(#t191), 0));
+  c = let final self::Class? #t192 = c in #t192.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t193 = self::Extension|get#field(#t192) in let final self::Class? #t194 = self::Extension|+(self::Extension|get#field(#t193), 0) in let final void #t195 = self::Extension|set#field(#t193, #t194) in #t194;
+  let final self::Class? #t196 = c in #t196.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t196, self::Extension|+(self::Extension|get#field(#t196), 1));
+  c = let final self::Class? #t197 = c in #t197.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t198 = self::Extension|get#field(#t197) in let final void #t199 = self::Extension|set#field(#t197, self::Extension|+(#t198, 1)) in #t198;
+  let final self::Class? #t200 = c in #t200.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t201 = self::Extension|+(self::Extension|get#field(#t200), 1) in let final void #t202 = self::Extension|set#field(#t200, #t201) in #t201;
+  c = let final self::Class? #t203 = c in #t203.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t204 = self::Extension|+(self::Extension|get#field(#t203), 1) in let final void #t205 = self::Extension|set#field(#t203, #t204) in #t204;
 }
 static method ifNull(self::Class? c) → void {
-  let final self::Class? #t203 = c in #t203.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(#t203).{core::Object::==}(null) ?{self::Class?} self::Extension|set#field(#t203, c) : null;
-  c = let final self::Class? #t204 = c in #t204.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t205 = self::Extension|get#field(#t204) in #t205.{core::Object::==}(null) ?{self::Class?} let final self::Class? #t206 = c in let final void #t207 = self::Extension|set#field(#t204, #t206) in #t206 : #t205;
-  let final self::Class? #t208 = c in #t208.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t209 = self::Extension|get#field(#t208) in let final self::Class? #t210 = c in self::Extension|[](#t209, #t210).{core::Object::==}(null) ?{self::Class?} self::Extension|[]=(#t209, #t210, c) : null;
+  let final self::Class? #t206 = c in #t206.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(#t206).{core::Object::==}(null) ?{self::Class?} self::Extension|set#field(#t206, c) : null;
+  c = let final self::Class? #t207 = c in #t207.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t208 = self::Extension|get#field(#t207) in #t208.{core::Object::==}(null) ?{self::Class?} let final self::Class? #t209 = c in let final void #t210 = self::Extension|set#field(#t207, #t209) in #t209 : #t208;
+  let final self::Class? #t211 = c in #t211.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t212 = self::Extension|get#field(#t211) in let final self::Class? #t213 = c in self::Extension|[](#t212, #t213).{core::Object::==}(null) ?{self::Class?} self::Extension|[]=(#t212, #t213, c) : null;
 }
 static method throws(() → void f) → void {
   try {
diff --git a/pkg/front_end/testcases/nnbd/null_shorting_extension.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/null_shorting_extension.dart.strong.transformed.expect
index ac7b6fb..e45d0bc 100644
--- a/pkg/front_end/testcases/nnbd/null_shorting_extension.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/null_shorting_extension.dart.strong.transformed.expect
@@ -44,98 +44,101 @@
 }
 static method propertyAccess(self::Class? c) → void {
   let final self::Class? #t1 = c in #t1.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(#t1);
-  let final self::Class? #t2 = c in #t2.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(#t2, new self::Class::•());
-  c = let final self::Class? #t3 = c in #t3.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t4 = new self::Class::•() in let final void #t5 = self::Extension|set#field(#t3, #t4) in #t4;
+  let final self::Class? #t2 = c in #t2.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(#t2, new self::Class::•());
+  c = let final self::Class? #t3 = c in #t3.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t4 = new self::Class::•() in let final void #t5 = self::Extension|set#field(#t3, #t4) in #t4;
   let final self::Class? #t6 = c in #t6.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(#t6);
   let final self::Class? #t7 = c in #t7.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(self::Extension|get#field(#t7));
-  let final self::Class? #t8 = c in #t8.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(self::Extension|get#field(#t8), new self::Class::•());
+  let final self::Class? #t8 = c in #t8.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(self::Extension|get#field(#t8), new self::Class::•());
   self::throws(() → self::Class? => self::Extension|get#field(let final self::Class? #t9 = c in #t9.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(#t9)));
-  self::throws(() → self::Class? => self::Extension|get#field(let final self::Class? #t10 = c in #t10.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t11 = new self::Class::•() in let final void #t12 = self::Extension|set#field(#t10, #t11) in #t11));
+  self::throws(() → self::Class? => self::Extension|get#field(let final self::Class? #t10 = c in #t10.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t11 = new self::Class::•() in let final void #t12 = self::Extension|set#field(#t10, #t11) in #t11));
   self::throws(() → self::Class? => self::Extension|get#field(let final self::Class? #t13 = c in #t13.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(#t13)));
-  c = let final self::Class? #t14 = c in #t14.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t15 = new self::Class::•() in let final void #t16 = self::Extension|set#field(self::Extension|get#field(#t14), #t15) in #t15;
+  c = let final self::Class? #t14 = c in #t14.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t15 = new self::Class::•() in let final void #t16 = self::Extension|set#field(self::Extension|get#field(#t14), #t15) in #t15;
   let final self::Class? #t17 = c in #t17.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(self::Extension|get#field(#t17));
   let final self::Class? #t18 = c in #t18.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t18, self::Extension|get#field(new self::Class::•()));
   c = let final self::Class? #t19 = c in #t19.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t20 = self::Extension|get#field(new self::Class::•()) in let final void #t21 = self::Extension|set#field(#t19, #t20) in #t20;
-  let final self::Class? #t22 = c in #t22.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(#t22, let final self::Class* #t23 = new self::Class::•() in let final void #t24 = self::Extension|set#field(new self::Class::•(), #t23) in #t23);
-  c = let final self::Class? #t25 = c in #t25.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t26 = let final self::Class* #t27 = new self::Class::•() in let final void #t28 = self::Extension|set#field(new self::Class::•(), #t27) in #t27 in let final void #t29 = self::Extension|set#field(#t25, #t26) in #t26;
+  let final self::Class? #t22 = c in #t22.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(#t22, let final self::Class #t23 = new self::Class::•() in let final void #t24 = self::Extension|set#field(new self::Class::•(), #t23) in #t23);
+  c = let final self::Class? #t25 = c in #t25.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t26 = let final self::Class #t27 = new self::Class::•() in let final void #t28 = self::Extension|set#field(new self::Class::•(), #t27) in #t27 in let final void #t29 = self::Extension|set#field(#t25, #t26) in #t26;
   let final self::Class? #t30 = c in #t30.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t30, self::Extension|method(new self::Class::•()));
   c = let final self::Class? #t31 = c in #t31.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t32 = self::Extension|method(new self::Class::•()) in let final void #t33 = self::Extension|set#field(#t31, #t32) in #t32;
   let final self::Class? #t34 = c in #t34.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(self::Extension|method(#t34));
-  let final self::Class? #t35 = c in #t35.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(self::Extension|method(#t35), new self::Class::•());
+  let final self::Class? #t35 = c in #t35.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(self::Extension|method(#t35), new self::Class::•());
   let final self::Class? #t36 = c in #t36.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(self::Extension|method(#t36));
   let final self::Class? #t37 = c in #t37.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(self::Extension|get#field(self::Extension|get#field(#t37)));
-  let final self::Class? #t38 = c in #t38.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(self::Extension|get#field(self::Extension|get#field(#t38)), new self::Class::•());
-  c = let final self::Class? #t39 = c in #t39.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t40 = new self::Class::•() in let final void #t41 = self::Extension|set#field(self::Extension|get#field(self::Extension|get#field(#t39)), #t40) in #t40;
+  let final self::Class? #t38 = c in #t38.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(self::Extension|get#field(self::Extension|get#field(#t38)), new self::Class::•());
+  c = let final self::Class? #t39 = c in #t39.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t40 = new self::Class::•() in let final void #t41 = self::Extension|set#field(self::Extension|get#field(self::Extension|get#field(#t39)), #t40) in #t40;
   let final self::Class? #t42 = c in #t42.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(self::Extension|get#field(self::Extension|get#field(#t42)));
   let final self::Class? #t43 = c in #t43.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t43, self::Extension|get#field(self::Extension|get#field(new self::Class::•())));
   c = let final self::Class? #t44 = c in #t44.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t45 = self::Extension|get#field(self::Extension|get#field(new self::Class::•())) in let final void #t46 = self::Extension|set#field(#t44, #t45) in #t45;
-  let final self::Class? #t47 = c in #t47.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(#t47, let final self::Class* #t48 = new self::Class::•() in let final void #t49 = self::Extension|set#field(self::Extension|get#field(new self::Class::•()), #t48) in #t48);
-  c = let final self::Class? #t50 = c in #t50.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t51 = let final self::Class* #t52 = new self::Class::•() in let final void #t53 = self::Extension|set#field(self::Extension|get#field(new self::Class::•()), #t52) in #t52 in let final void #t54 = self::Extension|set#field(#t50, #t51) in #t51;
+  let final self::Class? #t47 = c in #t47.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(#t47, let final self::Class #t48 = new self::Class::•() in let final void #t49 = self::Extension|set#field(self::Extension|get#field(new self::Class::•()), #t48) in #t48);
+  c = let final self::Class? #t50 = c in #t50.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t51 = let final self::Class #t52 = new self::Class::•() in let final void #t53 = self::Extension|set#field(self::Extension|get#field(new self::Class::•()), #t52) in #t52 in let final void #t54 = self::Extension|set#field(#t50, #t51) in #t51;
   let final self::Class? #t55 = c in #t55.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t55, self::Extension|method(self::Extension|get#field(new self::Class::•())));
   c = let final self::Class? #t56 = c in #t56.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t57 = self::Extension|method(self::Extension|get#field(new self::Class::•())) in let final void #t58 = self::Extension|set#field(#t56, #t57) in #t57;
   let final self::Class? #t59 = c in #t59.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(self::Extension|get#field(self::Extension|method(#t59)));
-  let final self::Class? #t60 = c in #t60.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(self::Extension|get#field(self::Extension|method(#t60)), new self::Class::•());
+  let final self::Class? #t60 = c in #t60.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(self::Extension|get#field(self::Extension|method(#t60)), new self::Class::•());
   let final self::Class? #t61 = c in #t61.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(self::Extension|get#field(self::Extension|method(#t61)));
   let final self::Class? #t62 = c in #t62.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(self::Extension|get#field(#t62), self::Extension|get#field(new self::Class::•()));
   c = let final self::Class? #t63 = c in #t63.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t64 = self::Extension|get#field(new self::Class::•()) in let final void #t65 = self::Extension|set#field(self::Extension|get#field(#t63), #t64) in #t64;
-  let final self::Class? #t66 = c in #t66.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(self::Extension|get#field(#t66), let final self::Class* #t67 = new self::Class::•() in let final void #t68 = self::Extension|set#field(new self::Class::•(), #t67) in #t67);
-  c = let final self::Class? #t69 = c in #t69.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t70 = let final self::Class* #t71 = new self::Class::•() in let final void #t72 = self::Extension|set#field(new self::Class::•(), #t71) in #t71 in let final void #t73 = self::Extension|set#field(self::Extension|get#field(#t69), #t70) in #t70;
+  let final self::Class? #t66 = c in #t66.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(self::Extension|get#field(#t66), let final self::Class #t67 = new self::Class::•() in let final void #t68 = self::Extension|set#field(new self::Class::•(), #t67) in #t67);
+  c = let final self::Class? #t69 = c in #t69.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t70 = let final self::Class #t71 = new self::Class::•() in let final void #t72 = self::Extension|set#field(new self::Class::•(), #t71) in #t71 in let final void #t73 = self::Extension|set#field(self::Extension|get#field(#t69), #t70) in #t70;
   let final self::Class? #t74 = c in #t74.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(self::Extension|get#field(#t74), self::Extension|method(new self::Class::•()));
   c = let final self::Class? #t75 = c in #t75.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t76 = self::Extension|method(new self::Class::•()) in let final void #t77 = self::Extension|set#field(self::Extension|get#field(#t75), #t76) in #t76;
   let final self::Class? #t78 = c in #t78.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t78, let final self::Class? #t79 = self::Extension|get#field(new self::Class::•()) in let final void #t80 = self::Extension|set#field(new self::Class::•(), #t79) in #t79);
   c = let final self::Class? #t81 = c in #t81.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t82 = let final self::Class? #t83 = self::Extension|get#field(new self::Class::•()) in let final void #t84 = self::Extension|set#field(new self::Class::•(), #t83) in #t83 in let final void #t85 = self::Extension|set#field(#t81, #t82) in #t82;
-  let final self::Class? #t86 = c in #t86.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(#t86, let final self::Class* #t87 = let final self::Class* #t88 = new self::Class::•() in let final void #t89 = self::Extension|set#field(new self::Class::•(), #t88) in #t88 in let final void #t90 = self::Extension|set#field(new self::Class::•(), #t87) in #t87);
-  c = let final self::Class? #t91 = c in #t91.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t92 = let final self::Class* #t93 = let final self::Class* #t94 = new self::Class::•() in let final void #t95 = self::Extension|set#field(new self::Class::•(), #t94) in #t94 in let final void #t96 = self::Extension|set#field(new self::Class::•(), #t93) in #t93 in let final void #t97 = self::Extension|set#field(#t91, #t92) in #t92;
+  let final self::Class? #t86 = c in #t86.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(#t86, let final self::Class #t87 = let final self::Class #t88 = new self::Class::•() in let final void #t89 = self::Extension|set#field(new self::Class::•(), #t88) in #t88 in let final void #t90 = self::Extension|set#field(new self::Class::•(), #t87) in #t87);
+  c = let final self::Class? #t91 = c in #t91.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t92 = let final self::Class #t93 = let final self::Class #t94 = new self::Class::•() in let final void #t95 = self::Extension|set#field(new self::Class::•(), #t94) in #t94 in let final void #t96 = self::Extension|set#field(new self::Class::•(), #t93) in #t93 in let final void #t97 = self::Extension|set#field(#t91, #t92) in #t92;
   let final self::Class? #t98 = c in #t98.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t98, let final self::Class? #t99 = self::Extension|method(new self::Class::•()) in let final void #t100 = self::Extension|set#field(new self::Class::•(), #t99) in #t99);
   c = let final self::Class? #t101 = c in #t101.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t102 = let final self::Class? #t103 = self::Extension|method(new self::Class::•()) in let final void #t104 = self::Extension|set#field(new self::Class::•(), #t103) in #t103 in let final void #t105 = self::Extension|set#field(#t101, #t102) in #t102;
   let final self::Class? #t106 = c in #t106.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(self::Extension|method(#t106), self::Extension|get#field(new self::Class::•()));
   c = let final self::Class? #t107 = c in #t107.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t108 = self::Extension|get#field(new self::Class::•()) in let final void #t109 = self::Extension|set#field(self::Extension|method(#t107), #t108) in #t108;
-  let final self::Class? #t110 = c in #t110.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(self::Extension|method(#t110), let final self::Class* #t111 = new self::Class::•() in let final void #t112 = self::Extension|set#field(new self::Class::•(), #t111) in #t111);
-  c = let final self::Class? #t113 = c in #t113.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t114 = let final self::Class* #t115 = new self::Class::•() in let final void #t116 = self::Extension|set#field(new self::Class::•(), #t115) in #t115 in let final void #t117 = self::Extension|set#field(self::Extension|method(#t113), #t114) in #t114;
+  let final self::Class? #t110 = c in #t110.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(self::Extension|method(#t110), let final self::Class #t111 = new self::Class::•() in let final void #t112 = self::Extension|set#field(new self::Class::•(), #t111) in #t111);
+  c = let final self::Class? #t113 = c in #t113.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t114 = let final self::Class #t115 = new self::Class::•() in let final void #t116 = self::Extension|set#field(new self::Class::•(), #t115) in #t115 in let final void #t117 = self::Extension|set#field(self::Extension|method(#t113), #t114) in #t114;
   let final self::Class? #t118 = c in #t118.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(self::Extension|method(#t118), self::Extension|method(new self::Class::•()));
   c = let final self::Class? #t119 = c in #t119.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t120 = self::Extension|method(new self::Class::•()) in let final void #t121 = self::Extension|set#field(self::Extension|method(#t119), #t120) in #t120;
   let final self::Class? #t122 = c in #t122.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(self::Extension|method(self::Extension|get#field(#t122)));
-  let final self::Class? #t123 = c in #t123.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(self::Extension|method(self::Extension|get#field(#t123)), new self::Class::•());
-  c = let final self::Class? #t124 = c in #t124.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t125 = new self::Class::•() in let final void #t126 = self::Extension|set#field(self::Extension|method(self::Extension|get#field(#t124)), #t125) in #t125;
+  let final self::Class? #t123 = c in #t123.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(self::Extension|method(self::Extension|get#field(#t123)), new self::Class::•());
+  c = let final self::Class? #t124 = c in #t124.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t125 = new self::Class::•() in let final void #t126 = self::Extension|set#field(self::Extension|method(self::Extension|get#field(#t124)), #t125) in #t125;
   let final self::Class? #t127 = c in #t127.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(self::Extension|method(self::Extension|get#field(#t127)));
   let final self::Class? #t128 = c in #t128.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t128, self::Extension|get#field(self::Extension|method(new self::Class::•())));
   c = let final self::Class? #t129 = c in #t129.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t130 = self::Extension|get#field(self::Extension|method(new self::Class::•())) in let final void #t131 = self::Extension|set#field(#t129, #t130) in #t130;
-  let final self::Class? #t132 = c in #t132.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(#t132, let final self::Class* #t133 = new self::Class::•() in let final void #t134 = self::Extension|set#field(self::Extension|method(new self::Class::•()), #t133) in #t133);
-  c = let final self::Class? #t135 = c in #t135.{core::Object::==}(null) ?{self::Class*} null : let final self::Class* #t136 = let final self::Class* #t137 = new self::Class::•() in let final void #t138 = self::Extension|set#field(self::Extension|method(new self::Class::•()), #t137) in #t137 in let final void #t139 = self::Extension|set#field(#t135, #t136) in #t136;
+  let final self::Class? #t132 = c in #t132.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(#t132, let final self::Class #t133 = new self::Class::•() in let final void #t134 = self::Extension|set#field(self::Extension|method(new self::Class::•()), #t133) in #t133);
+  c = let final self::Class? #t135 = c in #t135.{core::Object::==}(null) ?{self::Class} null : let final self::Class #t136 = let final self::Class #t137 = new self::Class::•() in let final void #t138 = self::Extension|set#field(self::Extension|method(new self::Class::•()), #t137) in #t137 in let final void #t139 = self::Extension|set#field(#t135, #t136) in #t136;
   let final self::Class? #t140 = c in #t140.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t140, self::Extension|method(self::Extension|method(new self::Class::•())));
   c = let final self::Class? #t141 = c in #t141.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t142 = self::Extension|method(self::Extension|method(new self::Class::•())) in let final void #t143 = self::Extension|set#field(#t141, #t142) in #t142;
   let final self::Class? #t144 = c in #t144.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(self::Extension|method(self::Extension|method(#t144)));
-  let final self::Class? #t145 = c in #t145.{core::Object::==}(null) ?{self::Class*} null : self::Extension|set#field(self::Extension|method(self::Extension|method(#t145)), new self::Class::•());
+  let final self::Class? #t145 = c in #t145.{core::Object::==}(null) ?{self::Class} null : self::Extension|set#field(self::Extension|method(self::Extension|method(#t145)), new self::Class::•());
   let final self::Class? #t146 = c in #t146.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(self::Extension|method(self::Extension|method(#t146)));
 }
 static method indexAccess(self::Class? c) → void {
-  let final self::Class? #t147 = c in #t147.{core::Object::==}(null) ?{self::Class?} null : self::Extension|[](self::Extension|get#field(#t147), c);
-  let final self::Class? #t148 = c in #t148.{core::Object::==}(null) ?{self::Class*} null : self::Extension|[]=(self::Extension|get#field(#t148), c, new self::Class::•());
-  c = let final self::Class? #t149 = c in #t149.{core::Object::==}(null) ?{self::Class*} null : let final self::Class? #t150 = self::Extension|get#field(#t149) in let final self::Class? #t151 = c in let final self::Class* #t152 = new self::Class::•() in let final void #t153 = self::Extension|[]=(#t150, #t151, #t152) in #t152;
-  let final self::Class? #t154 = c in #t154.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(self::Extension|[](self::Extension|get#field(#t154), c));
-  let final self::Class? #t155 = c in #t155.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t156 = self::Extension|get#field(#t155) in let final self::Class? #t157 = c in self::Extension|[]=(#t156, #t157, self::Extension|+(self::Extension|[](#t156, #t157), 0));
-  c = let final self::Class? #t158 = c in #t158.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t159 = self::Extension|get#field(#t158) in let final self::Class? #t160 = c in let final self::Class? #t161 = self::Extension|+(self::Extension|[](#t159, #t160), 0) in let final void #t162 = self::Extension|[]=(#t159, #t160, #t161) in #t161;
-  let final self::Class? #t163 = c in #t163.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t164 = self::Extension|get#field(#t163) in let final self::Class? #t165 = c in self::Extension|[]=(#t164, #t165, self::Extension|+(self::Extension|[](#t164, #t165), 1));
-  c = let final self::Class? #t166 = c in #t166.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t167 = self::Extension|get#field(#t166) in let final self::Class? #t168 = c in let final self::Class? #t169 = self::Extension|[](#t167, #t168) in let final void #t170 = self::Extension|[]=(#t167, #t168, self::Extension|+(#t169, 1)) in #t169;
-  let final self::Class? #t171 = c in #t171.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t172 = self::Extension|get#field(#t171) in let final self::Class? #t173 = c in let final self::Class? #t174 = self::Extension|+(self::Extension|[](#t172, #t173), 1) in let final void #t175 = self::Extension|[]=(#t172, #t173, #t174) in #t174;
-  c = let final self::Class? #t176 = c in #t176.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t177 = self::Extension|get#field(#t176) in let final self::Class? #t178 = c in let final self::Class? #t179 = self::Extension|+(self::Extension|[](#t177, #t178), 1) in let final void #t180 = self::Extension|[]=(#t177, #t178, #t179) in #t179;
+  let final self::Class? #t147 = c in #t147.{core::Object::==}(null) ?{self::Class?} null : self::Extension|[](#t147, c);
+  let final self::Class? #t148 = c in #t148.{core::Object::==}(null) ?{self::Class} null : self::Extension|[]=(#t148, c, new self::Class::•());
+  let final self::Class? #t149 = c in #t149.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(self::Extension|[](#t149, c));
+  let final self::Class? #t150 = c in #t150.{core::Object::==}(null) ?{self::Class?} null : self::Extension|[](self::Extension|get#field(#t150), c);
+  let final self::Class? #t151 = c in #t151.{core::Object::==}(null) ?{self::Class} null : self::Extension|[]=(self::Extension|get#field(#t151), c, new self::Class::•());
+  c = let final self::Class? #t152 = c in #t152.{core::Object::==}(null) ?{self::Class} null : let final self::Class? #t153 = self::Extension|get#field(#t152) in let final self::Class? #t154 = c in let final self::Class #t155 = new self::Class::•() in let final void #t156 = self::Extension|[]=(#t153, #t154, #t155) in #t155;
+  let final self::Class? #t157 = c in #t157.{core::Object::==}(null) ?{self::Class?} null : self::Extension|method(self::Extension|[](self::Extension|get#field(#t157), c));
+  let final self::Class? #t158 = c in #t158.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t159 = self::Extension|get#field(#t158) in let final self::Class? #t160 = c in self::Extension|[]=(#t159, #t160, self::Extension|+(self::Extension|[](#t159, #t160), 0));
+  c = let final self::Class? #t161 = c in #t161.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t162 = self::Extension|get#field(#t161) in let final self::Class? #t163 = c in let final self::Class? #t164 = self::Extension|+(self::Extension|[](#t162, #t163), 0) in let final void #t165 = self::Extension|[]=(#t162, #t163, #t164) in #t164;
+  let final self::Class? #t166 = c in #t166.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t167 = self::Extension|get#field(#t166) in let final self::Class? #t168 = c in self::Extension|[]=(#t167, #t168, self::Extension|+(self::Extension|[](#t167, #t168), 1));
+  c = let final self::Class? #t169 = c in #t169.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t170 = self::Extension|get#field(#t169) in let final self::Class? #t171 = c in let final self::Class? #t172 = self::Extension|[](#t170, #t171) in let final void #t173 = self::Extension|[]=(#t170, #t171, self::Extension|+(#t172, 1)) in #t172;
+  let final self::Class? #t174 = c in #t174.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t175 = self::Extension|get#field(#t174) in let final self::Class? #t176 = c in let final self::Class? #t177 = self::Extension|+(self::Extension|[](#t175, #t176), 1) in let final void #t178 = self::Extension|[]=(#t175, #t176, #t177) in #t177;
+  c = let final self::Class? #t179 = c in #t179.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t180 = self::Extension|get#field(#t179) in let final self::Class? #t181 = c in let final self::Class? #t182 = self::Extension|+(self::Extension|[](#t180, #t181), 1) in let final void #t183 = self::Extension|[]=(#t180, #t181, #t182) in #t182;
 }
 static method operatorAccess(self::Class? c) → void {
-  self::throws(() → self::Class? => self::Extension|+(let final self::Class? #t181 = c in #t181.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(#t181), 0));
-  self::throws(() → self::Class? => self::Extension|unary-(let final self::Class? #t182 = c in #t182.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(#t182)));
-  let final self::Class? #t183 = c in #t183.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t183, self::Extension|+(self::Extension|get#field(#t183), 0));
-  c = let final self::Class? #t184 = c in #t184.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t185 = self::Extension|+(self::Extension|get#field(#t184), 0) in let final void #t186 = self::Extension|set#field(#t184, #t185) in #t185;
-  let final self::Class? #t187 = c in #t187.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t188 = self::Extension|get#field(#t187) in self::Extension|set#field(#t188, self::Extension|+(self::Extension|get#field(#t188), 0));
-  c = let final self::Class? #t189 = c in #t189.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t190 = self::Extension|get#field(#t189) in let final self::Class? #t191 = self::Extension|+(self::Extension|get#field(#t190), 0) in let final void #t192 = self::Extension|set#field(#t190, #t191) in #t191;
-  let final self::Class? #t193 = c in #t193.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t193, self::Extension|+(self::Extension|get#field(#t193), 1));
-  c = let final self::Class? #t194 = c in #t194.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t195 = self::Extension|get#field(#t194) in let final void #t196 = self::Extension|set#field(#t194, self::Extension|+(#t195, 1)) in #t195;
-  let final self::Class? #t197 = c in #t197.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t198 = self::Extension|+(self::Extension|get#field(#t197), 1) in let final void #t199 = self::Extension|set#field(#t197, #t198) in #t198;
-  c = let final self::Class? #t200 = c in #t200.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t201 = self::Extension|+(self::Extension|get#field(#t200), 1) in let final void #t202 = self::Extension|set#field(#t200, #t201) in #t201;
+  self::throws(() → self::Class? => self::Extension|+(let final self::Class? #t184 = c in #t184.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(#t184), 0));
+  self::throws(() → self::Class? => self::Extension|unary-(let final self::Class? #t185 = c in #t185.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(#t185)));
+  let final self::Class? #t186 = c in #t186.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t186, self::Extension|+(self::Extension|get#field(#t186), 0));
+  c = let final self::Class? #t187 = c in #t187.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t188 = self::Extension|+(self::Extension|get#field(#t187), 0) in let final void #t189 = self::Extension|set#field(#t187, #t188) in #t188;
+  let final self::Class? #t190 = c in #t190.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t191 = self::Extension|get#field(#t190) in self::Extension|set#field(#t191, self::Extension|+(self::Extension|get#field(#t191), 0));
+  c = let final self::Class? #t192 = c in #t192.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t193 = self::Extension|get#field(#t192) in let final self::Class? #t194 = self::Extension|+(self::Extension|get#field(#t193), 0) in let final void #t195 = self::Extension|set#field(#t193, #t194) in #t194;
+  let final self::Class? #t196 = c in #t196.{core::Object::==}(null) ?{self::Class?} null : self::Extension|set#field(#t196, self::Extension|+(self::Extension|get#field(#t196), 1));
+  c = let final self::Class? #t197 = c in #t197.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t198 = self::Extension|get#field(#t197) in let final void #t199 = self::Extension|set#field(#t197, self::Extension|+(#t198, 1)) in #t198;
+  let final self::Class? #t200 = c in #t200.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t201 = self::Extension|+(self::Extension|get#field(#t200), 1) in let final void #t202 = self::Extension|set#field(#t200, #t201) in #t201;
+  c = let final self::Class? #t203 = c in #t203.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t204 = self::Extension|+(self::Extension|get#field(#t203), 1) in let final void #t205 = self::Extension|set#field(#t203, #t204) in #t204;
 }
 static method ifNull(self::Class? c) → void {
-  let final self::Class? #t203 = c in #t203.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(#t203).{core::Object::==}(null) ?{self::Class?} self::Extension|set#field(#t203, c) : null;
-  c = let final self::Class? #t204 = c in #t204.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t205 = self::Extension|get#field(#t204) in #t205.{core::Object::==}(null) ?{self::Class?} let final self::Class? #t206 = c in let final void #t207 = self::Extension|set#field(#t204, #t206) in #t206 : #t205;
-  let final self::Class? #t208 = c in #t208.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t209 = self::Extension|get#field(#t208) in let final self::Class? #t210 = c in self::Extension|[](#t209, #t210).{core::Object::==}(null) ?{self::Class?} self::Extension|[]=(#t209, #t210, c) : null;
+  let final self::Class? #t206 = c in #t206.{core::Object::==}(null) ?{self::Class?} null : self::Extension|get#field(#t206).{core::Object::==}(null) ?{self::Class?} self::Extension|set#field(#t206, c) : null;
+  c = let final self::Class? #t207 = c in #t207.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t208 = self::Extension|get#field(#t207) in #t208.{core::Object::==}(null) ?{self::Class?} let final self::Class? #t209 = c in let final void #t210 = self::Extension|set#field(#t207, #t209) in #t209 : #t208;
+  let final self::Class? #t211 = c in #t211.{core::Object::==}(null) ?{self::Class?} null : let final self::Class? #t212 = self::Extension|get#field(#t211) in let final self::Class? #t213 = c in self::Extension|[](#t212, #t213).{core::Object::==}(null) ?{self::Class?} self::Extension|[]=(#t212, #t213, c) : null;
 }
 static method throws(() → void f) → void {
   try {
diff --git a/pkg/front_end/testcases/nnbd/null_shorting_index.dart b/pkg/front_end/testcases/nnbd/null_shorting_index.dart
new file mode 100644
index 0000000..ce4173d
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/null_shorting_index.dart
@@ -0,0 +1,59 @@
+// Copyright (c) 2019, 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 Class1 {
+  int operator [](int index) => index;
+  void operator []=(int index, int value) {}
+}
+
+class Class2 {
+  int field;
+}
+
+extension Extension on Class2 {
+  int operator [](int index) => field;
+  void operator []=(int index, int value) {
+    field = value;
+  }
+}
+
+main() {
+  Class1? c1;
+  c1?.[0];
+  c1?.[0] = 1;
+  c1?.[0] = 1 + c1[0];
+  c1?.[0] += 1;
+  c1?.[0] += 1 + c1[0];
+  // TODO(johnniwinther): ++ should probably not be null-shorted, awaiting spec
+  //  update.
+  ++c1?.[0];
+  c1?.[0]++;
+  c1?.[0] ??= 1;
+  c1?.[0] ??= 1 + c1[1];
+
+  Class2? c2;
+  c2?.[0];
+  c2?.[0] = 1;
+  c2?.[0] = 1 + c2[0];
+  c2?.[0] += 1;
+  c2?.[0] += 1 + c2[0];
+  // TODO(johnniwinther): ++ should probably not be null-shorted, awaiting spec
+  //  update.
+  ++c2?.[0];
+  c2?.[0]++;
+  c2?.[0] ??= 1;
+  c2?.[0] ??= 1 + c2[1];
+
+  Extension(c2)?.[0];
+  Extension(c2)?.[0] = 1;
+  Extension(c2)?.[0] = 1 + Extension(c2)[0];
+  Extension(c2)?.[0] += 1;
+  Extension(c2)?.[0] += 1 + Extension(c2)[0];
+  // TODO(johnniwinther): ++ should probably not be null-shorted, awaiting spec
+  //  update.
+  ++Extension(c2)?.[0];
+  Extension(c2)?.[0]++;
+  Extension(c2)?.[0] ??= 1;
+  Extension(c2)?.[0] ??= 1 + Extension(c2)[1];
+}
diff --git a/pkg/front_end/testcases/nnbd/null_shorting_index.dart.outline.expect b/pkg/front_end/testcases/nnbd/null_shorting_index.dart.outline.expect
new file mode 100644
index 0000000..f96ff24
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/null_shorting_index.dart.outline.expect
@@ -0,0 +1,27 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  synthetic constructor •() → self::Class1*
+    ;
+  operator [](core::int index) → core::int
+    ;
+  operator []=(core::int index, core::int value) → void
+    ;
+}
+class Class2 extends core::Object {
+  field core::int field;
+  synthetic constructor •() → self::Class2*
+    ;
+}
+extension Extension on self::Class2 {
+  operator [] = self::Extension|[];
+  operator []= = self::Extension|[]=;
+}
+static method Extension|[](final self::Class2 #this, core::int index) → core::int
+  ;
+static method Extension|[]=(final self::Class2 #this, core::int index, core::int value) → void
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/nnbd/null_shorting_index.dart.strong.expect b/pkg/front_end/testcases/nnbd/null_shorting_index.dart.strong.expect
new file mode 100644
index 0000000..ebb3975
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/null_shorting_index.dart.strong.expect
@@ -0,0 +1,58 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  synthetic constructor •() → self::Class1*
+    : super core::Object::•()
+    ;
+  operator [](core::int index) → core::int
+    return index;
+  operator []=(core::int index, core::int value) → void {}
+}
+class Class2 extends core::Object {
+  field core::int field = null;
+  synthetic constructor •() → self::Class2*
+    : super core::Object::•()
+    ;
+}
+extension Extension on self::Class2 {
+  operator [] = self::Extension|[];
+  operator []= = self::Extension|[]=;
+}
+static method Extension|[](final self::Class2 #this, core::int index) → core::int
+  return #this.{self::Class2::field};
+static method Extension|[]=(final self::Class2 #this, core::int index, core::int value) → void {
+  #this.{self::Class2::field} = value;
+}
+static method main() → dynamic {
+  self::Class1? c1;
+  let final self::Class1? #t1 = c1 in #t1.{core::Object::==}(null) ?{core::int} null : #t1.{self::Class1::[]}(0);
+  let final self::Class1? #t2 = c1 in #t2.{core::Object::==}(null) ?{core::int} null : #t2.{self::Class1::[]=}(0, 1);
+  let final self::Class1? #t3 = c1 in #t3.{core::Object::==}(null) ?{core::int} null : #t3.{self::Class1::[]=}(0, 1.{core::num::+}(c1.{self::Class1::[]}(0)));
+  let final self::Class1? #t4 = c1 in #t4.{core::Object::==}(null) ?{core::int} null : let final core::int #t5 = 0 in #t4.{self::Class1::[]=}(#t5, #t4.{self::Class1::[]}(#t5).{core::num::+}(1));
+  let final self::Class1? #t6 = c1 in #t6.{core::Object::==}(null) ?{core::int} null : let final core::int #t7 = 0 in #t6.{self::Class1::[]=}(#t7, #t6.{self::Class1::[]}(#t7).{core::num::+}(1.{core::num::+}(c1.{self::Class1::[]}(0))));
+  let final self::Class1? #t8 = c1 in #t8.{core::Object::==}(null) ?{core::int} null : let final core::int #t9 = 0 in let final core::int #t10 = #t8.{self::Class1::[]}(#t9).{core::num::+}(1) in let final void #t11 = #t8.{self::Class1::[]=}(#t9, #t10) in #t10;
+  let final self::Class1? #t12 = c1 in #t12.{core::Object::==}(null) ?{core::int} null : let final core::int #t13 = 0 in #t12.{self::Class1::[]=}(#t13, #t12.{self::Class1::[]}(#t13).{core::num::+}(1));
+  let final self::Class1? #t14 = c1 in #t14.{core::Object::==}(null) ?{core::int} null : let final core::int #t15 = 0 in #t14.{self::Class1::[]}(#t15).{core::num::==}(null) ?{core::int} #t14.{self::Class1::[]=}(#t15, 1) : null;
+  let final self::Class1? #t16 = c1 in #t16.{core::Object::==}(null) ?{core::int} null : let final core::int #t17 = 0 in #t16.{self::Class1::[]}(#t17).{core::num::==}(null) ?{core::int} #t16.{self::Class1::[]=}(#t17, 1.{core::num::+}(c1.{self::Class1::[]}(1))) : null;
+  self::Class2? c2;
+  let final self::Class2? #t18 = c2 in #t18.{core::Object::==}(null) ?{core::int} null : self::Extension|[](#t18, 0);
+  let final self::Class2? #t19 = c2 in #t19.{core::Object::==}(null) ?{core::int} null : self::Extension|[]=(#t19, 0, 1);
+  let final self::Class2? #t20 = c2 in #t20.{core::Object::==}(null) ?{core::int} null : self::Extension|[]=(#t20, 0, 1.{core::num::+}(self::Extension|[](c2, 0)));
+  let final self::Class2? #t21 = c2 in #t21.{core::Object::==}(null) ?{core::int} null : let final core::int #t22 = 0 in self::Extension|[]=(#t21, #t22, self::Extension|[](#t21, #t22).{core::num::+}(1));
+  let final self::Class2? #t23 = c2 in #t23.{core::Object::==}(null) ?{core::int} null : let final core::int #t24 = 0 in self::Extension|[]=(#t23, #t24, self::Extension|[](#t23, #t24).{core::num::+}(1.{core::num::+}(self::Extension|[](c2, 0))));
+  let final self::Class2? #t25 = c2 in #t25.{core::Object::==}(null) ?{core::int} null : let final core::int #t26 = 0 in let final core::int #t27 = self::Extension|[](#t25, #t26).{core::num::+}(1) in let final void #t28 = self::Extension|[]=(#t25, #t26, #t27) in #t27;
+  let final self::Class2? #t29 = c2 in #t29.{core::Object::==}(null) ?{core::int} null : let final core::int #t30 = 0 in self::Extension|[]=(#t29, #t30, self::Extension|[](#t29, #t30).{core::num::+}(1));
+  let final self::Class2? #t31 = c2 in #t31.{core::Object::==}(null) ?{core::int} null : let final core::int #t32 = 0 in self::Extension|[](#t31, #t32).{core::num::==}(null) ?{core::int} self::Extension|[]=(#t31, #t32, 1) : null;
+  let final self::Class2? #t33 = c2 in #t33.{core::Object::==}(null) ?{core::int} null : let final core::int #t34 = 0 in self::Extension|[](#t33, #t34).{core::num::==}(null) ?{core::int} self::Extension|[]=(#t33, #t34, 1.{core::num::+}(self::Extension|[](c2, 1))) : null;
+  let final self::Class2? #t35 = c2 in #t35.{core::Object::==}(null) ?{core::int} null : self::Extension|[](#t35, 0);
+  let final self::Class2? #t36 = c2 in #t36.{core::Object::==}(null) ?{void} null : self::Extension|[]=(#t36, 0, 1);
+  let final self::Class2? #t37 = c2 in #t37.{core::Object::==}(null) ?{void} null : self::Extension|[]=(#t37, 0, 1.{core::num::+}(self::Extension|[](c2, 0)));
+  let final self::Class2? #t38 = c2 in #t38.{core::Object::==}(null) ?{core::int} null : let final core::int #t39 = 0 in self::Extension|[]=(#t38, #t39, self::Extension|[](#t38, #t39).{core::num::+}(1));
+  let final self::Class2? #t40 = c2 in #t40.{core::Object::==}(null) ?{core::int} null : let final core::int #t41 = 0 in self::Extension|[]=(#t40, #t41, self::Extension|[](#t40, #t41).{core::num::+}(1.{core::num::+}(self::Extension|[](c2, 0))));
+  let final self::Class2? #t42 = c2 in #t42.{core::Object::==}(null) ?{core::int} null : let final core::int #t43 = 0 in let final core::int #t44 = self::Extension|[](#t42, #t43).{core::num::+}(1) in let final void #t45 = self::Extension|[]=(#t42, #t43, #t44) in #t44;
+  let final self::Class2? #t46 = c2 in #t46.{core::Object::==}(null) ?{core::int} null : let final core::int #t47 = 0 in self::Extension|[]=(#t46, #t47, self::Extension|[](#t46, #t47).{core::num::+}(1));
+  let final self::Class2? #t48 = c2 in #t48.{core::Object::==}(null) ?{core::int} null : let final core::int #t49 = 0 in self::Extension|[](#t48, #t49).{core::num::==}(null) ?{core::int} self::Extension|[]=(#t48, #t49, 1) : null;
+  let final self::Class2? #t50 = c2 in #t50.{core::Object::==}(null) ?{core::int} null : let final core::int #t51 = 0 in self::Extension|[](#t50, #t51).{core::num::==}(null) ?{core::int} self::Extension|[]=(#t50, #t51, 1.{core::num::+}(self::Extension|[](c2, 1))) : null;
+}
diff --git a/pkg/front_end/testcases/nnbd/null_shorting_index.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/null_shorting_index.dart.strong.transformed.expect
new file mode 100644
index 0000000..ebb3975
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/null_shorting_index.dart.strong.transformed.expect
@@ -0,0 +1,58 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class1 extends core::Object {
+  synthetic constructor •() → self::Class1*
+    : super core::Object::•()
+    ;
+  operator [](core::int index) → core::int
+    return index;
+  operator []=(core::int index, core::int value) → void {}
+}
+class Class2 extends core::Object {
+  field core::int field = null;
+  synthetic constructor •() → self::Class2*
+    : super core::Object::•()
+    ;
+}
+extension Extension on self::Class2 {
+  operator [] = self::Extension|[];
+  operator []= = self::Extension|[]=;
+}
+static method Extension|[](final self::Class2 #this, core::int index) → core::int
+  return #this.{self::Class2::field};
+static method Extension|[]=(final self::Class2 #this, core::int index, core::int value) → void {
+  #this.{self::Class2::field} = value;
+}
+static method main() → dynamic {
+  self::Class1? c1;
+  let final self::Class1? #t1 = c1 in #t1.{core::Object::==}(null) ?{core::int} null : #t1.{self::Class1::[]}(0);
+  let final self::Class1? #t2 = c1 in #t2.{core::Object::==}(null) ?{core::int} null : #t2.{self::Class1::[]=}(0, 1);
+  let final self::Class1? #t3 = c1 in #t3.{core::Object::==}(null) ?{core::int} null : #t3.{self::Class1::[]=}(0, 1.{core::num::+}(c1.{self::Class1::[]}(0)));
+  let final self::Class1? #t4 = c1 in #t4.{core::Object::==}(null) ?{core::int} null : let final core::int #t5 = 0 in #t4.{self::Class1::[]=}(#t5, #t4.{self::Class1::[]}(#t5).{core::num::+}(1));
+  let final self::Class1? #t6 = c1 in #t6.{core::Object::==}(null) ?{core::int} null : let final core::int #t7 = 0 in #t6.{self::Class1::[]=}(#t7, #t6.{self::Class1::[]}(#t7).{core::num::+}(1.{core::num::+}(c1.{self::Class1::[]}(0))));
+  let final self::Class1? #t8 = c1 in #t8.{core::Object::==}(null) ?{core::int} null : let final core::int #t9 = 0 in let final core::int #t10 = #t8.{self::Class1::[]}(#t9).{core::num::+}(1) in let final void #t11 = #t8.{self::Class1::[]=}(#t9, #t10) in #t10;
+  let final self::Class1? #t12 = c1 in #t12.{core::Object::==}(null) ?{core::int} null : let final core::int #t13 = 0 in #t12.{self::Class1::[]=}(#t13, #t12.{self::Class1::[]}(#t13).{core::num::+}(1));
+  let final self::Class1? #t14 = c1 in #t14.{core::Object::==}(null) ?{core::int} null : let final core::int #t15 = 0 in #t14.{self::Class1::[]}(#t15).{core::num::==}(null) ?{core::int} #t14.{self::Class1::[]=}(#t15, 1) : null;
+  let final self::Class1? #t16 = c1 in #t16.{core::Object::==}(null) ?{core::int} null : let final core::int #t17 = 0 in #t16.{self::Class1::[]}(#t17).{core::num::==}(null) ?{core::int} #t16.{self::Class1::[]=}(#t17, 1.{core::num::+}(c1.{self::Class1::[]}(1))) : null;
+  self::Class2? c2;
+  let final self::Class2? #t18 = c2 in #t18.{core::Object::==}(null) ?{core::int} null : self::Extension|[](#t18, 0);
+  let final self::Class2? #t19 = c2 in #t19.{core::Object::==}(null) ?{core::int} null : self::Extension|[]=(#t19, 0, 1);
+  let final self::Class2? #t20 = c2 in #t20.{core::Object::==}(null) ?{core::int} null : self::Extension|[]=(#t20, 0, 1.{core::num::+}(self::Extension|[](c2, 0)));
+  let final self::Class2? #t21 = c2 in #t21.{core::Object::==}(null) ?{core::int} null : let final core::int #t22 = 0 in self::Extension|[]=(#t21, #t22, self::Extension|[](#t21, #t22).{core::num::+}(1));
+  let final self::Class2? #t23 = c2 in #t23.{core::Object::==}(null) ?{core::int} null : let final core::int #t24 = 0 in self::Extension|[]=(#t23, #t24, self::Extension|[](#t23, #t24).{core::num::+}(1.{core::num::+}(self::Extension|[](c2, 0))));
+  let final self::Class2? #t25 = c2 in #t25.{core::Object::==}(null) ?{core::int} null : let final core::int #t26 = 0 in let final core::int #t27 = self::Extension|[](#t25, #t26).{core::num::+}(1) in let final void #t28 = self::Extension|[]=(#t25, #t26, #t27) in #t27;
+  let final self::Class2? #t29 = c2 in #t29.{core::Object::==}(null) ?{core::int} null : let final core::int #t30 = 0 in self::Extension|[]=(#t29, #t30, self::Extension|[](#t29, #t30).{core::num::+}(1));
+  let final self::Class2? #t31 = c2 in #t31.{core::Object::==}(null) ?{core::int} null : let final core::int #t32 = 0 in self::Extension|[](#t31, #t32).{core::num::==}(null) ?{core::int} self::Extension|[]=(#t31, #t32, 1) : null;
+  let final self::Class2? #t33 = c2 in #t33.{core::Object::==}(null) ?{core::int} null : let final core::int #t34 = 0 in self::Extension|[](#t33, #t34).{core::num::==}(null) ?{core::int} self::Extension|[]=(#t33, #t34, 1.{core::num::+}(self::Extension|[](c2, 1))) : null;
+  let final self::Class2? #t35 = c2 in #t35.{core::Object::==}(null) ?{core::int} null : self::Extension|[](#t35, 0);
+  let final self::Class2? #t36 = c2 in #t36.{core::Object::==}(null) ?{void} null : self::Extension|[]=(#t36, 0, 1);
+  let final self::Class2? #t37 = c2 in #t37.{core::Object::==}(null) ?{void} null : self::Extension|[]=(#t37, 0, 1.{core::num::+}(self::Extension|[](c2, 0)));
+  let final self::Class2? #t38 = c2 in #t38.{core::Object::==}(null) ?{core::int} null : let final core::int #t39 = 0 in self::Extension|[]=(#t38, #t39, self::Extension|[](#t38, #t39).{core::num::+}(1));
+  let final self::Class2? #t40 = c2 in #t40.{core::Object::==}(null) ?{core::int} null : let final core::int #t41 = 0 in self::Extension|[]=(#t40, #t41, self::Extension|[](#t40, #t41).{core::num::+}(1.{core::num::+}(self::Extension|[](c2, 0))));
+  let final self::Class2? #t42 = c2 in #t42.{core::Object::==}(null) ?{core::int} null : let final core::int #t43 = 0 in let final core::int #t44 = self::Extension|[](#t42, #t43).{core::num::+}(1) in let final void #t45 = self::Extension|[]=(#t42, #t43, #t44) in #t44;
+  let final self::Class2? #t46 = c2 in #t46.{core::Object::==}(null) ?{core::int} null : let final core::int #t47 = 0 in self::Extension|[]=(#t46, #t47, self::Extension|[](#t46, #t47).{core::num::+}(1));
+  let final self::Class2? #t48 = c2 in #t48.{core::Object::==}(null) ?{core::int} null : let final core::int #t49 = 0 in self::Extension|[](#t48, #t49).{core::num::==}(null) ?{core::int} self::Extension|[]=(#t48, #t49, 1) : null;
+  let final self::Class2? #t50 = c2 in #t50.{core::Object::==}(null) ?{core::int} null : let final core::int #t51 = 0 in self::Extension|[](#t50, #t51).{core::num::==}(null) ?{core::int} self::Extension|[]=(#t50, #t51, 1.{core::num::+}(self::Extension|[](c2, 1))) : null;
+}
diff --git a/pkg/front_end/testcases/nnbd/nullable_null.dart.outline.expect b/pkg/front_end/testcases/nnbd/nullable_null.dart.outline.expect
index f782516..9c9d87a 100644
--- a/pkg/front_end/testcases/nnbd/nullable_null.dart.outline.expect
+++ b/pkg/front_end/testcases/nnbd/nullable_null.dart.outline.expect
@@ -3,7 +3,7 @@
 import "dart:core" as core;
 
 class A<X extends core::Object? = dynamic> extends core::Object {
-  synthetic constructor •() → self::A<self::A::X*>*
+  synthetic constructor •() → self::A<self::A::X%>*
     ;
 }
 class B extends self::A<core::Null?> {
diff --git a/pkg/front_end/testcases/nnbd/nullable_null.dart.strong.expect b/pkg/front_end/testcases/nnbd/nullable_null.dart.strong.expect
index 8d9c779..263e44a 100644
--- a/pkg/front_end/testcases/nnbd/nullable_null.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/nullable_null.dart.strong.expect
@@ -3,7 +3,7 @@
 import "dart:core" as core;
 
 class A<X extends core::Object? = dynamic> extends core::Object {
-  synthetic constructor •() → self::A<self::A::X*>*
+  synthetic constructor •() → self::A<self::A::X%>*
     : super core::Object::•()
     ;
 }
@@ -20,10 +20,10 @@
     return n;
 }
 static method foo() → dynamic {
-  return <core::List<self::A<core::Null?>>*>[<core::Null?>[], <self::A<core::Null?>>[]];
+  return <core::List<self::A<core::Null?>>>[<core::Null?>[], <self::A<core::Null?>>[]];
 }
 static method bar() → dynamic {
-  return <core::List<self::A<core::Null?>>*>[#C1, #C2];
+  return <core::List<self::A<core::Null?>>>[#C1, #C2];
 }
 static method main() → dynamic {}
 
diff --git a/pkg/front_end/testcases/nnbd/nullable_null.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/nullable_null.dart.strong.transformed.expect
index 8d9c779..263e44a 100644
--- a/pkg/front_end/testcases/nnbd/nullable_null.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/nullable_null.dart.strong.transformed.expect
@@ -3,7 +3,7 @@
 import "dart:core" as core;
 
 class A<X extends core::Object? = dynamic> extends core::Object {
-  synthetic constructor •() → self::A<self::A::X*>*
+  synthetic constructor •() → self::A<self::A::X%>*
     : super core::Object::•()
     ;
 }
@@ -20,10 +20,10 @@
     return n;
 }
 static method foo() → dynamic {
-  return <core::List<self::A<core::Null?>>*>[<core::Null?>[], <self::A<core::Null?>>[]];
+  return <core::List<self::A<core::Null?>>>[<core::Null?>[], <self::A<core::Null?>>[]];
 }
 static method bar() → dynamic {
-  return <core::List<self::A<core::Null?>>*>[#C1, #C2];
+  return <core::List<self::A<core::Null?>>>[#C1, #C2];
 }
 static method main() → dynamic {}
 
diff --git a/pkg/front_end/testcases/nnbd/substitution_in_inference.dart.outline.expect b/pkg/front_end/testcases/nnbd/substitution_in_inference.dart.outline.expect
index 5c95be5..537af02 100644
--- a/pkg/front_end/testcases/nnbd/substitution_in_inference.dart.outline.expect
+++ b/pkg/front_end/testcases/nnbd/substitution_in_inference.dart.outline.expect
@@ -3,7 +3,7 @@
 import "dart:core" as core;
 
 class A<T extends core::Object? = core::Object?, S extends core::Object = core::Object> extends core::Object {
-  synthetic constructor •() → self::A<self::A::T*, self::A::S*>*
+  synthetic constructor •() → self::A<self::A::T%, self::A::S>*
     ;
   method hest<generic-covariant-impl X extends self::A::T% = self::A::T%, Y extends core::List<self::A::hest::X%> = core::List<self::A::T%>, Z extends core::List<self::A::hest::X?> = core::List<self::A::T?>>() → dynamic
     ;
diff --git a/pkg/front_end/testcases/nnbd/substitution_in_inference.dart.strong.expect b/pkg/front_end/testcases/nnbd/substitution_in_inference.dart.strong.expect
index ed9375c..cbc95c4 100644
--- a/pkg/front_end/testcases/nnbd/substitution_in_inference.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/substitution_in_inference.dart.strong.expect
@@ -3,7 +3,7 @@
 import "dart:core" as core;
 
 class A<T extends core::Object? = core::Object?, S extends core::Object = core::Object> extends core::Object {
-  synthetic constructor •() → self::A<self::A::T*, self::A::S*>*
+  synthetic constructor •() → self::A<self::A::T%, self::A::S>*
     : super core::Object::•()
     ;
   method hest<generic-covariant-impl X extends self::A::T% = self::A::T%, Y extends core::List<self::A::hest::X%> = core::List<self::A::T%>, Z extends core::List<self::A::hest::X?> = core::List<self::A::T?>>() → dynamic
diff --git a/pkg/front_end/testcases/nnbd/substitution_in_inference.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/substitution_in_inference.dart.strong.transformed.expect
index ed9375c..cbc95c4 100644
--- a/pkg/front_end/testcases/nnbd/substitution_in_inference.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/substitution_in_inference.dart.strong.transformed.expect
@@ -3,7 +3,7 @@
 import "dart:core" as core;
 
 class A<T extends core::Object? = core::Object?, S extends core::Object = core::Object> extends core::Object {
-  synthetic constructor •() → self::A<self::A::T*, self::A::S*>*
+  synthetic constructor •() → self::A<self::A::T%, self::A::S>*
     : super core::Object::•()
     ;
   method hest<generic-covariant-impl X extends self::A::T% = self::A::T%, Y extends core::List<self::A::hest::X%> = core::List<self::A::T%>, Z extends core::List<self::A::hest::X?> = core::List<self::A::T?>>() → dynamic
diff --git a/pkg/front_end/testcases/nnbd/type_parameter_types.dart.outline.expect b/pkg/front_end/testcases/nnbd/type_parameter_types.dart.outline.expect
index ce46e5f..54c224f 100644
--- a/pkg/front_end/testcases/nnbd/type_parameter_types.dart.outline.expect
+++ b/pkg/front_end/testcases/nnbd/type_parameter_types.dart.outline.expect
@@ -3,7 +3,7 @@
 import "dart:core" as core;
 
 class A<X extends core::Object = core::Object, Y extends core::Object? = core::Object?> extends core::Object {
-  synthetic constructor •() → self::A<self::A::X*, self::A::Y*>*
+  synthetic constructor •() → self::A<self::A::X, self::A::Y%>*
     ;
   method foo() → self::A::X
     ;
@@ -13,19 +13,19 @@
     ;
 }
 class B<X extends core::List<self::B::Y%> = core::List<core::Object?>, Y extends core::Object? = core::Object?> extends core::Object {
-  synthetic constructor •() → self::B<self::B::X*, self::B::Y*>*
+  synthetic constructor •() → self::B<self::B::X, self::B::Y%>*
     ;
   method foo(generic-covariant-impl self::B::X x, generic-covariant-impl self::B::Y% y) → dynamic
     ;
 }
 class C<X extends core::List<self::C::Y%>? = core::List<dynamic>?, Y extends core::List<self::C::X%>? = core::List<dynamic>?> extends core::Object {
-  synthetic constructor •() → self::C<self::C::X*, self::C::Y*>*
+  synthetic constructor •() → self::C<self::C::X%, self::C::Y%>*
     ;
   method foo(generic-covariant-impl self::C::X% x, generic-covariant-impl self::C::Y% y) → dynamic
     ;
 }
 class D<X extends self::D::Y% = dynamic, Y extends self::D::Z% = dynamic, Z extends core::Object? = dynamic> extends core::Object {
-  synthetic constructor •() → self::D<self::D::X*, self::D::Y*, self::D::Z*>*
+  synthetic constructor •() → self::D<self::D::X%, self::D::Y%, self::D::Z%>*
     ;
   method foo(generic-covariant-impl self::D::X% x, generic-covariant-impl self::D::Y% y, generic-covariant-impl self::D::Z% z) → dynamic
     ;
diff --git a/pkg/front_end/testcases/nnbd/type_parameter_types.dart.strong.expect b/pkg/front_end/testcases/nnbd/type_parameter_types.dart.strong.expect
index 83c7544..da778be 100644
--- a/pkg/front_end/testcases/nnbd/type_parameter_types.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/type_parameter_types.dart.strong.expect
@@ -3,7 +3,7 @@
 import "dart:core" as core;
 
 class A<X extends core::Object = core::Object, Y extends core::Object? = core::Object?> extends core::Object {
-  synthetic constructor •() → self::A<self::A::X*, self::A::Y*>*
+  synthetic constructor •() → self::A<self::A::X, self::A::Y%>*
     : super core::Object::•()
     ;
   method foo() → self::A::X
@@ -14,19 +14,19 @@
     return null;
 }
 class B<X extends core::List<self::B::Y%> = core::List<core::Object?>, Y extends core::Object? = core::Object?> extends core::Object {
-  synthetic constructor •() → self::B<self::B::X*, self::B::Y*>*
+  synthetic constructor •() → self::B<self::B::X, self::B::Y%>*
     : super core::Object::•()
     ;
   method foo(generic-covariant-impl self::B::X x, generic-covariant-impl self::B::Y% y) → dynamic {}
 }
 class C<X extends core::List<self::C::Y%>? = core::List<dynamic>?, Y extends core::List<self::C::X%>? = core::List<dynamic>?> extends core::Object {
-  synthetic constructor •() → self::C<self::C::X*, self::C::Y*>*
+  synthetic constructor •() → self::C<self::C::X%, self::C::Y%>*
     : super core::Object::•()
     ;
   method foo(generic-covariant-impl self::C::X% x, generic-covariant-impl self::C::Y% y) → dynamic {}
 }
 class D<X extends self::D::Y% = dynamic, Y extends self::D::Z% = dynamic, Z extends core::Object? = dynamic> extends core::Object {
-  synthetic constructor •() → self::D<self::D::X*, self::D::Y*, self::D::Z*>*
+  synthetic constructor •() → self::D<self::D::X%, self::D::Y%, self::D::Z%>*
     : super core::Object::•()
     ;
   method foo(generic-covariant-impl self::D::X% x, generic-covariant-impl self::D::Y% y, generic-covariant-impl self::D::Z% z) → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/type_parameter_types.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/type_parameter_types.dart.strong.transformed.expect
index 83c7544..da778be 100644
--- a/pkg/front_end/testcases/nnbd/type_parameter_types.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/type_parameter_types.dart.strong.transformed.expect
@@ -3,7 +3,7 @@
 import "dart:core" as core;
 
 class A<X extends core::Object = core::Object, Y extends core::Object? = core::Object?> extends core::Object {
-  synthetic constructor •() → self::A<self::A::X*, self::A::Y*>*
+  synthetic constructor •() → self::A<self::A::X, self::A::Y%>*
     : super core::Object::•()
     ;
   method foo() → self::A::X
@@ -14,19 +14,19 @@
     return null;
 }
 class B<X extends core::List<self::B::Y%> = core::List<core::Object?>, Y extends core::Object? = core::Object?> extends core::Object {
-  synthetic constructor •() → self::B<self::B::X*, self::B::Y*>*
+  synthetic constructor •() → self::B<self::B::X, self::B::Y%>*
     : super core::Object::•()
     ;
   method foo(generic-covariant-impl self::B::X x, generic-covariant-impl self::B::Y% y) → dynamic {}
 }
 class C<X extends core::List<self::C::Y%>? = core::List<dynamic>?, Y extends core::List<self::C::X%>? = core::List<dynamic>?> extends core::Object {
-  synthetic constructor •() → self::C<self::C::X*, self::C::Y*>*
+  synthetic constructor •() → self::C<self::C::X%, self::C::Y%>*
     : super core::Object::•()
     ;
   method foo(generic-covariant-impl self::C::X% x, generic-covariant-impl self::C::Y% y) → dynamic {}
 }
 class D<X extends self::D::Y% = dynamic, Y extends self::D::Z% = dynamic, Z extends core::Object? = dynamic> extends core::Object {
-  synthetic constructor •() → self::D<self::D::X*, self::D::Y*, self::D::Z*>*
+  synthetic constructor •() → self::D<self::D::X%, self::D::Y%, self::D::Z%>*
     : super core::Object::•()
     ;
   method foo(generic-covariant-impl self::D::X% x, generic-covariant-impl self::D::Y% y, generic-covariant-impl self::D::Z% z) → dynamic {}
diff --git a/pkg/front_end/testcases/outline.status b/pkg/front_end/testcases/outline.status
index 33482fb..c400d6f 100644
--- a/pkg/front_end/testcases/outline.status
+++ b/pkg/front_end/testcases/outline.status
@@ -2,12 +2,6 @@
 # for details. All rights reserved. Use of this source code is governed by a
 # BSD-style license that can be found in the LICENSE.md file.
 
-inference/downwards_inference_on_list_literals_infer_if_value_types_match_context: ExpectationFileMismatchSerialized
-inference/generic_methods_infer_generic_function_parameter_type2: ExpectationFileMismatchSerialized
-regress/issue_31181: ExpectationFileMismatchSerialized
-regress/issue_31213: ExpectationFileMismatchSerialized
-runtime_checks/contravariant_generic_return_tear_off: ExpectationFileMismatchSerialized
-
 general/abstract_members: TypeCheckError
 general/bug30695: TypeCheckError
 general/bug30695: TypeCheckError
diff --git a/pkg/front_end/testcases/rasta/issue_000031.dart.strong.expect b/pkg/front_end/testcases/rasta/issue_000031.dart.strong.expect
index 896ebc5..8b4190c 100644
--- a/pkg/front_end/testcases/rasta/issue_000031.dart.strong.expect
+++ b/pkg/front_end/testcases/rasta/issue_000031.dart.strong.expect
@@ -7,11 +7,12 @@
 //   ^^^^
 //
 import self as self;
+import "dart:core" as core;
 
 import "dart:math" as math;
 
 static method main() → dynamic {
   let final dynamic #t1 = invalid-expression "pkg/front_end/testcases/rasta/issue_000031.dart:8:3: Error: A prefix can't be used as an expression.
   math..toString();
-  ^^^^" in let final void #t2 = #t1.{dart.core::Object::toString}() in #t1;
+  ^^^^" in let final void #t2 = #t1.{core::Object::toString}() in #t1;
 }
diff --git a/pkg/front_end/testcases/rasta/issue_000031.dart.strong.transformed.expect b/pkg/front_end/testcases/rasta/issue_000031.dart.strong.transformed.expect
index 896ebc5..8b4190c 100644
--- a/pkg/front_end/testcases/rasta/issue_000031.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/rasta/issue_000031.dart.strong.transformed.expect
@@ -7,11 +7,12 @@
 //   ^^^^
 //
 import self as self;
+import "dart:core" as core;
 
 import "dart:math" as math;
 
 static method main() → dynamic {
   let final dynamic #t1 = invalid-expression "pkg/front_end/testcases/rasta/issue_000031.dart:8:3: Error: A prefix can't be used as an expression.
   math..toString();
-  ^^^^" in let final void #t2 = #t1.{dart.core::Object::toString}() in #t1;
+  ^^^^" in let final void #t2 = #t1.{core::Object::toString}() in #t1;
 }
diff --git a/pkg/front_end/testcases/rasta/issue_000032.dart.outline.expect b/pkg/front_end/testcases/rasta/issue_000032.dart.outline.expect
index 4045a94..497582b 100644
--- a/pkg/front_end/testcases/rasta/issue_000032.dart.outline.expect
+++ b/pkg/front_end/testcases/rasta/issue_000032.dart.outline.expect
@@ -7,6 +7,7 @@
 // ^
 //
 // pkg/front_end/testcases/rasta/issue_000032.dart:6:4: Error: Constructors can't have type parameters.
+// Try removing the type parameters.
 //   C<
 //    ^^...
 //
diff --git a/pkg/front_end/testcases/rasta/issue_000032.dart.strong.expect b/pkg/front_end/testcases/rasta/issue_000032.dart.strong.expect
index 0bcb6e2..f449dd1 100644
--- a/pkg/front_end/testcases/rasta/issue_000032.dart.strong.expect
+++ b/pkg/front_end/testcases/rasta/issue_000032.dart.strong.expect
@@ -7,6 +7,7 @@
 // ^
 //
 // pkg/front_end/testcases/rasta/issue_000032.dart:6:4: Error: Constructors can't have type parameters.
+// Try removing the type parameters.
 //   C<
 //    ^^...
 //
diff --git a/pkg/front_end/testcases/rasta/issue_000032.dart.strong.transformed.expect b/pkg/front_end/testcases/rasta/issue_000032.dart.strong.transformed.expect
index 0bcb6e2..f449dd1 100644
--- a/pkg/front_end/testcases/rasta/issue_000032.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/rasta/issue_000032.dart.strong.transformed.expect
@@ -7,6 +7,7 @@
 // ^
 //
 // pkg/front_end/testcases/rasta/issue_000032.dart:6:4: Error: Constructors can't have type parameters.
+// Try removing the type parameters.
 //   C<
 //    ^^...
 //
diff --git a/pkg/front_end/testcases/regress/issue_29983.dart.strong.transformed.expect b/pkg/front_end/testcases/regress/issue_29983.dart.strong.transformed.expect
index 2908e6c..9eae023 100644
--- a/pkg/front_end/testcases/regress/issue_29983.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/regress/issue_29983.dart.strong.transformed.expect
@@ -22,7 +22,7 @@
 import "dart:core" as core;
 
 static method f() → dynamic /* originally sync* */ {
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   function :sync_op(core::_SyncIterator<dynamic>* :iterator) → core::bool* yielding {
     {
@@ -35,7 +35,7 @@
   return new core::_SyncIterable::•<dynamic>(:sync_op);
 }
 static method g() → dynamic /* originally sync* */ {
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   function :sync_op(core::_SyncIterator<dynamic>* :iterator) → core::bool* yielding {
     invalid-expression "pkg/front_end/testcases/regress/issue_29983.dart:11:14: Error: 'sync*' and 'async*' can't return a value.
@@ -46,7 +46,7 @@
   return new core::_SyncIterable::•<dynamic>(:sync_op);
 }
 static method h() → dynamic /* originally sync* */ {
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   function :sync_op(core::_SyncIterator<dynamic>* :iterator) → core::bool* yielding {
     {
diff --git a/pkg/front_end/testcases/regress/issue_31181.dart.outline.expect b/pkg/front_end/testcases/regress/issue_31181.dart.outline.expect
index 91c2fcb..2181f89 100644
--- a/pkg/front_end/testcases/regress/issue_31181.dart.outline.expect
+++ b/pkg/front_end/testcases/regress/issue_31181.dart.outline.expect
@@ -2,7 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-typedef Foo<invariant T extends core::Object* = dynamic> = <T extends core::Object* = dynamic>(T*) →* T*;
+typedef Foo<unrelated T extends core::Object* = dynamic> = <T extends core::Object* = dynamic>(T*) →* T*;
 static field <T extends core::Object* = dynamic>(T*) →* T* x;
 static method main() → dynamic
   ;
diff --git a/pkg/front_end/testcases/regress/issue_31213.dart.outline.expect b/pkg/front_end/testcases/regress/issue_31213.dart.outline.expect
index a734b9c..b80b64a 100644
--- a/pkg/front_end/testcases/regress/issue_31213.dart.outline.expect
+++ b/pkg/front_end/testcases/regress/issue_31213.dart.outline.expect
@@ -3,7 +3,7 @@
 import "dart:core" as core;
 
 typedef C<contravariant A extends core::Object* = dynamic, contravariant K extends core::Object* = dynamic> = <B extends core::Object* = dynamic>(A*, K*, B*) →* core::int*;
-typedef D<unrelated K extends core::Object* = dynamic> = <A extends core::Object* = dynamic>(core::int*) →* <B extends core::Object* = dynamic>(A*, K*, B*) →* core::int*;
+typedef D<contravariant K extends core::Object* = dynamic> = <A extends core::Object* = dynamic>(core::int*) →* <B extends core::Object* = dynamic>(A*, K*, B*) →* core::int*;
 static method producer<K extends core::Object* = dynamic>() → dynamic
   ;
 static method main() → dynamic
diff --git a/pkg/front_end/testcases/regress/issue_34850.dart.strong.transformed.expect b/pkg/front_end/testcases/regress/issue_34850.dart.strong.transformed.expect
index 26c459c..1175daa 100644
--- a/pkg/front_end/testcases/regress/issue_34850.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/regress/issue_34850.dart.strong.transformed.expect
@@ -57,6 +57,7 @@
 import self as self;
 import "dart:core" as core;
 import "dart:async" as asy;
+import "dart:_internal" as _in;
 
 static method f1() → invalid-type {
   return null;
@@ -68,7 +69,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
     try {
@@ -95,7 +96,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
     try {
@@ -122,7 +123,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   dynamic :saved_try_context_var0;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
@@ -133,7 +134,7 @@
         [yield] let dynamic #t1 = asy::_awaitHelper(self::f2(), :async_op_then, :async_op_error, :async_op) in null;
         core::print(:result);
         [yield] let dynamic #t2 = asy::_awaitHelper(self::f3(), :async_op_then, :async_op_error, :async_op) in null;
-        core::print(:result);
+        core::print(_in::unsafeCast<invalid-type>(:result));
       }
       asy::_completeOnAsyncReturn(:async_completer, :return_value);
       return;
diff --git a/pkg/front_end/testcases/regress/issue_37681.dart.strong.transformed.expect b/pkg/front_end/testcases/regress/issue_37681.dart.strong.transformed.expect
index 5cffed8..519cf0e 100644
--- a/pkg/front_end/testcases/regress/issue_37681.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/regress/issue_37681.dart.strong.transformed.expect
@@ -17,6 +17,7 @@
 import self as self;
 import "dart:async" as asy;
 import "dart:core" as core;
+import "dart:_internal" as _in;
 
 static method main() → dynamic /* originally async */ {
   final asy::_AsyncAwaitCompleter<dynamic>* :async_completer = new asy::_AsyncAwaitCompleter::•<dynamic>();
@@ -24,7 +25,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   dynamic :saved_try_context_var0;
   dynamic :saved_try_context_var1;
@@ -40,7 +41,7 @@
           dynamic :async_stack_trace;
           dynamic :async_op_then;
           dynamic :async_op_error;
-          dynamic :await_jump_var = 0;
+          core::int* :await_jump_var = 0;
           dynamic :await_ctx_var;
           function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
             try {
@@ -62,14 +63,14 @@
           return :async_completer.{asy::Completer::future};
         }
         [yield] let dynamic #t1 = asy::_awaitHelper(f_async.call(), :async_op_then, :async_op_error, :async_op) in null;
-        core::print(:result);
+        core::print(_in::unsafeCast<core::int*>(:result));
         function f_async_star() → core::int* /* originally async* */ {
           asy::_AsyncStarStreamController<dynamic>* :controller;
           dynamic :controller_stream;
           dynamic :async_stack_trace;
           dynamic :async_op_then;
           dynamic :async_op_error;
-          dynamic :await_jump_var = 0;
+          core::int* :await_jump_var = 0;
           dynamic :await_ctx_var;
           dynamic :saved_try_context_var0;
           dynamic :saved_try_context_var1;
@@ -107,7 +108,7 @@
             while (true) {
               dynamic #t2 = asy::_asyncStarMoveNextHelper(:stream);
               [yield] let dynamic #t3 = asy::_awaitHelper(:for-iterator.{asy::_StreamIterator::moveNext}(), :async_op_then, :async_op_error, :async_op) in null;
-              if(:result) {
+              if(_in::unsafeCast<core::bool*>(:result)) {
                 dynamic x = :for-iterator.{asy::_StreamIterator::current};
                 {
                   core::print(x);
@@ -123,7 +124,7 @@
             }
         }
         function f_sync_star() → core::int* /* originally sync* */ {
-          dynamic :await_jump_var = 0;
+          core::int* :await_jump_var = 0;
           dynamic :await_ctx_var;
           function :sync_op(core::_SyncIterator<dynamic>* :iterator) → core::bool* yielding {
             {
diff --git a/pkg/front_end/testcases/runtime_checks/contravariant_generic_return_tear_off.dart.outline.expect b/pkg/front_end/testcases/runtime_checks/contravariant_generic_return_tear_off.dart.outline.expect
index 3ab6c88..dd755c5 100644
--- a/pkg/front_end/testcases/runtime_checks/contravariant_generic_return_tear_off.dart.outline.expect
+++ b/pkg/front_end/testcases/runtime_checks/contravariant_generic_return_tear_off.dart.outline.expect
@@ -3,7 +3,7 @@
 import "dart:core" as core;
 
 typedef F<contravariant T extends core::Object* = dynamic> = (T*) →* void;
-typedef G<unrelated T extends core::Object* = dynamic> = () →* (T*) →* void;
+typedef G<contravariant T extends core::Object* = dynamic> = () →* (T*) →* void;
 class C<T extends core::Object* = dynamic> extends core::Object {
   field (self::C::T*) →* void _x;
   constructor •((self::C::T*) →* void _x) → self::C<self::C::T*>*
diff --git a/pkg/front_end/testcases/set_literals/disambiguation_rule.dart.strong.transformed.expect b/pkg/front_end/testcases/set_literals/disambiguation_rule.dart.strong.transformed.expect
index 5af0f46..3f7f9e6 100644
--- a/pkg/front_end/testcases/set_literals/disambiguation_rule.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/set_literals/disambiguation_rule.dart.strong.transformed.expect
@@ -48,6 +48,7 @@
 import "dart:async" as asy;
 import "dart:core" as core;
 import "dart:collection" as col;
+import "dart:_internal" as _in;
 
 import "dart:async";
 import "dart:collection";
@@ -58,7 +59,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   dynamic :saved_try_context_var0;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
@@ -81,25 +82,25 @@
   LinkedHashMap<int, bool> lhm = {};
                                  ^" in <dynamic, dynamic>{};
         [yield] let dynamic #t6 = asy::_awaitHelper(self::mapfun(), :async_op_then, :async_op_error, :async_op) in null;
-        core::Map<core::int*, core::bool*>* fm = :result;
+        core::Map<core::int*, core::bool*>* fm = _in::unsafeCast<core::Map<core::int*, core::bool*>*>(:result);
         [yield] let dynamic #t7 = asy::_awaitHelper(self::setfun(), :async_op_then, :async_op_error, :async_op) in null;
-        core::Set<core::int*>* fs = :result;
+        core::Set<core::int*>* fs = _in::unsafeCast<core::Set<core::int*>*>(:result);
         [yield] let dynamic #t8 = asy::_awaitHelper(self::iterablefun(), :async_op_then, :async_op_error, :async_op) in null;
-        core::Iterable<core::int*>* fi = :result;
+        core::Iterable<core::int*>* fi = _in::unsafeCast<core::Iterable<core::int*>*>(:result);
         [yield] let dynamic #t9 = asy::_awaitHelper(self::lhsfun(), :async_op_then, :async_op_error, :async_op) in null;
-        col::LinkedHashSet<core::int*>* flhs = :result;
+        col::LinkedHashSet<core::int*>* flhs = _in::unsafeCast<col::LinkedHashSet<core::int*>*>(:result);
         [yield] let dynamic #t10 = asy::_awaitHelper(self::lhmfun(), :async_op_then, :async_op_error, :async_op) in null;
-        col::LinkedHashMap<core::int*, core::bool*>* flhm = :result;
+        col::LinkedHashMap<core::int*, core::bool*>* flhm = _in::unsafeCast<col::LinkedHashMap<core::int*, core::bool*>*>(:result);
         [yield] let dynamic #t11 = asy::_awaitHelper(self::mapfun2(), :async_op_then, :async_op_error, :async_op) in null;
-        core::Map<core::int*, core::bool*>* fm2 = :result;
+        core::Map<core::int*, core::bool*>* fm2 = _in::unsafeCast<core::Map<core::int*, core::bool*>*>(:result);
         [yield] let dynamic #t12 = asy::_awaitHelper(self::setfun2(), :async_op_then, :async_op_error, :async_op) in null;
-        core::Set<core::int*>* fs2 = :result;
+        core::Set<core::int*>* fs2 = _in::unsafeCast<core::Set<core::int*>*>(:result);
         [yield] let dynamic #t13 = asy::_awaitHelper(self::iterablefun2(), :async_op_then, :async_op_error, :async_op) in null;
-        core::Iterable<core::int*>* fi2 = :result;
+        core::Iterable<core::int*>* fi2 = _in::unsafeCast<core::Iterable<core::int*>*>(:result);
         [yield] let dynamic #t14 = asy::_awaitHelper(self::lhsfun2(), :async_op_then, :async_op_error, :async_op) in null;
-        col::LinkedHashSet<core::int*>* flhs2 = :result;
+        col::LinkedHashSet<core::int*>* flhs2 = _in::unsafeCast<col::LinkedHashSet<core::int*>*>(:result);
         [yield] let dynamic #t15 = asy::_awaitHelper(self::lhmfun2(), :async_op_then, :async_op_error, :async_op) in null;
-        col::LinkedHashMap<core::int*, core::bool*>* flhm2 = :result;
+        col::LinkedHashMap<core::int*, core::bool*>* flhm2 = _in::unsafeCast<col::LinkedHashMap<core::int*, core::bool*>*>(:result);
       }
       asy::_completeOnAsyncReturn(:async_completer, :return_value);
       return;
@@ -119,7 +120,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
     try {
@@ -146,7 +147,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
     try {
@@ -173,7 +174,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
     try {
@@ -200,7 +201,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
     try {
@@ -232,7 +233,7 @@
   dynamic :async_stack_trace;
   dynamic :async_op_then;
   dynamic :async_op_error;
-  dynamic :await_jump_var = 0;
+  core::int* :await_jump_var = 0;
   dynamic :await_ctx_var;
   function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
     try {
diff --git a/pkg/front_end/testcases/strong.status b/pkg/front_end/testcases/strong.status
index 626187039..a50207f 100644
--- a/pkg/front_end/testcases/strong.status
+++ b/pkg/front_end/testcases/strong.status
@@ -62,7 +62,7 @@
 general/type_parameter_type_named_int: RuntimeError # Expected
 general/type_variable_as_super: RuntimeError
 general/type_variable_bound_access: TypeCheckError
-general/unsound_promotion: RuntimeError
+general/unsound_promotion: TypeCheckError
 general/void_methods: RuntimeError
 general/warn_unresolved_sends: InstrumentationMismatch # Test assumes Dart 1.0 semantics
 inference/abstract_class_instantiation: InstrumentationMismatch # Issue #30040
@@ -111,8 +111,8 @@
 inference_new/invalid_assignment_during_toplevel_inference: TypeCheckError
 instantiate_to_bound/non_simple_class_parametrized_typedef_cycle: RuntimeError # Expected
 instantiate_to_bound/non_simple_generic_function_in_bound_regress: RuntimeError # Expected
-nnbd/nullable_param: RuntimeError
 nnbd/inheritance_from_opt_out: TypeCheckError
+nnbd/nullable_param: RuntimeError
 rasta/abstract_constructor: RuntimeError
 rasta/bad_constructor_redirection: RuntimeError
 rasta/bad_continue: RuntimeError
diff --git a/pkg/front_end/testcases/text_serialization.status b/pkg/front_end/testcases/text_serialization.status
index c70f507..02dd58d 100644
--- a/pkg/front_end/testcases/text_serialization.status
+++ b/pkg/front_end/testcases/text_serialization.status
@@ -10,6 +10,7 @@
 expression/main: TextSerializationFailure # Was: Pass
 extensions/annotations: TextSerializationFailure
 extensions/builtin_identifiers: TextSerializationFailure
+extensions/call_methods: TextSerializationFailure
 extensions/check_bounds: TextSerializationFailure
 extensions/compounds: TextSerializationFailure
 extensions/conflict_with_object: TextSerializationFailure
@@ -87,6 +88,8 @@
 general/async_function: TextSerializationFailure # Was: Pass
 general/async_nested: TextSerializationFailure # Was: Pass
 general/await: TextSerializationFailure # Was: Pass
+general/await_complex: TextSerializationFailure
+general/await_in_cascade: TextSerializationFailure
 general/await_in_non_async: TextSerializationFailure
 general/bad_setter_abstract: TextSerializationFailure # Was: Pass
 general/bad_store: TextSerializationFailure # Was: Pass
@@ -167,6 +170,7 @@
 general/external: TextSerializationFailure # Was: Pass
 general/external_import: TextSerializationFailure # Was: RuntimeError # The native extension to import doesn't exist. This is ok.
 general/fallthrough: TextSerializationFailure
+general/ffi_sample: TextSerializationFailure
 general/fibonacci: TextSerializationFailure # Was: Pass
 general/for_in_scope: TextSerializationFailure # Was: Pass
 general/for_in_without_declaration: TextSerializationFailure
@@ -212,6 +216,8 @@
 general/issue38943: TextSerializationFailure
 general/issue38944: TextSerializationFailure
 general/issue38961: TextSerializationFailure
+general/issue39344: TextSerializationFailure
+general/issue39421: TextSerializationFailure
 general/literals: TextSerializationFailure # Was: Pass
 general/local_generic_function: TextSerializationFailure # Was: Pass
 general/long_chain_of_typedefs: TextSerializationFailure
@@ -317,7 +323,7 @@
 general/undefined: TextSerializationFailure # Was: Pass
 general/undefined_getter_in_compound_assignment: TextSerializationFailure # Was: Pass
 general/uninitialized_fields: TextSerializationFailure # Was: Pass
-general/unsound_promotion: TextSerializationFailure
+general/unsound_promotion: TypeCheckError
 general/unused_methods: TextSerializationFailure # Was: Pass
 general/var_as_type_name: TextSerializationFailure # Was: Pass
 general/void_methods: TextSerializationFailure
@@ -889,6 +895,28 @@
 instantiate_to_bound/typedef_omitted_bound: TextSerializationFailure # Was: Pass
 instantiate_to_bound/typedef_raw_in_bound: TextSerializationFailure # Was: Pass
 instantiate_to_bound/typedef_super_bounded_type: TextSerializationFailure # Was: Pass
+late_lowering/instance_field_with_initializer: TextSerializationFailure
+late_lowering/instance_field_without_initializer: TextSerializationFailure
+late_lowering/instance_final_field_without_initializer: TextSerializationFailure
+late_lowering/instance_nullable_field_with_initializer: TextSerializationFailure
+late_lowering/instance_nullable_field_without_initializer: TextSerializationFailure
+late_lowering/instance_nullable_final_field_without_initializer: TextSerializationFailure
+late_lowering/late_field_with_initializer: TextSerializationFailure
+late_lowering/late_field_without_initializer: TextSerializationFailure
+late_lowering/late_final_field_with_initializer: TextSerializationFailure
+late_lowering/late_final_field_without_initializer: TextSerializationFailure
+late_lowering/late_final_nullable_field_with_initializer: TextSerializationFailure
+late_lowering/late_final_nullable_field_without_initializer: TextSerializationFailure
+late_lowering/late_nullable_field_with_initializer: TextSerializationFailure
+late_lowering/late_nullable_field_without_initializer: TextSerializationFailure
+late_lowering/late_final_local_with_initializer: TextSerializationFailure
+late_lowering/late_final_local_without_initializer: TextSerializationFailure
+late_lowering/late_final_nullable_local_with_initializer: TextSerializationFailure
+late_lowering/late_final_nullable_local_without_initializer: TextSerializationFailure
+late_lowering/late_local_with_initializer: TextSerializationFailure
+late_lowering/late_local_without_initializer: TextSerializationFailure
+late_lowering/late_nullable_local_with_initializer: TextSerializationFailure
+late_lowering/late_nullable_local_without_initializer: TextSerializationFailure
 new_const_insertion/simple: TextSerializationFailure # Was: Pass
 nnbd/function_types: TextSerializationFailure
 nnbd/inheritance_from_opt_out: TypeCheckError
@@ -898,8 +926,10 @@
 nnbd/late: TextSerializationFailure
 nnbd/null_check: TextSerializationFailure
 nnbd/null_shorting: TextSerializationFailure
+nnbd/null_shorting_cascade: TextSerializationFailure
 nnbd/null_shorting_explicit_extension: TextSerializationFailure
 nnbd/null_shorting_extension: TextSerializationFailure
+nnbd/null_shorting_index: TextSerializationFailure
 nnbd/nullable_null: TextSerializationFailure
 nnbd/nullable_param: TextSerializationFailure
 nnbd/opt_out: TextSerializationFailure
@@ -1172,5 +1202,5 @@
 top_level_variance_test: TextSerializationFailure
 unified_collections/mixed_entries: TextSerializationFailure
 variance/class_type_parameter_modifier: TextSerializationFailure
-variance/mixin_type_parameter_modifier: TextSerializationFailure
 variance/generic_covariance_sound_variance: TextSerializationFailure
+variance/mixin_type_parameter_modifier: TextSerializationFailure
diff --git a/pkg/front_end/testcases/variance/generic_covariance_sound_variance.dart b/pkg/front_end/testcases/variance/generic_covariance_sound_variance.dart
index 9400df5..058c7be 100644
--- a/pkg/front_end/testcases/variance/generic_covariance_sound_variance.dart
+++ b/pkg/front_end/testcases/variance/generic_covariance_sound_variance.dart
@@ -20,7 +20,7 @@
 
 class B<inout T> {
   T x;
-  T method(T x) => null;
+  T method(T x) => x;
   void set y(T x) {}
 }
 
@@ -46,6 +46,10 @@
   F(void Function(T) f) : super(f);
 }
 
+class NoSuchMethod<inout T> implements B<T> {
+  noSuchMethod(_) => 3;
+}
+
 main() {
   A<int, num, String> a = new A();
   expect(null, a.field);
@@ -60,7 +64,7 @@
   B<int> b = new B();
   b.x = 3;
   expect(3, b.x);
-  expect(null, b.method(3));
+  expect(3, b.method(3));
   b.y = 3;
 
   C<int> c = new C();
@@ -70,6 +74,9 @@
 
   D<Object> d = new F<String>((String s) {});
   d.method("test");
+
+  NoSuchMethod<num> nsm = new NoSuchMethod<num>();
+  expect(3, nsm.method(3));
 }
 
 expect(expected, actual) {
diff --git a/pkg/front_end/testcases/variance/generic_covariance_sound_variance.dart.outline.expect b/pkg/front_end/testcases/variance/generic_covariance_sound_variance.dart.outline.expect
index 6260243..7d0b0e0 100644
--- a/pkg/front_end/testcases/variance/generic_covariance_sound_variance.dart.outline.expect
+++ b/pkg/front_end/testcases/variance/generic_covariance_sound_variance.dart.outline.expect
@@ -67,6 +67,20 @@
   forwarding-stub method method(generic-covariant-impl self::F::T* x) → core::int*
     return super.{self::E::method}(x);
 }
+class NoSuchMethod<invariant T extends core::Object* = dynamic> extends core::Object implements self::B<self::NoSuchMethod::T*> {
+  synthetic constructor •() → self::NoSuchMethod<self::NoSuchMethod::T*>*
+    ;
+  method noSuchMethod(core::Invocation* _) → dynamic
+    ;
+  no-such-method-forwarder get x() → self::NoSuchMethod::T*
+    return this.{self::NoSuchMethod::noSuchMethod}(new core::_InvocationMirror::_withType(#x, 1, const <core::Type*>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol*, dynamic>(const <core::Symbol*, dynamic>{}))) as{TypeError} self::NoSuchMethod::T*;
+  no-such-method-forwarder method method(self::NoSuchMethod::T* x) → self::NoSuchMethod::T*
+    return this.{self::NoSuchMethod::noSuchMethod}(new core::_InvocationMirror::_withType(#method, 0, const <core::Type*>[], core::List::unmodifiable<dynamic>(<dynamic>[x]), core::Map::unmodifiable<core::Symbol*, dynamic>(const <core::Symbol*, dynamic>{}))) as{TypeError} self::NoSuchMethod::T*;
+  no-such-method-forwarder set y(self::NoSuchMethod::T* x) → void
+    return this.{self::NoSuchMethod::noSuchMethod}(new core::_InvocationMirror::_withType(#y=, 2, const <core::Type*>[], core::List::unmodifiable<dynamic>(<dynamic>[x]), core::Map::unmodifiable<core::Symbol*, dynamic>(const <core::Symbol*, dynamic>{})));
+  no-such-method-forwarder set x(self::NoSuchMethod::T* value) → void
+    return this.{self::NoSuchMethod::noSuchMethod}(new core::_InvocationMirror::_withType(#x=, 2, const <core::Type*>[], core::List::unmodifiable<dynamic>(<dynamic>[value]), core::Map::unmodifiable<core::Symbol*, dynamic>(const <core::Symbol*, dynamic>{})));
+}
 static method main() → dynamic
   ;
 static method expect(dynamic expected, dynamic actual) → dynamic
diff --git a/pkg/front_end/testcases/variance/generic_covariance_sound_variance.dart.strong.expect b/pkg/front_end/testcases/variance/generic_covariance_sound_variance.dart.strong.expect
index 0c751d4..fa18fb9 100644
--- a/pkg/front_end/testcases/variance/generic_covariance_sound_variance.dart.strong.expect
+++ b/pkg/front_end/testcases/variance/generic_covariance_sound_variance.dart.strong.expect
@@ -37,7 +37,7 @@
     : super core::Object::•()
     ;
   method method(self::B::T* x) → self::B::T*
-    return null;
+    return x;
   set y(self::B::T* x) → void {}
 }
 class C<contravariant T extends core::Object* = dynamic> extends core::Object {
@@ -70,6 +70,21 @@
   forwarding-stub method method(generic-covariant-impl self::F::T* x) → core::int*
     return super.{self::E::method}(x);
 }
+class NoSuchMethod<invariant T extends core::Object* = dynamic> extends core::Object implements self::B<self::NoSuchMethod::T*> {
+  synthetic constructor •() → self::NoSuchMethod<self::NoSuchMethod::T*>*
+    : super core::Object::•()
+    ;
+  method noSuchMethod(core::Invocation* _) → dynamic
+    return 3;
+  no-such-method-forwarder get x() → self::NoSuchMethod::T*
+    return this.{self::NoSuchMethod::noSuchMethod}(new core::_InvocationMirror::_withType(#C2, 1, #C3, #C4, core::Map::unmodifiable<core::Symbol*, dynamic>(#C5))) as{TypeError} self::NoSuchMethod::T*;
+  no-such-method-forwarder method method(self::NoSuchMethod::T* x) → self::NoSuchMethod::T*
+    return this.{self::NoSuchMethod::noSuchMethod}(new core::_InvocationMirror::_withType(#C6, 0, #C3, core::List::unmodifiable<dynamic>(<dynamic>[x]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C5))) as{TypeError} self::NoSuchMethod::T*;
+  no-such-method-forwarder set y(self::NoSuchMethod::T* x) → void
+    return this.{self::NoSuchMethod::noSuchMethod}(new core::_InvocationMirror::_withType(#C7, 2, #C3, core::List::unmodifiable<dynamic>(<dynamic>[x]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C5)));
+  no-such-method-forwarder set x(self::NoSuchMethod::T* value) → void
+    return this.{self::NoSuchMethod::noSuchMethod}(new core::_InvocationMirror::_withType(#C8, 2, #C3, core::List::unmodifiable<dynamic>(<dynamic>[value]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C5)));
+}
 static method main() → dynamic {
   self::A<core::int*, core::num*, core::String*>* a = new self::A::•<core::int*, core::num*, core::String*>();
   self::expect(null, a.{self::A::field});
@@ -83,7 +98,7 @@
   self::B<core::int*>* b = new self::B::•<core::int*>();
   b.{self::B::x} = 3;
   self::expect(3, b.{self::B::x});
-  self::expect(null, b.{self::B::method}(3));
+  self::expect(3, b.{self::B::method}(3));
   b.{self::B::y} = 3;
   self::C<core::int*>* c = new self::C::•<core::int*>();
   self::expect(null, c.{self::C::field});
@@ -91,6 +106,8 @@
   c.{self::C::x} = 3;
   self::D<core::Object*>* d = new self::F::•<core::String*>((core::String* s) → core::Null? {});
   d.{self::D::method}("test");
+  self::NoSuchMethod<core::num*>* nsm = new self::NoSuchMethod::•<core::num*>();
+  self::expect(3, nsm.{self::B::method}(3));
 }
 static method expect(dynamic expected, dynamic actual) → dynamic {
   if(!expected.{core::Object::==}(actual)) {
@@ -100,4 +117,11 @@
 
 constants  {
   #C1 = null
+  #C2 = #x
+  #C3 = <core::Type*>[]
+  #C4 = <dynamic>[]
+  #C5 = core::_ImmutableMap<core::Symbol*, dynamic> {_kvPairs:#C4}
+  #C6 = #method
+  #C7 = #y=
+  #C8 = #x=
 }
diff --git a/pkg/front_end/testcases/variance/generic_covariance_sound_variance.dart.strong.transformed.expect b/pkg/front_end/testcases/variance/generic_covariance_sound_variance.dart.strong.transformed.expect
index 0c751d4..fa18fb9 100644
--- a/pkg/front_end/testcases/variance/generic_covariance_sound_variance.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/variance/generic_covariance_sound_variance.dart.strong.transformed.expect
@@ -37,7 +37,7 @@
     : super core::Object::•()
     ;
   method method(self::B::T* x) → self::B::T*
-    return null;
+    return x;
   set y(self::B::T* x) → void {}
 }
 class C<contravariant T extends core::Object* = dynamic> extends core::Object {
@@ -70,6 +70,21 @@
   forwarding-stub method method(generic-covariant-impl self::F::T* x) → core::int*
     return super.{self::E::method}(x);
 }
+class NoSuchMethod<invariant T extends core::Object* = dynamic> extends core::Object implements self::B<self::NoSuchMethod::T*> {
+  synthetic constructor •() → self::NoSuchMethod<self::NoSuchMethod::T*>*
+    : super core::Object::•()
+    ;
+  method noSuchMethod(core::Invocation* _) → dynamic
+    return 3;
+  no-such-method-forwarder get x() → self::NoSuchMethod::T*
+    return this.{self::NoSuchMethod::noSuchMethod}(new core::_InvocationMirror::_withType(#C2, 1, #C3, #C4, core::Map::unmodifiable<core::Symbol*, dynamic>(#C5))) as{TypeError} self::NoSuchMethod::T*;
+  no-such-method-forwarder method method(self::NoSuchMethod::T* x) → self::NoSuchMethod::T*
+    return this.{self::NoSuchMethod::noSuchMethod}(new core::_InvocationMirror::_withType(#C6, 0, #C3, core::List::unmodifiable<dynamic>(<dynamic>[x]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C5))) as{TypeError} self::NoSuchMethod::T*;
+  no-such-method-forwarder set y(self::NoSuchMethod::T* x) → void
+    return this.{self::NoSuchMethod::noSuchMethod}(new core::_InvocationMirror::_withType(#C7, 2, #C3, core::List::unmodifiable<dynamic>(<dynamic>[x]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C5)));
+  no-such-method-forwarder set x(self::NoSuchMethod::T* value) → void
+    return this.{self::NoSuchMethod::noSuchMethod}(new core::_InvocationMirror::_withType(#C8, 2, #C3, core::List::unmodifiable<dynamic>(<dynamic>[value]), core::Map::unmodifiable<core::Symbol*, dynamic>(#C5)));
+}
 static method main() → dynamic {
   self::A<core::int*, core::num*, core::String*>* a = new self::A::•<core::int*, core::num*, core::String*>();
   self::expect(null, a.{self::A::field});
@@ -83,7 +98,7 @@
   self::B<core::int*>* b = new self::B::•<core::int*>();
   b.{self::B::x} = 3;
   self::expect(3, b.{self::B::x});
-  self::expect(null, b.{self::B::method}(3));
+  self::expect(3, b.{self::B::method}(3));
   b.{self::B::y} = 3;
   self::C<core::int*>* c = new self::C::•<core::int*>();
   self::expect(null, c.{self::C::field});
@@ -91,6 +106,8 @@
   c.{self::C::x} = 3;
   self::D<core::Object*>* d = new self::F::•<core::String*>((core::String* s) → core::Null? {});
   d.{self::D::method}("test");
+  self::NoSuchMethod<core::num*>* nsm = new self::NoSuchMethod::•<core::num*>();
+  self::expect(3, nsm.{self::B::method}(3));
 }
 static method expect(dynamic expected, dynamic actual) → dynamic {
   if(!expected.{core::Object::==}(actual)) {
@@ -100,4 +117,11 @@
 
 constants  {
   #C1 = null
+  #C2 = #x
+  #C3 = <core::Type*>[]
+  #C4 = <dynamic>[]
+  #C5 = core::_ImmutableMap<core::Symbol*, dynamic> {_kvPairs:#C4}
+  #C6 = #method
+  #C7 = #y=
+  #C8 = #x=
 }
diff --git a/pkg/front_end/testing.json b/pkg/front_end/testing.json
index e2cbcce..47b4925 100644
--- a/pkg/front_end/testing.json
+++ b/pkg/front_end/testing.json
@@ -187,7 +187,7 @@
       "exclude": []
     },
     {
-      "name": "old_dill_test",
+      "name": "old_dill",
       "kind": "Chain",
       "source": "test/old_dill_suite.dart",
       "path": "testcases/old_dills/dills/",
@@ -198,7 +198,7 @@
       "exclude": []
     },
     {
-      "name": "parser_test",
+      "name": "parser",
       "kind": "Chain",
       "source": "test/parser_suite.dart",
       "path": "parser_testcases/",
@@ -210,7 +210,7 @@
       "exclude": []
     },
     {
-      "name": "lint_test",
+      "name": "lint",
       "kind": "Chain",
       "source": "test/lint_suite.dart",
       "path": "lib/",
@@ -223,7 +223,7 @@
       ]
     },
     {
-      "name": "spelling_test_src_test",
+      "name": "spelling_test_src",
       "kind": "Chain",
       "source": "test/spelling_test_src_suite.dart",
       "path": "../",
@@ -238,7 +238,7 @@
       ]
     },
     {
-      "name": "spelling_test_not_src_test",
+      "name": "spelling_test_not_src",
       "kind": "Chain",
       "source": "test/spelling_test_not_src_suite.dart",
       "path": ".",
diff --git a/pkg/front_end/tool/_fasta/command_line.dart b/pkg/front_end/tool/_fasta/command_line.dart
index 05a5b83..5644059 100644
--- a/pkg/front_end/tool/_fasta/command_line.dart
+++ b/pkg/front_end/tool/_fasta/command_line.dart
@@ -249,6 +249,7 @@
   "--omit-platform": false,
   "--fatal": ",",
   "--fatal-skip": String,
+  "--force-late-lowering": false,
   "--help": false,
   // TODO(johnniwinther): Remove legacy option flags. Legacy mode is no longer
   // supported.
@@ -304,7 +305,8 @@
 
   final String targetName = options["--target"] ?? "vm";
 
-  final TargetFlags flags = new TargetFlags();
+  final TargetFlags flags = new TargetFlags(
+      forceLateLoweringForTesting: options["--force-late-lowering"]);
 
   final Target target = getTarget(targetName, flags);
   if (target == null) {
diff --git a/pkg/frontend_server/lib/frontend_server.dart b/pkg/frontend_server/lib/frontend_server.dart
index 176909e..6f73514 100644
--- a/pkg/frontend_server/lib/frontend_server.dart
+++ b/pkg/frontend_server/lib/frontend_server.dart
@@ -428,6 +428,7 @@
           await _runWithPrintRedirection(() => _generator.compile());
       results = KernelCompilationResults(
           component,
+          const {},
           _generator.getClassHierarchy(),
           _generator.getCoreTypes(),
           component.uriToSource.keys);
@@ -444,6 +445,7 @@
       // No bytecode at this step. Bytecode is generated later in _writePackage.
       results = await _runWithPrintRedirection(() => compileToKernel(
           _mainSource, compilerOptions,
+          includePlatform: options['link-platform'],
           aot: options['aot'],
           useGlobalTypeFlowAnalysis: options['tfa'],
           environmentDefines: environmentDefines,
@@ -528,8 +530,12 @@
       KernelCompilationResults results, String filename) async {
     final Component component = results.component;
     // Compute strongly connected components.
-    final strongComponents = StrongComponents(component, _mainSource,
-        _compilerOptions.packagesFileUri, _compilerOptions.fileSystem);
+    final strongComponents = StrongComponents(
+        component,
+        results.loadedLibraries,
+        _mainSource,
+        _compilerOptions.packagesFileUri,
+        _compilerOptions.fileSystem);
     await strongComponents.computeModules();
 
     // Create JavaScript bundler.
@@ -543,8 +549,13 @@
     final sourceFileSink = sourceFile.openWrite();
     final manifestFileSink = manifestFile.openWrite();
     final sourceMapsFileSink = sourceMapsFile.openWrite();
-    bundler.compile(results.classHierarchy, results.coreTypes, sourceFileSink,
-        manifestFileSink, sourceMapsFileSink);
+    bundler.compile(
+        results.classHierarchy,
+        results.coreTypes,
+        results.loadedLibraries,
+        sourceFileSink,
+        manifestFileSink,
+        sourceMapsFileSink);
     await Future.wait([
       sourceFileSink.close(),
       manifestFileSink.close(),
@@ -569,7 +580,7 @@
           if (_options['incremental']) {
             // When loading a single kernel buffer with multiple sub-components,
             // the VM expects 'main' to be the first sub-component.
-            await forEachPackage(component,
+            await forEachPackage(results,
                 (String package, List<Library> libraries) async {
               _writePackage(results, package, libraries, sink);
             }, mainFirst: true);
@@ -597,11 +608,11 @@
         final file = new File(_initializeFromDill);
         await file.create(recursive: true);
         final IOSink sink = file.openWrite();
+        final Set<Library> loadedLibraries = results.loadedLibraries;
         final BinaryPrinter printer = filterExternal
             ? LimitedBinaryPrinter(
                 sink,
-                // ignore: DEPRECATED_MEMBER_USE
-                (lib) => !lib.isExternal,
+                (lib) => !loadedLibraries.contains(lib),
                 true /* excludeUriToSource */)
             : printerFactory.newBinaryPrinter(sink);
 
@@ -613,11 +624,9 @@
     } else {
       // Generate AST as the output proper.
       final IOSink sink = File(filename).openWrite();
+      final Set<Library> loadedLibraries = results.loadedLibraries;
       final BinaryPrinter printer = filterExternal
-          ? LimitedBinaryPrinter(
-              sink,
-              // ignore: DEPRECATED_MEMBER_USE
-              (lib) => !lib.isExternal,
+          ? LimitedBinaryPrinter(sink, (lib) => !loadedLibraries.contains(lib),
               true /* excludeUriToSource */)
           : printerFactory.newBinaryPrinter(sink);
 
@@ -636,12 +645,7 @@
 
     if (_options['split-output-by-packages']) {
       await writeOutputSplitByPackages(
-          _mainSource,
-          _compilerOptions,
-          results.component,
-          results.coreTypes,
-          results.classHierarchy,
-          filename,
+          _mainSource, _compilerOptions, results, filename,
           genBytecode: _compilerOptions.bytecode,
           bytecodeOptions: _bytecodeOptions,
           dropAST: _options['drop-ast']);
@@ -731,9 +735,16 @@
 
     Component partComponent = result.component;
     if (_compilerOptions.bytecode && errors.isEmpty) {
+      final List<Library> librariesFiltered = new List<Library>();
+      final Set<Library> loadedLibraries = result.loadedLibraries;
+      for (Library library in libraries) {
+        if (loadedLibraries.contains(library)) continue;
+        librariesFiltered.add(library);
+      }
+
       generateBytecode(partComponent,
           options: _bytecodeOptions,
-          libraries: libraries,
+          libraries: librariesFiltered,
           coreTypes: _generator?.getCoreTypes(),
           hierarchy: _generator?.getClassHierarchy());
 
@@ -743,8 +754,10 @@
     }
 
     final byteSink = ByteSink();
-    final BinaryPrinter printer = LimitedBinaryPrinter(byteSink,
-        (lib) => packageFor(lib) == package, false /* excludeUriToSource */);
+    final BinaryPrinter printer = LimitedBinaryPrinter(
+        byteSink,
+        (lib) => packageFor(lib, result.loadedLibraries) == package,
+        false /* excludeUriToSource */);
     printer.writeComponentFile(partComponent);
 
     final bytes = byteSink.builder.takeBytes();
@@ -771,6 +784,7 @@
 
     KernelCompilationResults results = KernelCompilationResults(
         deltaProgram,
+        const {},
         _generator.getClassHierarchy(),
         _generator.getCoreTypes(),
         deltaProgram.uriToSource.keys);
@@ -923,9 +937,9 @@
 
   @override
   Future<void> rejectLastDelta() async {
-    await _generator.reject();
     final String boundaryKey = Uuid().generateV4();
     _outputStream.writeln('result $boundaryKey');
+    await _generator.reject();
     _outputStream.writeln(boundaryKey);
   }
 
diff --git a/pkg/frontend_server/lib/src/javascript_bundle.dart b/pkg/frontend_server/lib/src/javascript_bundle.dart
index 2ed86d3..1178433 100644
--- a/pkg/frontend_server/lib/src/javascript_bundle.dart
+++ b/pkg/frontend_server/lib/src/javascript_bundle.dart
@@ -50,15 +50,20 @@
   Map<Uri, Component> _uriToComponent;
 
   /// Compile each component into a single JavaScript module.
-  void compile(ClassHierarchy classHierarchy, CoreTypes coreTypes,
-      IOSink codeSink, IOSink manifestSink, IOSink sourceMapsSink) {
+  void compile(
+      ClassHierarchy classHierarchy,
+      CoreTypes coreTypes,
+      Set<Library> loadedLibraries,
+      IOSink codeSink,
+      IOSink manifestSink,
+      IOSink sourceMapsSink) {
     var codeOffset = 0;
     var sourceMapOffset = 0;
     final manifest = <String, Map<String, List<int>>>{};
     final Set<Uri> visited = <Uri>{};
     for (Library library in _originalComponent.libraries) {
-      // ignore: DEPRECATED_MEMBER_USE
-      if (library.isExternal || library.importUri.scheme == 'dart') {
+      if (loadedLibraries.contains(library) ||
+          library.importUri.scheme == 'dart') {
         continue;
       }
       final Uri moduleUri = _strongComponents.moduleAssignment[library.fileUri];
diff --git a/pkg/frontend_server/lib/src/strong_components.dart b/pkg/frontend_server/lib/src/strong_components.dart
index bf2cf8d6..534cb30 100644
--- a/pkg/frontend_server/lib/src/strong_components.dart
+++ b/pkg/frontend_server/lib/src/strong_components.dart
@@ -29,6 +29,7 @@
 class StrongComponents {
   StrongComponents(
     this.component,
+    this.loadedLibraries,
     this.mainUri, [
     this.packagesUri,
     this.fileSystem,
@@ -40,6 +41,9 @@
   /// lbraries.
   final Component component;
 
+  /// The libraries loaded from a dill file that should not be processed.
+  final Set<Library> loadedLibraries;
+
   /// The main URI for thiis application.
   final Uri mainUri;
 
@@ -90,7 +94,7 @@
     }
 
     final List<List<Library>> results =
-        computeStrongComponents(_LibraryGraph(entrypoint));
+        computeStrongComponents(_LibraryGraph(entrypoint, loadedLibraries));
     for (List<Library> component in results) {
       assert(component.length > 0);
       final Uri moduleUri = component.first.fileUri;
@@ -149,16 +153,16 @@
 }
 
 class _LibraryGraph implements Graph<Library> {
-  _LibraryGraph(this.library);
+  _LibraryGraph(this.library, this.loadedLibraries);
 
   final Library library;
+  final Set<Library> loadedLibraries;
 
   @override
   Iterable<Library> neighborsOf(Library vertex) {
     return <Library>[
       for (LibraryDependency dependency in vertex.dependencies)
-        // ignore: DEPRECATED_MEMBER_USE
-        if (!dependency.targetLibrary.isExternal &&
+        if (!loadedLibraries.contains(dependency.targetLibrary) &&
             dependency.targetLibrary.importUri.scheme != 'dart')
           dependency.targetLibrary
     ];
diff --git a/pkg/frontend_server/test/frontend_server_test.dart b/pkg/frontend_server/test/frontend_server_test.dart
index 26d94bd..810c85e 100644
--- a/pkg/frontend_server/test/frontend_server_test.dart
+++ b/pkg/frontend_server/test/frontend_server_test.dart
@@ -1095,14 +1095,18 @@
             file.writeAsStringSync("pkgA() {} pkgA_2() {}");
 
             count += 1;
+            outputParser.expectSources = false;
             inputStreamController.add('reject\n'.codeUnits);
-            inputStreamController.add('reset\n'.codeUnits);
-            inputStreamController.add('recompile ${file.path} abc\n'
-                    '${file.path}\n'
-                    'abc\n'
-                .codeUnits);
             break;
           case 1:
+            count += 1;
+            inputStreamController.add('reset\n'.codeUnits);
+            inputStreamController.add('recompile ${file.path} abc\n'
+                '${file.uri}\n'
+                'abc\n'
+                .codeUnits);
+            break;
+          case 2:
             expect(dillFile.existsSync(), equals(true));
             expect(result.filename, dillFile.path);
             expect(result.errorsCount, 0);
@@ -1124,11 +1128,11 @@
             inputStreamController.add('accept\n'.codeUnits);
             inputStreamController.add('reset\n'.codeUnits);
             inputStreamController.add('recompile ${file.path} abc\n'
-                    '${file.path}\n'
-                    'abc\n'
+                '${file.uri}\n'
+                'abc\n'
                 .codeUnits);
             break;
-          case 2:
+          case 3:
             expect(result.filename, dillFile.path);
             expect(result.errorsCount, 0);
             inputStreamController.add('quit\n'.codeUnits);
diff --git a/pkg/frontend_server/test/src/javascript_bundle_test.dart b/pkg/frontend_server/test/src/javascript_bundle_test.dart
index b6d860d..7c491da 100644
--- a/pkg/frontend_server/test/src/javascript_bundle_test.dart
+++ b/pkg/frontend_server/test/src/javascript_bundle_test.dart
@@ -69,7 +69,7 @@
     );
     final testComponent = Component(libraries: [library, ...testCoreLibraries]);
     final strongComponents =
-        StrongComponents(testComponent, Uri.file('/c.dart'));
+        StrongComponents(testComponent, {}, Uri.file('/c.dart'));
     strongComponents.computeModules();
     final javaScriptBundler =
         JavaScriptBundler(testComponent, strongComponents);
@@ -78,7 +78,7 @@
     final sourcemapSink = _MemorySink();
 
     javaScriptBundler.compile(ClassHierarchy(testComponent),
-        CoreTypes(testComponent), codeSink, manifestSink, sourcemapSink);
+        CoreTypes(testComponent), {}, codeSink, manifestSink, sourcemapSink);
 
     final Map manifest = json.decode(utf8.decode(manifestSink.buffer));
     final String code = utf8.decode(codeSink.buffer);
@@ -117,7 +117,7 @@
         libraries: [libraryA, libraryB, libraryC, ...testCoreLibraries]);
 
     final strongComponents =
-        StrongComponents(testComponent, Uri.file('/a.dart'));
+        StrongComponents(testComponent, {}, Uri.file('/a.dart'));
     strongComponents.computeModules();
     final javaScriptBundler =
         JavaScriptBundler(testComponent, strongComponents);
@@ -126,7 +126,7 @@
     final sourcemapSink = _MemorySink();
 
     javaScriptBundler.compile(ClassHierarchy(testComponent),
-        CoreTypes(testComponent), codeSink, manifestSink, sourcemapSink);
+        CoreTypes(testComponent), {}, codeSink, manifestSink, sourcemapSink);
 
     final code = utf8.decode(codeSink.buffer);
     final manifest = json.decode(utf8.decode(manifestSink.buffer));
diff --git a/pkg/frontend_server/test/src/strong_components_test.dart b/pkg/frontend_server/test/src/strong_components_test.dart
index 42dab3b..6d36691 100644
--- a/pkg/frontend_server/test/src/strong_components_test.dart
+++ b/pkg/frontend_server/test/src/strong_components_test.dart
@@ -10,7 +10,7 @@
   test('empty component', () {
     final testComponent = Component(libraries: []);
     final StrongComponents strongComponents =
-        StrongComponents(testComponent, Uri.file('/c.dart'));
+        StrongComponents(testComponent, {}, Uri.file('/c.dart'));
     strongComponents.computeModules();
 
     expect(strongComponents.modules, {});
@@ -41,7 +41,7 @@
       libraryC,
     ]);
     final StrongComponents strongComponents =
-        StrongComponents(testComponent, Uri.file('/c.dart'));
+        StrongComponents(testComponent, {}, Uri.file('/c.dart'));
     strongComponents.computeModules();
 
     expect(strongComponents.modules, {
@@ -81,7 +81,7 @@
       libraryC,
     ]);
     final StrongComponents strongComponents =
-        StrongComponents(testComponent, Uri.file('/c.dart'));
+        StrongComponents(testComponent, {}, Uri.file('/c.dart'));
     strongComponents.computeModules();
 
     expect(strongComponents.modules, {
@@ -97,8 +97,8 @@
     });
   });
 
-  test('does not index external, dart:, or unimported libraries', () {
-    final libraryExternal = Library(
+  test('does not index loaded , dart:, or unimported libraries', () {
+    final libraryLoaded = Library(
       Uri.file('a.dart'),
       fileUri: Uri.file('/a.dart'),
       isExternal: true,
@@ -115,18 +115,18 @@
       Uri.file('/c.dart'),
       fileUri: Uri.file('/c.dart'),
       dependencies: [
-        LibraryDependency.import(libraryExternal),
+        LibraryDependency.import(libraryLoaded),
         LibraryDependency.import(libraryDart),
       ],
     );
     final testComponent = Component(libraries: [
-      libraryExternal,
+      libraryLoaded,
       libraryDart,
       libraryUnrelated,
       libraryC,
     ]);
     final StrongComponents strongComponents =
-        StrongComponents(testComponent, Uri.file('/c.dart'));
+        StrongComponents(testComponent, {libraryLoaded}, Uri.file('/c.dart'));
     strongComponents.computeModules();
 
     expect(strongComponents.modules, {
diff --git a/pkg/js/proposal.md b/pkg/js/proposal.md
index abc888d..381e85c 100644
--- a/pkg/js/proposal.md
+++ b/pkg/js/proposal.md
@@ -60,7 +60,7 @@
 This proposal outlines a series of usability improvements that, taken together,
 make it much easier to use JS from Dart and vice versa.
 
-Here's an example of JS interop is like today, from the [Firebase package](https://pub.dartlang.org/packages/firebase):
+Here's an example of JS interop is like today, from the [Firebase package](https://pub.dev/packages/firebase):
 ```dart
 import 'interop/app_interop.dart';
 
diff --git a/pkg/kernel/bin/transform.dart b/pkg/kernel/bin/transform.dart
index 8285315..40196b4 100755
--- a/pkg/kernel/bin/transform.dart
+++ b/pkg/kernel/bin/transform.dart
@@ -20,6 +20,7 @@
 import 'package:kernel/transformations/empty.dart' as empty;
 import 'package:kernel/transformations/method_call.dart' as method_call;
 import 'package:kernel/transformations/mixin_full_resolution.dart' as mix;
+import 'package:kernel/type_environment.dart';
 import 'package:kernel/vm/constants_native_effects.dart';
 
 ArgParser parser = new ArgParser()
@@ -87,10 +88,11 @@
 
   final coreTypes = new CoreTypes(component);
   final hierarchy = new ClassHierarchy(component);
+  final typeEnvironment = new TypeEnvironment(coreTypes, hierarchy);
   switch (options['transformation']) {
     case 'continuation':
       bool productMode = defines["dart.vm.product"] == "true";
-      component = cont.transformComponent(coreTypes, component,
+      component = cont.transformComponent(typeEnvironment, component,
           productMode: productMode);
       break;
     case 'resolve-mixins':
diff --git a/pkg/kernel/doc/nnbd_api.md b/pkg/kernel/doc/nnbd_api.md
index a0b3781..cfabaeb 100644
--- a/pkg/kernel/doc/nnbd_api.md
+++ b/pkg/kernel/doc/nnbd_api.md
@@ -274,9 +274,212 @@
 
 Fields and variables can be declared using the `late` keyword.  To reflect the use of the keyword the CFE sets the `isLate` flag on `Field` and `VariableDeclaration` nodes.
 
-The plan is to provide an optional desugaring of `late` fields and variables to aid the initial implementation of the feature.  The desugaring could be turned on by back ends via a compilation-target flag.
+#### Late field encoding
+An optional desugaring of `late` fields and variables is provided to aid the initial implementation of the feature.  The desugaring is enabled if `Target.supportsLateFields` returns `false`.
 
-*TODO: Expand the section on desugaring.*
+There are 8 variants of the encoding based on whether type of the field is potentially nullable, whether the field is final and whether the field has an initializer.
+
+If a late field is non-nullable, its value is stored in a private nullable field and a field value of `null` signals that the field is uninitialized. Otherwise if a late field is potentially nullable, an additional boolean `_#isSet#` field is generated to tracking whether the field has been initialized.
+
+##### 1) Potentially nullable late field without initializer
+A potentially nullable late non-final field:
+```
+late T? x;
+```
+is encoded as
+```
+bool _#x#isSet = false;
+T? _#x;
+T? get x => _#x#isSet ? _#x : throw new StateError("Field 'x' has not been initialized.");
+void set x(T? value) {
+  _#x#isSet = true;
+  _#x = value;
+}
+```
+
+##### 2) Potentially nullable late final field without initializer
+A potentially nullable late final field _without_ an initializer
+```
+late final T? x;
+```
+is encoded as
+```
+bool _#x#isSet = false;
+T? _#x;
+T? get x => _#x#isSet ? _#x : throw new StateError("Field 'x' has not been initialized.");
+void set x(T? value) {
+  if (_#x#isSet) {
+    throw new StateError('Field x has already been initialized.');
+  } else {
+    _#x#isSet = true;
+    _#x = value;
+  }
+}
+```
+
+##### 3) Potentially nullable late field with initializer
+A potentially nullable late field _with_ initializer `<exp>`
+```
+late T? x = <exp>;
+```
+is encoded as
+```
+bool _#x#isSet = false;
+T? _#x;
+T? get x {
+  if (!_#x#isSet) {
+    _#x#isSet = true;
+    _#x = <exp>;
+  }
+return _#x
+}
+void set x(T? value) {
+  _#x#isSet = true
+  _#x = value;
+}
+```
+
+##### 4) Potentially nullable late final field with initializer
+A potentially nullable late final field _with_ initializer `<exp>`
+```
+late final T? x = <exp>;
+```
+is encoded as
+```
+bool _#x#isSet = false;
+T? _#x;
+T? get x {
+  if (!_#x#isSet) {
+    _#x#isSet = true;
+    _#x = <exp>;
+  }
+  return _#x;
+}
+```
+
+##### 5) Non-nullable late field without initializer
+A non-nullable late non-final field:
+```
+late T x;
+```
+is encoded as
+```
+T? _#x;
+T get x => let T? # = _#x in # == null ? throw new StateError("Field 'x' has not been initialized.") : #;
+void set x(T value) {
+  _#x = value;
+}
+```
+The reason for using a `let` expression here, is that while the private field is nullable, the temporary variable in the `let` expression will be promoted to a non-nullable type when checking against `null`, thus ensuring that the returned value is soundly non-nullable, also when analyzing the kernel ast itself.
+
+##### 6) Non-nullable late final field without initializer
+A non-nullable late final field _without_ an initializer
+```
+late final T x;
+```
+is encoded as
+```
+T? _#x;
+T get x => let T? # = _#x in # == null ? throw new StateError("Field 'x' has not been initialized.") : #;
+void set x(T value) {
+  if (_#x == null) {
+    _#x = value;
+  } else {
+    throw new StateError("Field 'x' has already been initialized.");
+  }
+}
+```
+
+##### 7) Non-nullable late field with initializer
+A non-nullable late field _with_ initializer `<exp>`
+```
+late T x = <exp>;
+```
+is encoded as
+```
+T? _#x;
+T get x => let T? # = _#x in # == null ? _#x = <exp> : #;
+void set x(T value) {
+  _#x = value;
+}
+```
+
+##### 8) Non-nullable late final field with initializer
+A non-nullable late final field _with_ initializer `<exp>`
+```
+late final T x = <exp>;
+```
+is encoded as
+```
+T? _#x;
+T get x => let T? # = _#x in # == null ? _#x = <exp> : _#x;
+```
+
+##### Local variables
+A late local variable is encoded similarly to a late field. Local functions are created which correspond to the getters and setters for late fields.
+
+For instance, a nullable late local _without_ initializer
+```
+method() {
+  late T? x;
+  <lhs> = x;
+  variable = <rhs>;
+}
+```
+is encoded as
+```
+method() {
+  bool #x#isSet = false;
+  T? #x;
+  T? #x#get() => #x#isSet ? #x : throw new StateError("Local 'x' has not been initialized.")
+  T? #x#set(T? value)  {
+    _#x#isSet = true;
+    return _#x = value;
+  }
+  <lhs> = #x#get.call();
+  #x#set.call(<rhs>);
+}
+```
+
+##### Instance field initialization
+A field initialization of late _nullable_ instance field
+```
+class Class {
+  late T? x;
+  Class.a();
+  Class.b(this.x);
+  Class.c() : x = <exp>;
+}
+```
+is encoded as
+```
+class Class {
+  bool _#x#isSet = false;
+  T? _#x;
+  Class.a();
+  Class.b(T x) : _#x#isSet true, _#x = x;
+  Class.c() : _#x#isSet = true, _#x = <exp>;
+}
+```
+
+A field initialization of late _non-nullable_ instance field
+```
+class Class {
+  late T x;
+  Class.a();
+  Class.b(this.x);
+  Class.c() : x = <exp>;
+}
+```
+is encoded as
+```
+class Class {
+  T? _#x;
+  Class.a();
+  Class.b(T x) : _#x = x;
+  Class.b() : _#x = <exp>;
+}
+```
 
 
 ### The Null Check Operator
diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart
index 8f97938..1c993e3 100644
--- a/pkg/kernel/lib/ast.dart
+++ b/pkg/kernel/lib/ast.dart
@@ -75,6 +75,7 @@
 
 import 'transformations/flags.dart';
 import 'text/ast_to_text.dart';
+import 'core_types.dart';
 import 'type_algebra.dart';
 import 'type_environment.dart';
 
@@ -705,8 +706,10 @@
   final List<TypeParameter> typeParameters;
   DartType type;
 
-  // The following two fields describe parameters of the underlying function
-  // type.  They are needed to keep such attributes as names and annotations.
+  // The following two fields describe parameters of the underlying type when
+  // that is a function type.  They are needed to keep such attributes as names
+  // and annotations. When the underlying type is not a function type, they are
+  // empty.
   final List<TypeParameter> typeParametersOfFunctionType;
   final List<VariableDeclaration> positionalParameters;
   final List<VariableDeclaration> namedParameters;
@@ -730,11 +733,6 @@
 
   Library get enclosingLibrary => parent;
 
-  TypedefType get thisType {
-    return new TypedefType(
-        this, Nullability.legacy, _getAsTypeArguments(typeParameters));
-  }
-
   R accept<R>(TreeVisitor<R> v) {
     return v.visitTypedef(this);
   }
@@ -1226,13 +1224,13 @@
   }
 
   Supertype get asThisSupertype {
-    return new Supertype(this, _getAsTypeArguments(typeParameters));
+    return new Supertype(
+        this, getAsTypeArguments(typeParameters, this.enclosingLibrary));
   }
 
-  InterfaceType _thisType;
-  InterfaceType get thisType {
-    return _thisType ??= new InterfaceType(
-        this, Nullability.legacy, _getAsTypeArguments(typeParameters));
+  /// Returns the type of `this` for the class using [coreTypes] for caching.
+  InterfaceType getThisType(CoreTypes coreTypes, Nullability nullability) {
+    return coreTypes.thisInterfaceType(this, nullability);
   }
 
   InterfaceType _bottomType;
@@ -2571,10 +2569,7 @@
 
 abstract class Expression extends TreeNode {
   /// Returns the static type of the expression.
-  ///
-  /// Shouldn't be used on code compiled in legacy mode, as this method assumes
-  /// the IR is strongly typed.
-  DartType getStaticType(TypeEnvironment types);
+  DartType getStaticType(StaticTypeContext context);
 
   /// Returns the static type of the expression as an instantiation of
   /// [superclass].
@@ -2587,32 +2582,36 @@
   /// If this is not the case, either an exception is thrown or the raw type of
   /// [superclass] is returned.
   InterfaceType getStaticTypeAsInstanceOf(
-      Class superclass, TypeEnvironment types) {
+      Class superclass, StaticTypeContext context) {
     // This method assumes the program is correctly typed, so if the superclass
     // is not generic, we can just return its raw type without computing the
     // type of this expression.  It also ensures that all types are considered
     // subtypes of Object (not just interface types), and function types are
     // considered subtypes of Function.
     if (superclass.typeParameters.isEmpty) {
-      return types.coreTypes.legacyRawType(superclass);
+      return context.typeEnvironment.coreTypes
+          .rawType(superclass, context.nonNullable);
     }
-    var type = getStaticType(types);
+    var type = getStaticType(context);
     while (type is TypeParameterType) {
       TypeParameterType typeParameterType = type;
       type =
           typeParameterType.promotedBound ?? typeParameterType.parameter.bound;
     }
-    if (type == types.nullType) {
+    if (type == context.typeEnvironment.nullType) {
       return superclass.bottomType;
     }
     if (type is InterfaceType) {
-      var upcastType = types.getTypeAsInstanceOf(type, superclass);
+      var upcastType =
+          context.typeEnvironment.getTypeAsInstanceOf(type, superclass);
       if (upcastType != null) return upcastType;
     } else if (type is BottomType) {
       return superclass.bottomType;
     }
-    types.typeError(this, '$type is not a subtype of $superclass');
-    return types.coreTypes.legacyRawType(superclass);
+    context.typeEnvironment
+        .typeError(this, '$type is not a subtype of $superclass');
+    return context.typeEnvironment.coreTypes
+        .rawType(superclass, context.nonNullable);
   }
 
   R accept<R>(ExpressionVisitor<R> v);
@@ -2630,7 +2629,7 @@
 
   InvalidExpression(this.message);
 
-  DartType getStaticType(TypeEnvironment types) => const BottomType();
+  DartType getStaticType(StaticTypeContext context) => const BottomType();
 
   R accept<R>(ExpressionVisitor<R> v) => v.visitInvalidExpression(this);
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
@@ -2645,9 +2644,9 @@
   VariableDeclaration variable;
   DartType promotedType; // Null if not promoted.
 
-  VariableGet(this.variable, [this.promotedType]);
+  VariableGet(this.variable, [this.promotedType]) : assert(variable != null);
 
-  DartType getStaticType(TypeEnvironment types) {
+  DartType getStaticType(StaticTypeContext context) {
     return promotedType ?? variable.type;
   }
 
@@ -2673,11 +2672,12 @@
   VariableDeclaration variable;
   Expression value;
 
-  VariableSet(this.variable, this.value) {
+  VariableSet(this.variable, this.value) : assert(variable != null) {
     value?.parent = this;
   }
 
-  DartType getStaticType(TypeEnvironment types) => value.getStaticType(types);
+  DartType getStaticType(StaticTypeContext context) =>
+      value.getStaticType(context);
 
   R accept<R>(ExpressionVisitor<R> v) => v.visitVariableSet(this);
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
@@ -2718,20 +2718,21 @@
     interfaceTargetReference = getMemberReference(member);
   }
 
-  DartType getStaticType(TypeEnvironment types) {
+  DartType getStaticType(StaticTypeContext context) {
     var interfaceTarget = this.interfaceTarget;
     if (interfaceTarget != null) {
       Class superclass = interfaceTarget.enclosingClass;
-      var receiverType = receiver.getStaticTypeAsInstanceOf(superclass, types);
+      var receiverType =
+          receiver.getStaticTypeAsInstanceOf(superclass, context);
       return Substitution.fromInterfaceType(receiverType)
           .substituteType(interfaceTarget.getterType);
     }
     // Treat the properties of Object specially.
     String nameString = name.name;
     if (nameString == 'hashCode') {
-      return types.coreTypes.intLegacyRawType;
+      return context.typeEnvironment.coreTypes.intRawType(context.nonNullable);
     } else if (nameString == 'runtimeType') {
-      return types.coreTypes.typeLegacyRawType;
+      return context.typeEnvironment.coreTypes.typeRawType(context.nonNullable);
     }
     return const DynamicType();
   }
@@ -2742,6 +2743,7 @@
 
   visitChildren(Visitor v) {
     receiver?.accept(v);
+    interfaceTarget?.acceptReference(v);
     name?.accept(v);
   }
 
@@ -2782,7 +2784,8 @@
     interfaceTargetReference = getMemberReference(member);
   }
 
-  DartType getStaticType(TypeEnvironment types) => value.getStaticType(types);
+  DartType getStaticType(StaticTypeContext context) =>
+      value.getStaticType(context);
 
   R accept<R>(ExpressionVisitor<R> v) => v.visitPropertySet(this);
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
@@ -2790,6 +2793,7 @@
 
   visitChildren(Visitor v) {
     receiver?.accept(v);
+    interfaceTarget?.acceptReference(v);
     name?.accept(v);
     value?.accept(v);
   }
@@ -2840,9 +2844,9 @@
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitDirectPropertyGet(this, arg);
 
-  DartType getStaticType(TypeEnvironment types) {
+  DartType getStaticType(StaticTypeContext context) {
     Class superclass = target.enclosingClass;
-    var receiverType = receiver.getStaticTypeAsInstanceOf(superclass, types);
+    var receiverType = receiver.getStaticTypeAsInstanceOf(superclass, context);
     return Substitution.fromInterfaceType(receiverType)
         .substituteType(target.getterType);
   }
@@ -2892,7 +2896,8 @@
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitDirectPropertySet(this, arg);
 
-  DartType getStaticType(TypeEnvironment types) => value.getStaticType(types);
+  DartType getStaticType(StaticTypeContext context) =>
+      value.getStaticType(context);
 }
 
 /// Directly call an instance method, bypassing ordinary dispatch.
@@ -2940,13 +2945,14 @@
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitDirectMethodInvocation(this, arg);
 
-  DartType getStaticType(TypeEnvironment types) {
-    if (types.isOverloadedArithmeticOperator(target)) {
-      return types.getTypeOfOverloadedArithmetic(receiver.getStaticType(types),
-          arguments.positional[0].getStaticType(types));
+  DartType getStaticType(StaticTypeContext context) {
+    if (context.typeEnvironment.isOverloadedArithmeticOperator(target)) {
+      return context.typeEnvironment.getTypeOfOverloadedArithmetic(
+          receiver.getStaticType(context),
+          arguments.positional[0].getStaticType(context));
     }
     Class superclass = target.enclosingClass;
-    var receiverType = receiver.getStaticTypeAsInstanceOf(superclass, types);
+    var receiverType = receiver.getStaticTypeAsInstanceOf(superclass, context);
     var returnType = Substitution.fromInterfaceType(receiverType)
         .substituteType(target.function.returnType);
     return Substitution.fromPairs(
@@ -2974,12 +2980,18 @@
     interfaceTargetReference = getMemberReference(member);
   }
 
-  DartType getStaticType(TypeEnvironment types) {
+  DartType getStaticType(StaticTypeContext context) {
+    if (interfaceTarget == null) {
+      // TODO(johnniwinther): SuperPropertyGet without a target should be
+      // replaced by invalid expressions.
+      return const DynamicType();
+    }
     Class declaringClass = interfaceTarget.enclosingClass;
     if (declaringClass.typeParameters.isEmpty) {
       return interfaceTarget.getterType;
     }
-    var receiver = types.getTypeAsInstanceOf(types.thisType, declaringClass);
+    var receiver = context.typeEnvironment
+        .getTypeAsInstanceOf(context.thisType, declaringClass);
     return Substitution.fromInterfaceType(receiver)
         .substituteType(interfaceTarget.getterType);
   }
@@ -2989,6 +3001,7 @@
       v.visitSuperPropertyGet(this, arg);
 
   visitChildren(Visitor v) {
+    interfaceTarget?.acceptReference(v);
     name?.accept(v);
   }
 
@@ -3020,13 +3033,15 @@
     interfaceTargetReference = getMemberReference(member);
   }
 
-  DartType getStaticType(TypeEnvironment types) => value.getStaticType(types);
+  DartType getStaticType(StaticTypeContext context) =>
+      value.getStaticType(context);
 
   R accept<R>(ExpressionVisitor<R> v) => v.visitSuperPropertySet(this);
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
       v.visitSuperPropertySet(this, arg);
 
   visitChildren(Visitor v) {
+    interfaceTarget?.acceptReference(v);
     name?.accept(v);
     value?.accept(v);
   }
@@ -3054,7 +3069,7 @@
     targetReference = getMemberReference(target);
   }
 
-  DartType getStaticType(TypeEnvironment types) => target.getterType;
+  DartType getStaticType(StaticTypeContext context) => target.getterType;
 
   R accept<R>(ExpressionVisitor<R> v) => v.visitStaticGet(this);
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
@@ -3088,7 +3103,8 @@
     targetReference = getMemberReference(target);
   }
 
-  DartType getStaticType(TypeEnvironment types) => value.getStaticType(types);
+  DartType getStaticType(StaticTypeContext context) =>
+      value.getStaticType(context);
 
   R accept<R>(ExpressionVisitor<R> v) => v.visitStaticSet(this);
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
@@ -3127,14 +3143,15 @@
         positional = <Expression>[],
         named = <NamedExpression>[];
 
-  factory Arguments.forwarded(FunctionNode function) {
+  factory Arguments.forwarded(FunctionNode function, Library library) {
     return new Arguments(
         function.positionalParameters.map((p) => new VariableGet(p)).toList(),
         named: function.namedParameters
             .map((p) => new NamedExpression(p.name, new VariableGet(p)))
             .toList(),
         types: function.typeParameters
-            .map((p) => new TypeParameterType(p, Nullability.legacy))
+            .map((p) => new TypeParameterType.withDefaultNullabilityForLibrary(
+                p, library))
             .toList());
   }
 
@@ -3213,29 +3230,59 @@
     interfaceTargetReference = getMemberReference(target);
   }
 
-  DartType getStaticType(TypeEnvironment types) {
+  DartType getStaticType(StaticTypeContext context) {
     var interfaceTarget = this.interfaceTarget;
     if (interfaceTarget != null) {
       if (interfaceTarget is Procedure &&
-          types.isOverloadedArithmeticOperator(interfaceTarget)) {
-        return types.getTypeOfOverloadedArithmetic(
-            receiver.getStaticType(types),
-            arguments.positional[0].getStaticType(types));
+          context.typeEnvironment
+              .isOverloadedArithmeticOperator(interfaceTarget)) {
+        return context.typeEnvironment.getTypeOfOverloadedArithmetic(
+            receiver.getStaticType(context),
+            arguments.positional[0].getStaticType(context));
       }
       Class superclass = interfaceTarget.enclosingClass;
-      var receiverType = receiver.getStaticTypeAsInstanceOf(superclass, types);
+      var receiverType =
+          receiver.getStaticTypeAsInstanceOf(superclass, context);
       var getterType = Substitution.fromInterfaceType(receiverType)
           .substituteType(interfaceTarget.getterType);
       if (getterType is FunctionType) {
-        return Substitution.fromPairs(
-                getterType.typeParameters, arguments.types)
-            .substituteType(getterType.returnType);
-      } else {
-        return const DynamicType();
+        Substitution substitution;
+        if (getterType.typeParameters.length == arguments.types.length) {
+          substitution = Substitution.fromPairs(
+              getterType.typeParameters, arguments.types);
+        } else {
+          // TODO(johnniwinther): The front end should normalize the type
+          //  argument count or create an invalid expression in case of method
+          //  invocations with invalid type argument count.
+          substitution = Substitution.fromPairs(
+              getterType.typeParameters,
+              getterType.typeParameters
+                  .map((TypeParameter typeParameter) =>
+                      typeParameter.defaultType)
+                  .toList());
+        }
+        return substitution.substituteType(getterType.returnType);
       }
+      // The front end currently do not replace a property call `o.foo()`, where
+      // `foo` is a field or getter, with a function call on the property,
+      // `o.foo.call()`, so we look up the call method explicitly here.
+      // TODO(johnniwinther): Remove this when the front end performs the
+      // correct replacement.
+      if (getterType is InterfaceType) {
+        Member member = context.typeEnvironment
+            .getInterfaceMember(getterType.classNode, new Name('call'));
+        if (member != null) {
+          DartType callType = member.getterType;
+          if (callType is FunctionType) {
+            return Substitution.fromInterfaceType(getterType)
+                .substituteType(callType.returnType);
+          }
+        }
+      }
+      return const DynamicType();
     }
     if (name.name == 'call') {
-      var receiverType = receiver.getStaticType(types);
+      var receiverType = receiver.getStaticType(context);
       if (receiverType is FunctionType) {
         if (receiverType.typeParameters.length != arguments.types.length) {
           return const BottomType();
@@ -3247,7 +3294,7 @@
     }
     if (name.name == '==') {
       // We use this special case to simplify generation of '==' checks.
-      return types.coreTypes.boolLegacyRawType;
+      return context.typeEnvironment.coreTypes.boolRawType(context.nonNullable);
     }
     return const DynamicType();
   }
@@ -3258,6 +3305,7 @@
 
   visitChildren(Visitor v) {
     receiver?.accept(v);
+    interfaceTarget?.acceptReference(v);
     name?.accept(v);
     arguments?.accept(v);
   }
@@ -3298,10 +3346,11 @@
     interfaceTargetReference = getMemberReference(target);
   }
 
-  DartType getStaticType(TypeEnvironment types) {
+  DartType getStaticType(StaticTypeContext context) {
     if (interfaceTarget == null) return const DynamicType();
     Class superclass = interfaceTarget.enclosingClass;
-    var receiverType = types.getTypeAsInstanceOf(types.thisType, superclass);
+    var receiverType = context.typeEnvironment
+        .getTypeAsInstanceOf(context.thisType, superclass);
     var returnType = Substitution.fromInterfaceType(receiverType)
         .substituteType(interfaceTarget.function.returnType);
     return Substitution.fromPairs(
@@ -3314,6 +3363,7 @@
       v.visitSuperMethodInvocation(this, arg);
 
   visitChildren(Visitor v) {
+    interfaceTarget?.acceptReference(v);
     name?.accept(v);
     arguments?.accept(v);
   }
@@ -3354,7 +3404,7 @@
     targetReference = getMemberReference(target);
   }
 
-  DartType getStaticType(TypeEnvironment types) {
+  DartType getStaticType(StaticTypeContext context) {
     return Substitution.fromPairs(
             target.function.typeParameters, arguments.types)
         .substituteType(target.function.returnType);
@@ -3407,11 +3457,12 @@
     targetReference = getMemberReference(target);
   }
 
-  DartType getStaticType(TypeEnvironment types) {
+  DartType getStaticType(StaticTypeContext context) {
     return arguments.types.isEmpty
-        ? types.coreTypes.legacyRawType(target.enclosingClass)
+        ? context.typeEnvironment.coreTypes
+            .rawType(target.enclosingClass, context.nonNullable)
         : new InterfaceType(
-            target.enclosingClass, Nullability.legacy, arguments.types);
+            target.enclosingClass, context.nonNullable, arguments.types);
   }
 
   R accept<R>(ExpressionVisitor<R> v) => v.visitConstructorInvocation(this);
@@ -3452,8 +3503,8 @@
     expression?.parent = this;
   }
 
-  DartType getStaticType(TypeEnvironment types) {
-    FunctionType type = expression.getStaticType(types);
+  DartType getStaticType(StaticTypeContext context) {
+    FunctionType type = expression.getStaticType(context);
     return Substitution.fromPairs(type.typeParameters, typeArguments)
         .substituteType(type.withoutTypeParameters);
   }
@@ -3487,8 +3538,8 @@
     operand?.parent = this;
   }
 
-  DartType getStaticType(TypeEnvironment types) =>
-      types.coreTypes.boolLegacyRawType;
+  DartType getStaticType(StaticTypeContext context) =>
+      context.typeEnvironment.coreTypes.boolRawType(context.nonNullable);
 
   R accept<R>(ExpressionVisitor<R> v) => v.visitNot(this);
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) => v.visitNot(this, arg);
@@ -3516,8 +3567,8 @@
     right?.parent = this;
   }
 
-  DartType getStaticType(TypeEnvironment types) =>
-      types.coreTypes.boolLegacyRawType;
+  DartType getStaticType(StaticTypeContext context) =>
+      context.typeEnvironment.coreTypes.boolRawType(context.nonNullable);
 
   R accept<R>(ExpressionVisitor<R> v) => v.visitLogicalExpression(this);
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
@@ -3556,7 +3607,7 @@
     otherwise?.parent = this;
   }
 
-  DartType getStaticType(TypeEnvironment types) => staticType;
+  DartType getStaticType(StaticTypeContext context) => staticType;
 
   R accept<R>(ExpressionVisitor<R> v) => v.visitConditionalExpression(this);
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
@@ -3602,8 +3653,8 @@
     setParents(expressions, this);
   }
 
-  DartType getStaticType(TypeEnvironment types) =>
-      types.coreTypes.stringLegacyRawType;
+  DartType getStaticType(StaticTypeContext context) =>
+      context.typeEnvironment.coreTypes.stringRawType(context.nonNullable);
 
   R accept<R>(ExpressionVisitor<R> v) => v.visitStringConcatenation(this);
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
@@ -3633,8 +3684,9 @@
     setParents(lists, this);
   }
 
-  DartType getStaticType(TypeEnvironment types) {
-    return types.literalListType(typeArgument);
+  DartType getStaticType(StaticTypeContext context) {
+    return context.typeEnvironment
+        .literalListType(typeArgument, context.nonNullable);
   }
 
   R accept<R>(ExpressionVisitor<R> v) => v.visitListConcatenation(this);
@@ -3670,8 +3722,9 @@
     setParents(sets, this);
   }
 
-  DartType getStaticType(TypeEnvironment types) {
-    return types.literalSetType(typeArgument);
+  DartType getStaticType(StaticTypeContext context) {
+    return context.typeEnvironment
+        .literalSetType(typeArgument, context.nonNullable);
   }
 
   R accept<R>(ExpressionVisitor<R> v) => v.visitSetConcatenation(this);
@@ -3710,8 +3763,9 @@
     setParents(maps, this);
   }
 
-  DartType getStaticType(TypeEnvironment types) {
-    return types.literalMapType(keyType, valueType);
+  DartType getStaticType(StaticTypeContext context) {
+    return context.typeEnvironment
+        .literalMapType(keyType, valueType, context.nonNullable);
   }
 
   R accept<R>(ExpressionVisitor<R> v) => v.visitMapConcatenation(this);
@@ -3753,10 +3807,11 @@
 
   Class get classNode => classReference.asClass;
 
-  DartType getStaticType(TypeEnvironment types) {
+  DartType getStaticType(StaticTypeContext context) {
     return typeArguments.isEmpty
-        ? types.coreTypes.legacyRawType(classNode)
-        : new InterfaceType(classNode, Nullability.legacy, typeArguments);
+        ? context.typeEnvironment.coreTypes
+            .rawType(classNode, context.nonNullable)
+        : new InterfaceType(classNode, context.nonNullable, typeArguments);
   }
 
   R accept<R>(ExpressionVisitor<R> v) => v.visitInstanceCreation(this);
@@ -3806,8 +3861,8 @@
     expression.parent = this;
   }
 
-  DartType getStaticType(TypeEnvironment types) =>
-      expression.getStaticType(types);
+  DartType getStaticType(StaticTypeContext context) =>
+      expression.getStaticType(context);
 
   R accept<R>(ExpressionVisitor<R> v) => v.visitFileUriExpression(this);
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
@@ -3835,8 +3890,8 @@
     operand?.parent = this;
   }
 
-  DartType getStaticType(TypeEnvironment types) =>
-      types.coreTypes.boolLegacyRawType;
+  DartType getStaticType(StaticTypeContext context) =>
+      context.typeEnvironment.coreTypes.boolRawType(context.nonNullable);
 
   R accept<R>(ExpressionVisitor<R> v) => v.visitIsExpression(this);
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
@@ -3879,7 +3934,7 @@
     flags = value ? (flags | FlagTypeError) : (flags & ~FlagTypeError);
   }
 
-  DartType getStaticType(TypeEnvironment types) => type;
+  DartType getStaticType(StaticTypeContext context) => type;
 
   R accept<R>(ExpressionVisitor<R> v) => v.visitAsExpression(this);
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
@@ -3910,9 +3965,9 @@
     operand?.parent = this;
   }
 
-  DartType getStaticType(TypeEnvironment types) =>
-      // TODO(johnniwinther): Return `NonNull(operand.getStaticType(types))`.
-      operand.getStaticType(types);
+  DartType getStaticType(StaticTypeContext context) =>
+      // TODO(johnniwinther): Return `NonNull(operand.getStaticType(context))`.
+      operand.getStaticType(context);
 
   R accept<R>(ExpressionVisitor<R> v) => v.visitNullCheck(this);
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
@@ -3943,8 +3998,8 @@
 
   StringLiteral(this.value);
 
-  DartType getStaticType(TypeEnvironment types) =>
-      types.coreTypes.stringLegacyRawType;
+  DartType getStaticType(StaticTypeContext context) =>
+      context.typeEnvironment.coreTypes.stringRawType(context.nonNullable);
 
   R accept<R>(ExpressionVisitor<R> v) => v.visitStringLiteral(this);
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
@@ -3960,8 +4015,8 @@
 
   IntLiteral(this.value);
 
-  DartType getStaticType(TypeEnvironment types) =>
-      types.coreTypes.intLegacyRawType;
+  DartType getStaticType(StaticTypeContext context) =>
+      context.typeEnvironment.coreTypes.intRawType(context.nonNullable);
 
   R accept<R>(ExpressionVisitor<R> v) => v.visitIntLiteral(this);
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
@@ -3973,8 +4028,8 @@
 
   DoubleLiteral(this.value);
 
-  DartType getStaticType(TypeEnvironment types) =>
-      types.coreTypes.doubleLegacyRawType;
+  DartType getStaticType(StaticTypeContext context) =>
+      context.typeEnvironment.coreTypes.doubleRawType(context.nonNullable);
 
   R accept<R>(ExpressionVisitor<R> v) => v.visitDoubleLiteral(this);
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
@@ -3986,8 +4041,8 @@
 
   BoolLiteral(this.value);
 
-  DartType getStaticType(TypeEnvironment types) =>
-      types.coreTypes.boolLegacyRawType;
+  DartType getStaticType(StaticTypeContext context) =>
+      context.typeEnvironment.coreTypes.boolRawType(context.nonNullable);
 
   R accept<R>(ExpressionVisitor<R> v) => v.visitBoolLiteral(this);
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
@@ -3997,7 +4052,8 @@
 class NullLiteral extends BasicLiteral {
   Object get value => null;
 
-  DartType getStaticType(TypeEnvironment types) => types.nullType;
+  DartType getStaticType(StaticTypeContext context) =>
+      context.typeEnvironment.nullType;
 
   R accept<R>(ExpressionVisitor<R> v) => v.visitNullLiteral(this);
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
@@ -4009,8 +4065,8 @@
 
   SymbolLiteral(this.value);
 
-  DartType getStaticType(TypeEnvironment types) =>
-      types.coreTypes.symbolLegacyRawType;
+  DartType getStaticType(StaticTypeContext context) =>
+      context.typeEnvironment.coreTypes.symbolRawType(context.nonNullable);
 
   R accept<R>(ExpressionVisitor<R> v) => v.visitSymbolLiteral(this);
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
@@ -4025,8 +4081,8 @@
 
   TypeLiteral(this.type);
 
-  DartType getStaticType(TypeEnvironment types) =>
-      types.coreTypes.typeLegacyRawType;
+  DartType getStaticType(StaticTypeContext context) =>
+      context.typeEnvironment.coreTypes.typeRawType(context.nonNullable);
 
   R accept<R>(ExpressionVisitor<R> v) => v.visitTypeLiteral(this);
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
@@ -4042,7 +4098,7 @@
 }
 
 class ThisExpression extends Expression {
-  DartType getStaticType(TypeEnvironment types) => types.thisType;
+  DartType getStaticType(StaticTypeContext context) => context.thisType;
 
   R accept<R>(ExpressionVisitor<R> v) => v.visitThisExpression(this);
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
@@ -4053,7 +4109,7 @@
 }
 
 class Rethrow extends Expression {
-  DartType getStaticType(TypeEnvironment types) => const BottomType();
+  DartType getStaticType(StaticTypeContext context) => const BottomType();
 
   R accept<R>(ExpressionVisitor<R> v) => v.visitRethrow(this);
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
@@ -4070,7 +4126,7 @@
     expression?.parent = this;
   }
 
-  DartType getStaticType(TypeEnvironment types) => const BottomType();
+  DartType getStaticType(StaticTypeContext context) => const BottomType();
 
   R accept<R>(ExpressionVisitor<R> v) => v.visitThrow(this);
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) => v.visitThrow(this, arg);
@@ -4098,8 +4154,9 @@
     setParents(expressions, this);
   }
 
-  DartType getStaticType(TypeEnvironment types) {
-    return types.literalListType(typeArgument);
+  DartType getStaticType(StaticTypeContext context) {
+    return context.typeEnvironment
+        .literalListType(typeArgument, context.nonNullable);
   }
 
   R accept<R>(ExpressionVisitor<R> v) => v.visitListLiteral(this);
@@ -4128,8 +4185,9 @@
     setParents(expressions, this);
   }
 
-  DartType getStaticType(TypeEnvironment types) {
-    return types.literalSetType(typeArgument);
+  DartType getStaticType(StaticTypeContext context) {
+    return context.typeEnvironment
+        .literalSetType(typeArgument, context.nonNullable);
   }
 
   R accept<R>(ExpressionVisitor<R> v) => v.visitSetLiteral(this);
@@ -4162,8 +4220,9 @@
     setParents(entries, this);
   }
 
-  DartType getStaticType(TypeEnvironment types) {
-    return types.literalMapType(keyType, valueType);
+  DartType getStaticType(StaticTypeContext context) {
+    return context.typeEnvironment
+        .literalMapType(keyType, valueType, context.nonNullable);
   }
 
   R accept<R>(ExpressionVisitor<R> v) => v.visitMapLiteral(this);
@@ -4219,8 +4278,8 @@
     operand?.parent = this;
   }
 
-  DartType getStaticType(TypeEnvironment types) {
-    return types.unfutureType(operand.getStaticType(types));
+  DartType getStaticType(StaticTypeContext context) {
+    return context.typeEnvironment.unfutureType(operand.getStaticType(context));
   }
 
   R accept<R>(ExpressionVisitor<R> v) => v.visitAwaitExpression(this);
@@ -4254,7 +4313,7 @@
     function?.parent = this;
   }
 
-  DartType getStaticType(TypeEnvironment types) => function.functionType;
+  DartType getStaticType(StaticTypeContext context) => function.functionType;
 
   R accept<R>(ExpressionVisitor<R> v) => v.visitFunctionExpression(this);
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
@@ -4280,7 +4339,7 @@
     assert(constant != null);
   }
 
-  DartType getStaticType(TypeEnvironment types) => type;
+  DartType getStaticType(StaticTypeContext context) => type;
 
   R accept<R>(ExpressionVisitor<R> v) => v.visitConstantExpression(this);
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
@@ -4307,7 +4366,8 @@
     body?.parent = this;
   }
 
-  DartType getStaticType(TypeEnvironment types) => body.getStaticType(types);
+  DartType getStaticType(StaticTypeContext context) =>
+      body.getStaticType(context);
 
   R accept<R>(ExpressionVisitor<R> v) => v.visitLet(this);
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) => v.visitLet(this, arg);
@@ -4338,7 +4398,8 @@
     value?.parent = this;
   }
 
-  DartType getStaticType(TypeEnvironment types) => value.getStaticType(types);
+  DartType getStaticType(StaticTypeContext context) =>
+      value.getStaticType(context);
 
   R accept<R>(ExpressionVisitor<R> v) => v.visitBlockExpression(this);
   R accept1<R, A>(ExpressionVisitor1<R, A> v, A arg) =>
@@ -4379,8 +4440,9 @@
 
   LoadLibrary(this.import);
 
-  DartType getStaticType(TypeEnvironment types) {
-    return types.futureType(const DynamicType(), Nullability.legacy);
+  DartType getStaticType(StaticTypeContext context) {
+    return context.typeEnvironment
+        .futureType(const DynamicType(), context.nonNullable);
   }
 
   R accept<R>(ExpressionVisitor<R> v) => v.visitLoadLibrary(this);
@@ -4398,8 +4460,8 @@
 
   CheckLibraryIsLoaded(this.import);
 
-  DartType getStaticType(TypeEnvironment types) {
-    return types.coreTypes.objectLegacyRawType;
+  DartType getStaticType(StaticTypeContext context) {
+    return context.typeEnvironment.coreTypes.objectRawType(context.nonNullable);
   }
 
   R accept<R>(ExpressionVisitor<R> v) => v.visitCheckLibraryIsLoaded(this);
@@ -5216,6 +5278,10 @@
     flags = value ? (flags | FlagRequired) : (flags & ~FlagRequired);
   }
 
+  void clearAnnotations() {
+    annotations = const <Expression>[];
+  }
+
   void addAnnotation(Expression annotation) {
     if (annotations.isEmpty) {
       annotations = <Expression>[];
@@ -5703,8 +5769,7 @@
   /// type.
   FunctionType get withoutTypeParameters {
     if (typeParameters.isEmpty) return this;
-    return new FunctionType(
-        positionalParameters, returnType, Nullability.legacy,
+    return new FunctionType(positionalParameters, returnType, nullability,
         requiredParameterCount: requiredParameterCount,
         namedParameters: namedParameters,
         typedefType: null);
@@ -5738,7 +5803,6 @@
     hash = 0x3fffffff & (hash * 31 + requiredParameterCount);
     for (int i = 0; i < typeParameters.length; ++i) {
       TypeParameter parameter = typeParameters[i];
-      _temporaryHashCodeTable[parameter] = _temporaryHashCodeTable.length;
       hash = 0x3fffffff & (hash * 31 + parameter.bound.hashCode);
     }
     for (int i = 0; i < positionalParameters.length; ++i) {
@@ -5748,10 +5812,6 @@
       hash = 0x3fffffff & (hash * 31 + namedParameters[i].hashCode);
     }
     hash = 0x3fffffff & (hash * 31 + returnType.hashCode);
-    for (int i = 0; i < typeParameters.length; ++i) {
-      // Remove the type parameters from the scope again.
-      _temporaryHashCodeTable.remove(typeParameters[i]);
-    }
     hash = 0x3fffffff & (hash * 31 + nullability.index);
     return hash;
   }
@@ -5872,14 +5932,6 @@
   }
 }
 
-/// Stores the hash code of function type parameters while computing the hash
-/// code of a [FunctionType] object.
-///
-/// This ensures that distinct [FunctionType] objects get the same hash code
-/// if they represent the same type, even though their type parameters are
-/// represented by different objects.
-final Map<TypeParameter, int> _temporaryHashCodeTable = <TypeParameter, int>{};
-
 /// Reference to a type variable.
 ///
 /// A type variable has an optional bound because type promotion can change the
@@ -5912,6 +5964,35 @@
   TypeParameterType(this.parameter, this.typeParameterTypeNullability,
       [this.promotedBound]);
 
+  /// Creates an intersection type between a type parameter and [promotedBound].
+  TypeParameterType.intersection(
+      this.parameter, this.typeParameterTypeNullability, this.promotedBound);
+
+  /// Creates a type-parameter type to be used in alpha-renaming.
+  ///
+  /// The constructed type object is supposed to be used as a value in a
+  /// substitution map created to perform an alpha-renaming from parameter
+  /// [from] to parameter [to] on a generic type.  The resulting type-parameter
+  /// type is an occurrence of [to] as a type, but the nullability property is
+  /// derived from the bound of [from].  It allows to assign the bound to [to]
+  /// after the desired alpha-renaming is performed, which is often the case.
+  TypeParameterType.forAlphaRenaming(TypeParameter from, TypeParameter to)
+      : this(to, computeNullabilityFromBound(from));
+
+  /// Creates a type-parameter type with default nullability for the library.
+  ///
+  /// The nullability is computed as if the programmer omitted the modifier. It
+  /// means that in the opt-out libraries `Nullability.legacy` will be used, and
+  /// in opt-in libraries either `Nullability.nonNullable` or
+  /// `Nullability.undetermined` will be used, depending on the nullability of
+  /// the bound of [parameter].
+  TypeParameterType.withDefaultNullabilityForLibrary(
+      this.parameter, Library library) {
+    typeParameterTypeNullability = library.isNonNullableByDefault
+        ? computeNullabilityFromBound(parameter)
+        : Nullability.legacy;
+  }
+
   R accept<R>(DartTypeVisitor<R> v) => v.visitTypeParameterType(this);
   R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg) =>
       v.visitTypeParameterType(this, arg);
@@ -5926,7 +6007,10 @@
   }
 
   int get hashCode {
-    int hash = _temporaryHashCodeTable[parameter] ?? parameter.hashCode;
+    // TODO(johnniwinther): Since we use a unification strategy for function
+    //  type type parameter equality, we have to assume they can end up being
+    //  equal. Maybe we should change the equality strategy.
+    int hash = parameter.isFunctionTypeTypeParameter ? 0 : parameter.hashCode;
     int nullabilityHash = (0x33333333 >> nullability.index) ^ 0x33333333;
     hash = 0x3fffffff & (hash * 31 + (hash ^ nullabilityHash));
     hash = 0x3fffffff & (hash * 31 + (hash ^ promotedBound.hashCode));
@@ -6354,7 +6438,7 @@
   bool operator ==(Object other);
 
   /// Gets the type of this constant.
-  DartType getType(TypeEnvironment types);
+  DartType getType(StaticTypeContext context);
 
   Expression asExpression() {
     return new ConstantExpression(this);
@@ -6381,7 +6465,8 @@
   R accept<R>(ConstantVisitor<R> v) => v.visitNullConstant(this);
   R acceptReference<R>(Visitor<R> v) => v.visitNullConstantReference(this);
 
-  DartType getType(TypeEnvironment types) => types.nullType;
+  DartType getType(StaticTypeContext context) =>
+      context.typeEnvironment.nullType;
 }
 
 class BoolConstant extends PrimitiveConstant<bool> {
@@ -6391,7 +6476,8 @@
   R accept<R>(ConstantVisitor<R> v) => v.visitBoolConstant(this);
   R acceptReference<R>(Visitor<R> v) => v.visitBoolConstantReference(this);
 
-  DartType getType(TypeEnvironment types) => types.coreTypes.boolLegacyRawType;
+  DartType getType(StaticTypeContext context) =>
+      context.typeEnvironment.coreTypes.boolRawType(context.nonNullable);
 }
 
 /// An integer constant on a non-JS target.
@@ -6402,7 +6488,8 @@
   R accept<R>(ConstantVisitor<R> v) => v.visitIntConstant(this);
   R acceptReference<R>(Visitor<R> v) => v.visitIntConstantReference(this);
 
-  DartType getType(TypeEnvironment types) => types.coreTypes.intLegacyRawType;
+  DartType getType(StaticTypeContext context) =>
+      context.typeEnvironment.coreTypes.intRawType(context.nonNullable);
 }
 
 /// A double constant on a non-JS target or any numeric constant on a JS target.
@@ -6417,8 +6504,8 @@
   bool operator ==(Object other) =>
       other is DoubleConstant && identical(value, other.value);
 
-  DartType getType(TypeEnvironment types) =>
-      types.coreTypes.doubleLegacyRawType;
+  DartType getType(StaticTypeContext context) =>
+      context.typeEnvironment.coreTypes.doubleRawType(context.nonNullable);
 }
 
 class StringConstant extends PrimitiveConstant<String> {
@@ -6430,8 +6517,8 @@
   R accept<R>(ConstantVisitor<R> v) => v.visitStringConstant(this);
   R acceptReference<R>(Visitor<R> v) => v.visitStringConstantReference(this);
 
-  DartType getType(TypeEnvironment types) =>
-      types.coreTypes.stringLegacyRawType;
+  DartType getType(StaticTypeContext context) =>
+      context.typeEnvironment.coreTypes.stringRawType(context.nonNullable);
 }
 
 class SymbolConstant extends Constant {
@@ -6459,8 +6546,8 @@
           other.name == name &&
           other.libraryReference == libraryReference);
 
-  DartType getType(TypeEnvironment types) =>
-      types.coreTypes.symbolLegacyRawType;
+  DartType getType(StaticTypeContext context) =>
+      context.typeEnvironment.coreTypes.symbolRawType(context.nonNullable);
 }
 
 class MapConstant extends Constant {
@@ -6497,8 +6584,8 @@
           other.valueType == valueType &&
           listEquals(other.entries, entries));
 
-  DartType getType(TypeEnvironment types) =>
-      types.literalMapType(keyType, valueType);
+  DartType getType(StaticTypeContext context) => context.typeEnvironment
+      .literalMapType(keyType, valueType, context.nonNullable);
 }
 
 class ConstantMapEntry {
@@ -6544,8 +6631,8 @@
           other.typeArgument == typeArgument &&
           listEquals(other.entries, entries));
 
-  DartType getType(TypeEnvironment types) =>
-      types.literalListType(typeArgument);
+  DartType getType(StaticTypeContext context) => context.typeEnvironment
+      .literalListType(typeArgument, context.nonNullable);
 }
 
 class SetConstant extends Constant {
@@ -6578,7 +6665,8 @@
           other.typeArgument == typeArgument &&
           listEquals(other.entries, entries));
 
-  DartType getType(TypeEnvironment types) => types.literalSetType(typeArgument);
+  DartType getType(StaticTypeContext context) =>
+      context.typeEnvironment.literalSetType(typeArgument, context.nonNullable);
 }
 
 class InstanceConstant extends Constant {
@@ -6636,8 +6724,8 @@
             mapEquals(other.fieldValues, fieldValues));
   }
 
-  DartType getType(TypeEnvironment types) =>
-      new InterfaceType(classNode, Nullability.legacy, typeArguments);
+  DartType getType(StaticTypeContext context) =>
+      new InterfaceType(classNode, context.nonNullable, typeArguments);
 }
 
 class PartialInstantiationConstant extends Constant {
@@ -6669,8 +6757,8 @@
         listEquals(other.types, types);
   }
 
-  DartType getType(TypeEnvironment typeEnvironment) {
-    final FunctionType type = tearOffConstant.getType(typeEnvironment);
+  DartType getType(StaticTypeContext context) {
+    final FunctionType type = tearOffConstant.getType(context);
     final mapping = <TypeParameter, DartType>{};
     for (final parameter in type.typeParameters) {
       mapping[parameter] = types[mapping.length];
@@ -6709,7 +6797,7 @@
         other.procedureReference == procedureReference;
   }
 
-  FunctionType getType(TypeEnvironment types) =>
+  FunctionType getType(StaticTypeContext context) =>
       procedure.function.functionType;
 }
 
@@ -6734,7 +6822,8 @@
     return other is TypeLiteralConstant && other.type == type;
   }
 
-  DartType getType(TypeEnvironment types) => types.coreTypes.typeLegacyRawType;
+  DartType getType(StaticTypeContext context) =>
+      context.typeEnvironment.coreTypes.typeRawType(context.nonNullable);
 }
 
 class UnevaluatedConstant extends Constant {
@@ -6752,7 +6841,8 @@
   R acceptReference<R>(Visitor<R> v) =>
       v.visitUnevaluatedConstantReference(this);
 
-  DartType getType(TypeEnvironment types) => expression.getStaticType(types);
+  DartType getType(StaticTypeContext context) =>
+      expression.getStaticType(context);
 
   @override
   Expression asExpression() => expression;
@@ -7033,13 +7123,6 @@
   }
 }
 
-List<DartType> _getAsTypeArguments(List<TypeParameter> typeParameters) {
-  if (typeParameters.isEmpty) return const <DartType>[];
-  return new List<DartType>.generate(typeParameters.length,
-      (i) => new TypeParameterType(typeParameters[i], Nullability.legacy),
-      growable: false);
-}
-
 class _ChildReplacer extends Transformer {
   final TreeNode child;
   final TreeNode replacement;
@@ -7362,3 +7445,16 @@
   assert(nameParts[0].startsWith('_'));
   return nameParts[0].substring(1);
 }
+
+/// Computes a list of [typeParameters] taken as types.
+List<DartType> getAsTypeArguments(
+    List<TypeParameter> typeParameters, Library library) {
+  if (typeParameters.isEmpty) return const <DartType>[];
+  List<DartType> result =
+      new List<DartType>.filled(typeParameters.length, null, growable: false);
+  for (int i = 0; i < result.length; ++i) {
+    result[i] = new TypeParameterType.withDefaultNullabilityForLibrary(
+        typeParameters[i], library);
+  }
+  return result;
+}
diff --git a/pkg/kernel/lib/binary/ast_to_binary.dart b/pkg/kernel/lib/binary/ast_to_binary.dart
index 141f142..50ad84c 100644
--- a/pkg/kernel/lib/binary/ast_to_binary.dart
+++ b/pkg/kernel/lib/binary/ast_to_binary.dart
@@ -1338,7 +1338,7 @@
   void visitVariableGet(VariableGet node) {
     _variableIndexer ??= new VariableIndexer();
     int index = _variableIndexer[node.variable];
-    assert(index != null);
+    assert(index != null, "No index found for ${node.variable}");
     if (index & Tag.SpecializedPayloadMask == index &&
         node.promotedType == null) {
       writeByte(Tag.SpecializedVariableGet + index);
@@ -1357,7 +1357,7 @@
   void visitVariableSet(VariableSet node) {
     _variableIndexer ??= new VariableIndexer();
     int index = _variableIndexer[node.variable];
-    assert(index != null);
+    assert(index != null, "No index found for ${node.variable}");
     if (index & Tag.SpecializedPayloadMask == index) {
       writeByte(Tag.SpecializedVariableSet + index);
       writeOffset(node.fileOffset);
diff --git a/pkg/kernel/lib/clone.dart b/pkg/kernel/lib/clone.dart
index dc958c9..b4a2b9a 100644
--- a/pkg/kernel/lib/clone.dart
+++ b/pkg/kernel/lib/clone.dart
@@ -522,7 +522,7 @@
         newNode = new TypeParameter(node.name);
         typeParams[node] = newNode;
         typeSubstitution[node] =
-            new TypeParameterType(newNode, Nullability.legacy);
+            new TypeParameterType.forAlphaRenaming(node, newNode);
       }
     }
   }
diff --git a/pkg/kernel/lib/core_types.dart b/pkg/kernel/lib/core_types.dart
index 7524a6d..059e579 100644
--- a/pkg/kernel/lib/core_types.dart
+++ b/pkg/kernel/lib/core_types.dart
@@ -168,6 +168,10 @@
       new Map<Class, InterfaceType>.identity();
   final Map<Class, InterfaceType> _nonNullableRawTypes =
       new Map<Class, InterfaceType>.identity();
+  final Map<Class, InterfaceType> _thisInterfaceTypes =
+      new Map<Class, InterfaceType>.identity();
+  final Map<Typedef, TypedefType> _thisTypedefTypes =
+      new Map<Typedef, TypedefType>.identity();
 
   CoreTypes(Component component)
       : index = new LibraryIndex.coreLibraries(component);
@@ -1229,4 +1233,28 @@
             "Unsupported nullability $nullability on an InterfaceType.");
     }
   }
+
+  InterfaceType thisInterfaceType(Class klass, Nullability nullability) {
+    InterfaceType result = _thisInterfaceTypes[klass];
+    if (result == null) {
+      return _thisInterfaceTypes[klass] = new InterfaceType(klass, nullability,
+          getAsTypeArguments(klass.typeParameters, klass.enclosingLibrary));
+    }
+    if (result.nullability != nullability) {
+      return _thisInterfaceTypes[klass] = result.withNullability(nullability);
+    }
+    return result;
+  }
+
+  TypedefType thisTypedefType(Typedef typedef, Nullability nullability) {
+    TypedefType result = _thisTypedefTypes[typedef];
+    if (result == null) {
+      return _thisTypedefTypes[typedef] = new TypedefType(typedef, nullability,
+          getAsTypeArguments(typedef.typeParameters, typedef.enclosingLibrary));
+    }
+    if (result.nullability != nullability) {
+      return _thisTypedefTypes[typedef] = result.withNullability(nullability);
+    }
+    return result;
+  }
 }
diff --git a/pkg/kernel/lib/naive_type_checker.dart b/pkg/kernel/lib/naive_type_checker.dart
index 4f78734..619d2b8 100644
--- a/pkg/kernel/lib/naive_type_checker.dart
+++ b/pkg/kernel/lib/naive_type_checker.dart
@@ -148,8 +148,8 @@
       for (int i = 0; i < ownFunction.typeParameters.length; ++i) {
         var subParameter = ownFunction.typeParameters[i];
         var superParameter = superFunction.typeParameters[i];
-        typeParameterMap[subParameter] =
-            new TypeParameterType(superParameter, Nullability.legacy);
+        typeParameterMap[subParameter] = new TypeParameterType.forAlphaRenaming(
+            subParameter, superParameter);
       }
 
       ownSubstitution = Substitution.combine(
diff --git a/pkg/kernel/lib/src/bounds_checks.dart b/pkg/kernel/lib/src/bounds_checks.dart
index 0096017..a92c8d3 100644
--- a/pkg/kernel/lib/src/bounds_checks.dart
+++ b/pkg/kernel/lib/src/bounds_checks.dart
@@ -13,7 +13,6 @@
         InvalidType,
         NamedType,
         NeverType,
-        Nullability,
         TypeParameter,
         TypeParameterType,
         Typedef,
@@ -229,7 +228,7 @@
     // (https://github.com/dart-lang/sdk/blob/master/docs/language/informal/super-bounded-types.md).
     FunctionType functionType = type;
     FunctionType cloned = new FunctionType(functionType.positionalParameters,
-        functionType.returnType, Nullability.legacy,
+        functionType.returnType, functionType.nullability,
         namedParameters: functionType.namedParameters,
         typeParameters: functionType.typeParameters,
         requiredParameterCount: functionType.requiredParameterCount,
@@ -424,7 +423,7 @@
           isCovariant: isCovariant);
     }
     return new InterfaceType(
-        type.classNode, Nullability.legacy, replacedTypeArguments);
+        type.classNode, type.nullability, replacedTypeArguments);
   } else if (type is TypedefType && type.typedefNode.typeParameters != null) {
     List<DartType> replacedTypeArguments =
         new List<DartType>(type.typeArguments.length);
@@ -434,7 +433,7 @@
           isCovariant: isCovariant);
     }
     return new TypedefType(
-        type.typedefNode, Nullability.legacy, replacedTypeArguments);
+        type.typedefNode, type.nullability, replacedTypeArguments);
   } else if (type is FunctionType) {
     var replacedReturnType = convertSuperBoundedToRegularBounded(
         typeEnvironment, type.returnType,
@@ -456,7 +455,7 @@
               isCovariant: !isCovariant));
     }
     return new FunctionType(
-        replacedPositionalParameters, replacedReturnType, Nullability.legacy,
+        replacedPositionalParameters, replacedReturnType, type.nullability,
         namedParameters: replacedNamedParameters,
         typeParameters: type.typeParameters,
         requiredParameterCount: type.requiredParameterCount,
diff --git a/pkg/kernel/lib/src/future_or.dart b/pkg/kernel/lib/src/future_or.dart
index fd2d9d0..51f35cf 100644
--- a/pkg/kernel/lib/src/future_or.dart
+++ b/pkg/kernel/lib/src/future_or.dart
@@ -30,7 +30,7 @@
   if (a == Nullability.legacy || b == Nullability.legacy) {
     return Nullability.legacy;
   }
-  return Nullability.nonNullable;
+  return Nullability.nullable;
 }
 
 Nullability computeNullabilityOfFutureOr(
diff --git a/pkg/kernel/lib/src/hierarchy_based_type_environment.dart b/pkg/kernel/lib/src/hierarchy_based_type_environment.dart
index d41962f..5ef4e9f 100644
--- a/pkg/kernel/lib/src/hierarchy_based_type_environment.dart
+++ b/pkg/kernel/lib/src/hierarchy_based_type_environment.dart
@@ -4,7 +4,7 @@
 
 library kernel.hierarchy_based_type_environment;
 
-import '../ast.dart' show Class, InterfaceType;
+import '../ast.dart' show Class, InterfaceType, Member, Name;
 
 import '../class_hierarchy.dart' show ClassHierarchy;
 
@@ -22,4 +22,9 @@
   InterfaceType getTypeAsInstanceOf(InterfaceType type, Class superclass) {
     return hierarchy.getTypeAsInstanceOf(type, superclass);
   }
+
+  @override
+  Member getInterfaceMember(Class cls, Name name, {bool setter: false}) {
+    return hierarchy.getInterfaceMember(cls, name, setter: setter);
+  }
 }
diff --git a/pkg/kernel/lib/target/targets.dart b/pkg/kernel/lib/target/targets.dart
index 57673c6..afc3160 100644
--- a/pkg/kernel/lib/target/targets.dart
+++ b/pkg/kernel/lib/target/targets.dart
@@ -11,8 +11,11 @@
 
 class TargetFlags {
   final bool trackWidgetCreation;
+  final bool forceLateLoweringForTesting;
 
-  TargetFlags({this.trackWidgetCreation = false});
+  TargetFlags(
+      {this.trackWidgetCreation = false,
+      this.forceLateLoweringForTesting = false});
 }
 
 typedef Target _TargetBuilder(TargetFlags flags);
@@ -223,6 +226,13 @@
   /// literals (for const set literals).
   bool get supportsSetLiterals => true;
 
+  /// Whether late fields and variable are support by this target.
+  ///
+  /// If `false`, late fields and variables are lowered fields, getter, setters
+  /// etc. that provide equivalent semantics. See `pkg/kernel/nnbd_api.md` for
+  /// details.
+  bool get supportsLateFields;
+
   /// Builds an expression that instantiates an [Invocation] that can be passed
   /// to [noSuchMethod].
   Expression instantiateInvocation(CoreTypes coreTypes, Expression receiver,
@@ -268,8 +278,9 @@
 
 class NoneTarget extends Target {
   final TargetFlags flags;
+  final bool supportsLateFields;
 
-  NoneTarget(this.flags);
+  NoneTarget(this.flags, {this.supportsLateFields: true});
 
   String get name => 'none';
   List<String> get extraRequiredLibraries => <String>[];
diff --git a/pkg/kernel/lib/testing/mock_sdk_component.dart b/pkg/kernel/lib/testing/mock_sdk_component.dart
index f37b01c..9943d3e 100644
--- a/pkg/kernel/lib/testing/mock_sdk_component.dart
+++ b/pkg/kernel/lib/testing/mock_sdk_component.dart
@@ -17,7 +17,7 @@
   }
 
   var objectClass = addClass(coreLib, new Class(name: 'Object'));
-  var objectType = new InterfaceType(objectClass, Nullability.legacy);
+  var objectType = new InterfaceType(objectClass, coreLib.nonNullable);
 
   TypeParameter typeParam(String name, [DartType bound]) {
     return new TypeParameter(name, bound ?? objectType);
@@ -47,8 +47,9 @@
         class_('List', typeParameters: [
           T
         ], implementedTypes: [
-          new Supertype(
-              iterable, [new TypeParameterType(T, Nullability.legacy)])
+          new Supertype(iterable, [
+            new TypeParameterType.withDefaultNullabilityForLibrary(T, coreLib)
+          ])
         ]));
   }
   addClass(
diff --git a/pkg/kernel/lib/text/serializer_combinators.dart b/pkg/kernel/lib/text/serializer_combinators.dart
index e6db3ac..e166cb2 100644
--- a/pkg/kernel/lib/text/serializer_combinators.dart
+++ b/pkg/kernel/lib/text/serializer_combinators.dart
@@ -483,37 +483,39 @@
   }
 }
 
-/// Binds binders from one term in the other and adds them to the environment.
+/// Nested binding pattern that also binds binders from one term in the other.
 ///
-/// Serializes a [Tuple2] of [pattern] and [term], closing [term] over the
-/// binders found in [pattern].  The binders are added to the enclosing
-/// environment.
+/// Serializes a [Tuple2] of [pattern1] and [pattern2], closing [pattern2] over
+/// the binders found in [pattern1].  The binders from both [pattern1] and
+/// [pattern2] are added to the enclosing environment.
 class Rebind<P, T> extends TextSerializer<Tuple2<P, T>> {
-  final TextSerializer<P> pattern;
-  final TextSerializer<T> term;
+  final TextSerializer<P> pattern1;
+  final TextSerializer<T> pattern2;
 
-  const Rebind(this.pattern, this.term);
+  const Rebind(this.pattern1, this.pattern2);
 
   Tuple2<P, T> readFrom(Iterator<Object> stream, DeserializationState state) {
-    P first = pattern.readFrom(stream, state);
+    P first = pattern1.readFrom(stream, state);
     var closedState = new DeserializationState(
         new DeserializationEnvironment(state.environment)
           ..binders.addAll(state.environment.binders)
           ..close(),
         state.nameRoot);
-    T second = term.readFrom(stream, closedState);
+    T second = pattern2.readFrom(stream, closedState);
+    state.environment.binders.addAll(closedState.environment.binders);
     return new Tuple2(first, second);
   }
 
   void writeTo(
       StringBuffer buffer, Tuple2<P, T> tuple, SerializationState state) {
-    pattern.writeTo(buffer, tuple.first, state);
+    pattern1.writeTo(buffer, tuple.first, state);
     var closedState =
         new SerializationState(new SerializationEnvironment(state.environment)
           ..binders.addAll(state.environment.binders)
           ..close());
     buffer.write(' ');
-    term.writeTo(buffer, tuple.second, closedState);
+    pattern2.writeTo(buffer, tuple.second, closedState);
+    state.environment.binders.addAll(closedState.environment.binders);
   }
 }
 
diff --git a/pkg/kernel/lib/text/text_serializer.dart b/pkg/kernel/lib/text/text_serializer.dart
index 6aa0943..d2a9bb6 100644
--- a/pkg/kernel/lib/text/text_serializer.dart
+++ b/pkg/kernel/lib/text/text_serializer.dart
@@ -115,6 +115,8 @@
         ? "invoke-const-constructor"
         : "invoke-constructor";
   }
+
+  String visitFunctionExpression(FunctionExpression _) => "fun";
 }
 
 TextSerializer<InvalidExpression> invalidExpressionSerializer = new Wrapped(
@@ -691,6 +693,17 @@
       isConst: true);
 }
 
+TextSerializer<FunctionExpression> functionExpressionSerializer = new Wrapped(
+    unwrapFunctionExpression, wrapFunctionExpression, functionNodeSerializer);
+
+FunctionNode unwrapFunctionExpression(FunctionExpression expression) {
+  return expression.function;
+}
+
+FunctionExpression wrapFunctionExpression(FunctionNode node) {
+  return new FunctionExpression(node);
+}
+
 Case<Expression> expressionSerializer =
     new Case.uninitialized(const ExpressionTagger());
 
@@ -975,6 +988,7 @@
   String tag(Statement statement) => statement.accept(this);
 
   String visitExpressionStatement(ExpressionStatement _) => "expr";
+  String visitReturnStatement(ReturnStatement _) => "ret";
 }
 
 TextSerializer<ExpressionStatement> expressionStatementSerializer = new Wrapped(
@@ -988,9 +1002,231 @@
   return new ExpressionStatement(expression);
 }
 
+TextSerializer<ReturnStatement> returnStatementSerializer = new Wrapped(
+    unwrapReturnStatement, wrapReturnStatement, expressionSerializer);
+
+Expression unwrapReturnStatement(ReturnStatement statement) {
+  return statement.expression;
+}
+
+ReturnStatement wrapReturnStatement(Expression expression) {
+  return new ReturnStatement(expression);
+}
+
 Case<Statement> statementSerializer =
     new Case.uninitialized(const StatementTagger());
 
+class FunctionNodeTagger implements Tagger<FunctionNode> {
+  const FunctionNodeTagger();
+
+  String tag(FunctionNode node) {
+    switch (node.asyncMarker) {
+      case AsyncMarker.Async:
+        return "async";
+      case AsyncMarker.Sync:
+        return "sync";
+      case AsyncMarker.AsyncStar:
+        return "async-star";
+      case AsyncMarker.SyncStar:
+        return "sync-star";
+      case AsyncMarker.SyncYielding:
+        return "sync-yielding";
+    }
+    throw new UnsupportedError("${node.asyncMarker}");
+  }
+}
+
+TextSerializer<FunctionNode> syncFunctionNodeSerializer = new Wrapped(
+    unwrapFunctionNode,
+    wrapSyncFunctionNode,
+    new Bind(
+        new Rebind(
+            typeParametersSerializer,
+            new Tuple3Serializer(
+                new ListSerializer(new Binder(variableDeclarationSerializer,
+                    getVariableDeclarationName, setVariableDeclarationName)),
+                new ListSerializer(new Binder(variableDeclarationSerializer,
+                    getVariableDeclarationName, setVariableDeclarationName)),
+                new ListSerializer(new Binder(variableDeclarationSerializer,
+                    getVariableDeclarationName, setVariableDeclarationName)))),
+        new Tuple2Serializer(dartTypeSerializer, statementSerializer)));
+
+Tuple2<
+    Tuple2<
+        List<TypeParameter>,
+        Tuple3<List<VariableDeclaration>, List<VariableDeclaration>,
+            List<VariableDeclaration>>>,
+    Tuple2<DartType, Statement>> unwrapFunctionNode(FunctionNode node) {
+  return new Tuple2(
+      new Tuple2(
+          node.typeParameters,
+          new Tuple3(
+              node.positionalParameters.sublist(0, node.requiredParameterCount),
+              node.positionalParameters.sublist(node.requiredParameterCount),
+              node.namedParameters)),
+      new Tuple2(node.returnType, node.body));
+}
+
+FunctionNode wrapSyncFunctionNode(
+    Tuple2<
+            Tuple2<
+                List<TypeParameter>,
+                Tuple3<List<VariableDeclaration>, List<VariableDeclaration>,
+                    List<VariableDeclaration>>>,
+            Tuple2<DartType, Statement>>
+        tuple) {
+  return new FunctionNode(tuple.second.second,
+      typeParameters: tuple.first.first,
+      positionalParameters:
+          tuple.first.second.first + tuple.first.second.second,
+      namedParameters: tuple.first.second.third,
+      requiredParameterCount: tuple.first.second.first.length,
+      returnType: tuple.second.first,
+      asyncMarker: AsyncMarker.Sync);
+}
+
+TextSerializer<FunctionNode> asyncFunctionNodeSerializer = new Wrapped(
+    unwrapFunctionNode,
+    wrapAsyncFunctionNode,
+    new Bind(
+        new Rebind(
+            typeParametersSerializer,
+            new Tuple3Serializer(
+                new ListSerializer(new Binder(variableDeclarationSerializer,
+                    getVariableDeclarationName, setVariableDeclarationName)),
+                new ListSerializer(new Binder(variableDeclarationSerializer,
+                    getVariableDeclarationName, setVariableDeclarationName)),
+                new ListSerializer(new Binder(variableDeclarationSerializer,
+                    getVariableDeclarationName, setVariableDeclarationName)))),
+        new Tuple2Serializer(dartTypeSerializer, statementSerializer)));
+
+FunctionNode wrapAsyncFunctionNode(
+    Tuple2<
+            Tuple2<
+                List<TypeParameter>,
+                Tuple3<List<VariableDeclaration>, List<VariableDeclaration>,
+                    List<VariableDeclaration>>>,
+            Tuple2<DartType, Statement>>
+        tuple) {
+  return new FunctionNode(tuple.second.second,
+      typeParameters: tuple.first.first,
+      positionalParameters:
+          tuple.first.second.first + tuple.first.second.second,
+      namedParameters: tuple.first.second.third,
+      requiredParameterCount: tuple.first.second.first.length,
+      returnType: tuple.second.first,
+      asyncMarker: AsyncMarker.Async);
+}
+
+TextSerializer<FunctionNode> syncStarFunctionNodeSerializer = new Wrapped(
+    unwrapFunctionNode,
+    wrapSyncStarFunctionNode,
+    new Bind(
+        new Rebind(
+            typeParametersSerializer,
+            new Tuple3Serializer(
+                new ListSerializer(new Binder(variableDeclarationSerializer,
+                    getVariableDeclarationName, setVariableDeclarationName)),
+                new ListSerializer(new Binder(variableDeclarationSerializer,
+                    getVariableDeclarationName, setVariableDeclarationName)),
+                new ListSerializer(new Binder(variableDeclarationSerializer,
+                    getVariableDeclarationName, setVariableDeclarationName)))),
+        new Tuple2Serializer(dartTypeSerializer, statementSerializer)));
+
+FunctionNode wrapSyncStarFunctionNode(
+    Tuple2<
+            Tuple2<
+                List<TypeParameter>,
+                Tuple3<List<VariableDeclaration>, List<VariableDeclaration>,
+                    List<VariableDeclaration>>>,
+            Tuple2<DartType, Statement>>
+        tuple) {
+  return new FunctionNode(tuple.second.second,
+      typeParameters: tuple.first.first,
+      positionalParameters:
+          tuple.first.second.first + tuple.first.second.second,
+      namedParameters: tuple.first.second.third,
+      requiredParameterCount: tuple.first.second.first.length,
+      returnType: tuple.second.first,
+      asyncMarker: AsyncMarker.SyncStar);
+}
+
+TextSerializer<FunctionNode> asyncStarFunctionNodeSerializer = new Wrapped(
+    unwrapFunctionNode,
+    wrapAsyncStarFunctionNode,
+    new Bind(
+        new Rebind(
+            typeParametersSerializer,
+            new Tuple3Serializer(
+                new ListSerializer(new Binder(variableDeclarationSerializer,
+                    getVariableDeclarationName, setVariableDeclarationName)),
+                new ListSerializer(new Binder(variableDeclarationSerializer,
+                    getVariableDeclarationName, setVariableDeclarationName)),
+                new ListSerializer(new Binder(variableDeclarationSerializer,
+                    getVariableDeclarationName, setVariableDeclarationName)))),
+        new Tuple2Serializer(dartTypeSerializer, statementSerializer)));
+
+FunctionNode wrapAsyncStarFunctionNode(
+    Tuple2<
+            Tuple2<
+                List<TypeParameter>,
+                Tuple3<List<VariableDeclaration>, List<VariableDeclaration>,
+                    List<VariableDeclaration>>>,
+            Tuple2<DartType, Statement>>
+        tuple) {
+  return new FunctionNode(tuple.second.second,
+      typeParameters: tuple.first.first,
+      positionalParameters:
+          tuple.first.second.first + tuple.first.second.second,
+      namedParameters: tuple.first.second.third,
+      requiredParameterCount: tuple.first.second.first.length,
+      returnType: tuple.second.first,
+      asyncMarker: AsyncMarker.AsyncStar);
+}
+
+TextSerializer<FunctionNode> syncYieldingStarFunctionNodeSerializer =
+    new Wrapped(
+        unwrapFunctionNode,
+        wrapSyncYieldingFunctionNode,
+        new Bind(
+            new Rebind(
+                typeParametersSerializer,
+                new Tuple3Serializer(
+                    new ListSerializer(new Binder(
+                        variableDeclarationSerializer,
+                        getVariableDeclarationName,
+                        setVariableDeclarationName)),
+                    new ListSerializer(new Binder(
+                        variableDeclarationSerializer,
+                        getVariableDeclarationName,
+                        setVariableDeclarationName)),
+                    new ListSerializer(new Binder(
+                        variableDeclarationSerializer,
+                        getVariableDeclarationName,
+                        setVariableDeclarationName)))),
+            new Tuple2Serializer(dartTypeSerializer, statementSerializer)));
+
+FunctionNode wrapSyncYieldingFunctionNode(
+    Tuple2<
+            Tuple2<
+                List<TypeParameter>,
+                Tuple3<List<VariableDeclaration>, List<VariableDeclaration>,
+                    List<VariableDeclaration>>>,
+            Tuple2<DartType, Statement>>
+        tuple) {
+  return new FunctionNode(tuple.second.second,
+      typeParameters: tuple.first.first,
+      positionalParameters:
+          tuple.first.second.first + tuple.first.second.second,
+      namedParameters: tuple.first.second.third,
+      requiredParameterCount: tuple.first.second.first.length,
+      returnType: tuple.second.first,
+      asyncMarker: AsyncMarker.SyncYielding);
+}
+
+Case<FunctionNode> functionNodeSerializer =
+    new Case.uninitialized(const FunctionNodeTagger());
+
 void initializeSerializers() {
   expressionSerializer.tags.addAll([
     "string",
@@ -1036,6 +1272,7 @@
     "invoke-direct-method",
     "invoke-constructor",
     "invoke-const-constructor",
+    "fun",
   ]);
   expressionSerializer.serializers.addAll([
     stringLiteralSerializer,
@@ -1081,6 +1318,7 @@
     directMethodInvocationSerializer,
     constructorInvocationSerializer,
     constConstructorInvocationSerializer,
+    functionExpressionSerializer,
   ]);
   dartTypeSerializer.tags.addAll([
     "invalid",
@@ -1100,8 +1338,24 @@
   ]);
   statementSerializer.tags.addAll([
     "expr",
+    "ret",
   ]);
   statementSerializer.serializers.addAll([
     expressionStatementSerializer,
+    returnStatementSerializer,
+  ]);
+  functionNodeSerializer.tags.addAll([
+    "sync",
+    "async",
+    "sync-star",
+    "async-star",
+    "sync-yielding",
+  ]);
+  functionNodeSerializer.serializers.addAll([
+    syncFunctionNodeSerializer,
+    asyncFunctionNodeSerializer,
+    syncStarFunctionNodeSerializer,
+    asyncStarFunctionNodeSerializer,
+    syncYieldingStarFunctionNodeSerializer,
   ]);
 }
diff --git a/pkg/kernel/lib/transformations/async.dart b/pkg/kernel/lib/transformations/async.dart
index caa4ffd..ee85e03 100644
--- a/pkg/kernel/lib/transformations/async.dart
+++ b/pkg/kernel/lib/transformations/async.dart
@@ -5,6 +5,7 @@
 library kernel.transformations.async;
 
 import '../kernel.dart';
+import '../type_environment.dart';
 import 'continuation.dart';
 
 /// A transformer that introduces temporary variables for all subexpressions
@@ -80,6 +81,9 @@
 
   ExpressionLifter(this.continuationRewriter);
 
+  StaticTypeContext get _staticTypeContext =>
+      continuationRewriter.staticTypeContext;
+
   Block blockOf(List<Statement> statements) {
     return new Block(statements.reversed.toList());
   }
@@ -115,14 +119,16 @@
 
   // Name an expression by emitting an assignment to a temporary variable.
   VariableGet name(Expression expr) {
-    VariableDeclaration temp = allocateTemporary(nameIndex);
+    VariableDeclaration temp =
+        allocateTemporary(nameIndex, expr.getStaticType(_staticTypeContext));
     statements.add(new ExpressionStatement(new VariableSet(temp, expr)));
     return new VariableGet(temp);
   }
 
-  VariableDeclaration allocateTemporary(int index) {
+  VariableDeclaration allocateTemporary(int index, DartType type) {
     for (var i = variables.length; i <= index; i++) {
-      variables.add(new VariableDeclaration(":async_temporary_${i}"));
+      variables
+          .add(new VariableDeclaration(":async_temporary_${i}", type: type));
     }
     return variables[index];
   }
@@ -332,7 +338,10 @@
     // so any statements it emits occur after in the accumulated list (that is,
     // so they occur before in the corresponding block).
     var rightBody = blockOf(rightStatements);
-    var result = allocateTemporary(nameIndex);
+    var result = allocateTemporary(
+        nameIndex,
+        _staticTypeContext.typeEnvironment.coreTypes
+            .boolRawType(_staticTypeContext.nonNullable));
     rightBody.addStatement(new ExpressionStatement(new VariableSet(
         result,
         new MethodInvocation(expr.right, new Name('=='),
@@ -394,7 +403,7 @@
     // } else {
     //   t = [right];
     // }
-    var result = allocateTemporary(nameIndex);
+    var result = allocateTemporary(nameIndex, expr.staticType);
     var thenBody = blockOf(thenStatements);
     var otherwiseBody = blockOf(otherwiseStatements);
     thenBody.addStatement(
@@ -416,7 +425,20 @@
   TreeNode visitAwaitExpression(AwaitExpression expr) {
     final R = continuationRewriter;
     var shouldName = seenAwait;
-    var result = new VariableGet(asyncResult);
+    var type = expr.getStaticType(_staticTypeContext);
+    Expression result = new VariableGet(asyncResult);
+    if (type is! DynamicType) {
+      int fileOffset = expr.operand.fileOffset;
+      if (fileOffset == TreeNode.noOffset) {
+        fileOffset = expr.fileOffset;
+      }
+      assert(fileOffset != TreeNode.noOffset);
+      result = new StaticInvocation(
+          continuationRewriter.helper.unsafeCast,
+          new Arguments(<Expression>[result], types: <DartType>[type])
+            ..fileOffset = fileOffset)
+        ..fileOffset = fileOffset;
+    }
 
     // The statements are in reverse order, so name the result first if
     // necessary and then add the two other statements in reverse.
@@ -504,8 +526,8 @@
   }
 
   visitFunctionNode(FunctionNode node) {
-    var nestedRewriter =
-        new RecursiveContinuationRewriter(continuationRewriter.helper);
+    var nestedRewriter = new RecursiveContinuationRewriter(
+        continuationRewriter.helper, _staticTypeContext);
     return node.accept(nestedRewriter);
   }
 
diff --git a/pkg/kernel/lib/transformations/continuation.dart b/pkg/kernel/lib/transformations/continuation.dart
index d77ba82..71bba56 100644
--- a/pkg/kernel/lib/transformations/continuation.dart
+++ b/pkg/kernel/lib/transformations/continuation.dart
@@ -8,6 +8,7 @@
 
 import '../ast.dart';
 import '../core_types.dart';
+import '../type_environment.dart';
 import '../visitor.dart';
 
 import 'async.dart';
@@ -25,26 +26,35 @@
   static String stackTraceVar(int depth) => ':stack_trace$depth';
 }
 
-void transformLibraries(CoreTypes coreTypes, List<Library> libraries,
+void transformLibraries(
+    TypeEnvironment typeEnvironment, List<Library> libraries,
     {bool productMode}) {
-  var helper = new HelperNodes.fromCoreTypes(coreTypes, productMode);
-  var rewriter = new RecursiveContinuationRewriter(helper);
+  var helper =
+      new HelperNodes.fromCoreTypes(typeEnvironment.coreTypes, productMode);
+  var rewriter = new RecursiveContinuationRewriter(
+      helper, new StatefulStaticTypeContext.stacked(typeEnvironment));
   for (var library in libraries) {
     rewriter.rewriteLibrary(library);
   }
 }
 
-Component transformComponent(CoreTypes coreTypes, Component component,
+Component transformComponent(
+    TypeEnvironment typeEnvironment, Component component,
     {bool productMode}) {
-  var helper = new HelperNodes.fromCoreTypes(coreTypes, productMode);
-  var rewriter = new RecursiveContinuationRewriter(helper);
+  var helper =
+      new HelperNodes.fromCoreTypes(typeEnvironment.coreTypes, productMode);
+  var rewriter = new RecursiveContinuationRewriter(
+      helper, new StatefulStaticTypeContext.stacked(typeEnvironment));
   return rewriter.rewriteComponent(component);
 }
 
-Procedure transformProcedure(CoreTypes coreTypes, Procedure procedure,
+Procedure transformProcedure(
+    TypeEnvironment typeEnvironment, Procedure procedure,
     {bool productMode}) {
-  var helper = new HelperNodes.fromCoreTypes(coreTypes, productMode);
-  var rewriter = new RecursiveContinuationRewriter(helper);
+  var helper =
+      new HelperNodes.fromCoreTypes(typeEnvironment.coreTypes, productMode);
+  var rewriter = new RecursiveContinuationRewriter(
+      helper, new StatefulStaticTypeContext.stacked(typeEnvironment));
   return rewriter.visitProcedure(procedure);
 }
 
@@ -57,7 +67,9 @@
   final VariableDeclaration asyncContextVariable =
       new VariableDeclaration(ContinuationVariables.awaitContextVar);
 
-  RecursiveContinuationRewriter(this.helper);
+  StatefulStaticTypeContext staticTypeContext;
+
+  RecursiveContinuationRewriter(this.helper, this.staticTypeContext);
 
   Component rewriteComponent(Component node) {
     return node.accept<TreeNode>(this);
@@ -67,22 +79,53 @@
     return node.accept<TreeNode>(this);
   }
 
-  visitProcedure(Procedure node) {
-    return node.isAbstract ? node : super.visitProcedure(node);
+  visitField(Field node) {
+    staticTypeContext.enterMember(node);
+    final result = super.visitField(node);
+    staticTypeContext.leaveMember(node);
+    return result;
   }
 
+  visitConstructor(Constructor node) {
+    staticTypeContext.enterMember(node);
+    final result = super.visitConstructor(node);
+    staticTypeContext.leaveMember(node);
+    return result;
+  }
+
+  @override
+  visitProcedure(Procedure node) {
+    staticTypeContext.enterMember(node);
+    final result = node.isAbstract ? node : super.visitProcedure(node);
+    staticTypeContext.leaveMember(node);
+    return result;
+  }
+
+  @override
+  visitLibrary(Library node) {
+    staticTypeContext.enterLibrary(node);
+    Library result = super.visitLibrary(node);
+    staticTypeContext.leaveLibrary(node);
+    return result;
+  }
+
+  @override
   visitFunctionNode(FunctionNode node) {
     switch (node.asyncMarker) {
       case AsyncMarker.Sync:
       case AsyncMarker.SyncYielding:
-        node.transformChildren(new RecursiveContinuationRewriter(helper));
+        node.transformChildren(
+            new RecursiveContinuationRewriter(helper, staticTypeContext));
         return node;
       case AsyncMarker.SyncStar:
-        return new SyncStarFunctionRewriter(helper, node).rewrite();
+        return new SyncStarFunctionRewriter(helper, node, staticTypeContext)
+            .rewrite();
       case AsyncMarker.Async:
-        return new AsyncFunctionRewriter(helper, node).rewrite();
+        return new AsyncFunctionRewriter(helper, node, staticTypeContext)
+            .rewrite();
       case AsyncMarker.AsyncStar:
-        return new AsyncStarFunctionRewriter(helper, node).rewrite();
+        return new AsyncStarFunctionRewriter(helper, node, staticTypeContext)
+            .rewrite();
       default:
         return null;
     }
@@ -97,8 +140,9 @@
   int capturedTryDepth = 0; // Deepest yield point within a try-block.
   int capturedCatchDepth = 0; // Deepest yield point within a catch-block.
 
-  ContinuationRewriterBase(HelperNodes helper, this.enclosingFunction)
-      : super(helper);
+  ContinuationRewriterBase(HelperNodes helper, this.enclosingFunction,
+      StatefulStaticTypeContext staticTypeContext)
+      : super(helper, staticTypeContext);
 
   /// Given a container [type], which is an instantiation of the given
   /// [containerClass] extract its element type.
@@ -175,23 +219,27 @@
             new VariableDeclaration(ContinuationVariables.stackTraceVar(depth)),
           ]);
 
-  List<VariableDeclaration> variableDeclarations() =>
-      [asyncJumpVariable, asyncContextVariable]
-        ..addAll(createCapturedTryVariables())
-        ..addAll(createCapturedCatchVariables());
+  List<VariableDeclaration> variableDeclarations() {
+    asyncJumpVariable.type = staticTypeContext.typeEnvironment.coreTypes
+        .intRawType(staticTypeContext.nonNullable);
+    return [asyncJumpVariable, asyncContextVariable]
+      ..addAll(createCapturedTryVariables())
+      ..addAll(createCapturedCatchVariables());
+  }
 }
 
 class SyncStarFunctionRewriter extends ContinuationRewriterBase {
   final VariableDeclaration iteratorVariable;
 
-  SyncStarFunctionRewriter(HelperNodes helper, FunctionNode enclosingFunction)
+  SyncStarFunctionRewriter(HelperNodes helper, FunctionNode enclosingFunction,
+      StatefulStaticTypeContext staticTypeContext)
       : iteratorVariable = new VariableDeclaration(':iterator')
-          ..type =
-              new InterfaceType(helper.syncIteratorClass, Nullability.legacy, [
+          ..type = new InterfaceType(
+              helper.syncIteratorClass, staticTypeContext.nullable, [
             ContinuationRewriterBase.elementTypeFrom(
                 helper.iterableClass, enclosingFunction.returnType)
           ]),
-        super(helper, enclosingFunction);
+        super(helper, enclosingFunction, staticTypeContext);
 
   FunctionNode rewrite() {
     // :sync_op(:iterator) {
@@ -286,8 +334,9 @@
 
   ExpressionLifter expressionRewriter;
 
-  AsyncRewriterBase(HelperNodes helper, FunctionNode enclosingFunction)
-      : super(helper, enclosingFunction) {}
+  AsyncRewriterBase(HelperNodes helper, FunctionNode enclosingFunction,
+      StaticTypeContext staticTypeContext)
+      : super(helper, enclosingFunction, staticTypeContext) {}
 
   void setupAsyncContinuations(List<Statement> statements) {
     expressionRewriter = new ExpressionLifter(this);
@@ -751,7 +800,7 @@
               new Arguments(<Expression>[new VariableGet(streamVariable)],
                   types: [valueVariable.type])),
           type: new InterfaceType(helper.streamIteratorClass,
-              Nullability.legacy, [valueVariable.type]));
+              staticTypeContext.nullable, [valueVariable.type]));
 
       // await :for-iterator.moveNext()
       var condition = new AwaitExpression(new MethodInvocation(
@@ -905,8 +954,9 @@
 class AsyncStarFunctionRewriter extends AsyncRewriterBase {
   VariableDeclaration controllerVariable;
 
-  AsyncStarFunctionRewriter(HelperNodes helper, FunctionNode enclosingFunction)
-      : super(helper, enclosingFunction);
+  AsyncStarFunctionRewriter(HelperNodes helper, FunctionNode enclosingFunction,
+      StaticTypeContext staticTypeContext)
+      : super(helper, enclosingFunction, staticTypeContext);
 
   FunctionNode rewrite() {
     var statements = <Statement>[];
@@ -916,7 +966,7 @@
     // _AsyncStarStreamController<T> :controller;
     controllerVariable = new VariableDeclaration(":controller",
         type: new InterfaceType(helper.asyncStarStreamControllerClass,
-            Nullability.legacy, [elementType]));
+            staticTypeContext.nullable, [elementType]));
     statements.add(controllerVariable);
 
     // dynamic :controller_stream;
@@ -1022,8 +1072,9 @@
   VariableDeclaration completerVariable;
   VariableDeclaration returnVariable;
 
-  AsyncFunctionRewriter(HelperNodes helper, FunctionNode enclosingFunction)
-      : super(helper, enclosingFunction);
+  AsyncFunctionRewriter(HelperNodes helper, FunctionNode enclosingFunction,
+      StaticTypeContext staticTypeContext)
+      : super(helper, enclosingFunction, staticTypeContext);
 
   FunctionNode rewrite() {
     var statements = <Statement>[];
@@ -1037,12 +1088,12 @@
     if (valueType == const DynamicType()) {
       valueType = elementTypeFromReturnType(helper.futureOrClass);
     }
-    final DartType returnType = new InterfaceType(
-        helper.futureOrClass, Nullability.legacy, <DartType>[valueType]);
+    final DartType returnType = new InterfaceType(helper.futureOrClass,
+        staticTypeContext.nullable, <DartType>[valueType]);
     var completerTypeArguments = <DartType>[valueType];
 
     final completerType = new InterfaceType(helper.asyncAwaitCompleterClass,
-        Nullability.legacy, completerTypeArguments);
+        staticTypeContext.nonNullable, completerTypeArguments);
     // final Completer<T> :async_completer = new _AsyncAwaitCompleter<T>();
     completerVariable = new VariableDeclaration(":async_completer",
         initializer: new ConstructorInvocation(
@@ -1150,6 +1201,7 @@
   final Member syncIteratorCurrent;
   final Member syncIteratorYieldEachIterable;
   final Class boolClass;
+  final Procedure unsafeCast;
 
   bool productMode;
 
@@ -1189,7 +1241,8 @@
       this.syncIteratorCurrent,
       this.syncIteratorYieldEachIterable,
       this.boolClass,
-      this.productMode);
+      this.productMode,
+      this.unsafeCast);
 
   factory HelperNodes.fromCoreTypes(CoreTypes coreTypes, bool productMode) {
     return new HelperNodes._(
@@ -1228,6 +1281,7 @@
         coreTypes.syncIteratorCurrent,
         coreTypes.syncIteratorYieldEachIterable,
         coreTypes.boolClass,
-        productMode);
+        productMode,
+        coreTypes.index.getTopLevelMember('dart:_internal', 'unsafeCast'));
   }
 }
diff --git a/pkg/kernel/lib/transformations/track_widget_constructor_locations.dart b/pkg/kernel/lib/transformations/track_widget_constructor_locations.dart
index c2289a5..46c0f61 100644
--- a/pkg/kernel/lib/transformations/track_widget_constructor_locations.dart
+++ b/pkg/kernel/lib/transformations/track_widget_constructor_locations.dart
@@ -129,6 +129,12 @@
 
   WidgetCreatorTracker _tracker;
 
+  /// Library that contains the transformed call sites.
+  ///
+  /// The transformation of the call sites is affected by the NNBD opt-in status
+  /// of the library.
+  Library _currentLibrary;
+
   _WidgetCallSiteTransformer(
       {@required Class widgetClass,
       @required Class locationClass,
@@ -271,11 +277,26 @@
       location,
       parameterLocations: new ListLiteral(
         parameterLocations,
-        typeArgument: _locationClass.thisType,
+        typeArgument:
+            new InterfaceType(_locationClass, _currentLibrary.nonNullable),
         isConst: true,
       ),
     );
   }
+
+  void enterLibrary(Library library) {
+    assert(
+        _currentLibrary == null,
+        "Attempting to enter library '${library.fileUri}' "
+        "without having exited library '${_currentLibrary.fileUri}'.");
+    _currentLibrary = library;
+  }
+
+  void exitLibrary() {
+    assert(_currentLibrary != null,
+        "Attempting to exit a library without having entered one.");
+    _currentLibrary = null;
+  }
 }
 
 /// Rewrites all widget constructors and constructor invocations to add a
@@ -345,7 +366,8 @@
       _hasCreationLocationClass.enclosingLibrary,
     );
     final Field locationField = new Field(fieldName,
-        type: new InterfaceType(_locationClass, Nullability.legacy),
+        type: new InterfaceType(
+            _locationClass, clazz.enclosingLibrary.nonNullable),
         isFinal: true,
         reference: clazz.reference.canonicalName
             ?.getChildFromFieldWithName(fieldName)
@@ -365,7 +387,8 @@
       ));
       final VariableDeclaration variable = new VariableDeclaration(
         _creationLocationParameterName,
-        type: _locationClass.thisType,
+        type: new InterfaceType(
+            _locationClass, clazz.enclosingLibrary.nonNullable),
       );
       if (!_maybeAddNamedParameter(constructor.function, variable)) {
         return;
@@ -458,7 +481,9 @@
       if (library.isExternal) {
         continue;
       }
+      callsiteTransformer.enterLibrary(library);
       library.transformChildren(callsiteTransformer);
+      callsiteTransformer.exitLibrary();
     }
   }
 
@@ -497,10 +522,10 @@
       if (procedure.isFactory) {
         _maybeAddNamedParameter(
           procedure.function,
-          new VariableDeclaration(
-            _creationLocationParameterName,
-            type: _locationClass.thisType,
-          ),
+          new VariableDeclaration(_creationLocationParameterName,
+              type: new InterfaceType(
+                  _locationClass, clazz.enclosingLibrary.nonNullable),
+              isRequired: clazz.enclosingLibrary.isNonNullableByDefault),
         );
       }
     }
@@ -521,9 +546,10 @@
       }
 
       final VariableDeclaration variable = new VariableDeclaration(
-        _creationLocationParameterName,
-        type: _locationClass.thisType,
-      );
+          _creationLocationParameterName,
+          type: new InterfaceType(
+              _locationClass, clazz.enclosingLibrary.nonNullable),
+          isRequired: clazz.enclosingLibrary.isNonNullableByDefault);
       if (_hasNamedParameter(
           constructor.function, _creationLocationParameterName)) {
         // Constructor was already rewritten. TODO(jacobr): is this case actually hit?
diff --git a/pkg/kernel/lib/type_algebra.dart b/pkg/kernel/lib/type_algebra.dart
index e7b810b..87ac4a0 100644
--- a/pkg/kernel/lib/type_algebra.dart
+++ b/pkg/kernel/lib/type_algebra.dart
@@ -114,8 +114,8 @@
       growable: true);
   var map = <TypeParameter, DartType>{};
   for (int i = 0; i < typeParameters.length; ++i) {
-    map[typeParameters[i]] =
-        new TypeParameterType(freshParameters[i], Nullability.legacy);
+    map[typeParameters[i]] = new TypeParameterType.forAlphaRenaming(
+        typeParameters[i], freshParameters[i]);
   }
   CloneVisitor cloner;
   for (int i = 0; i < typeParameters.length; ++i) {
@@ -293,7 +293,7 @@
   const _NullSubstitution();
 
   DartType getSubstitute(TypeParameter parameter, bool upperBound) {
-    return new TypeParameterType(parameter, Nullability.legacy);
+    return new TypeParameterType.forAlphaRenaming(parameter, parameter);
   }
 
   @override
@@ -388,7 +388,7 @@
 
   TypeParameter freshTypeParameter(TypeParameter node) {
     var fresh = new TypeParameter(node.name);
-    substitution[node] = new TypeParameterType(fresh, Nullability.legacy);
+    substitution[node] = new TypeParameterType.forAlphaRenaming(node, fresh);
     fresh.bound = visit(node.bound);
     if (node.defaultType != null) {
       fresh.defaultType = visit(node.defaultType);
@@ -719,8 +719,8 @@
       var rightInstance = <TypeParameter, DartType>{};
       for (int i = 0; i < type1.typeParameters.length; ++i) {
         var instantiator = new TypeParameter(type1.typeParameters[i].name);
-        var instantiatorType =
-            new TypeParameterType(instantiator, Nullability.legacy);
+        var instantiatorType = new TypeParameterType.forAlphaRenaming(
+            type1.typeParameters[i], instantiator);
         leftInstance[type1.typeParameters[i]] = instantiatorType;
         rightInstance[type2.typeParameters[i]] = instantiatorType;
         _universallyQuantifiedVariables.add(instantiator);
diff --git a/pkg/kernel/lib/type_checker.dart b/pkg/kernel/lib/type_checker.dart
index 53eec114..ba3e192 100644
--- a/pkg/kernel/lib/type_checker.dart
+++ b/pkg/kernel/lib/type_checker.dart
@@ -18,6 +18,8 @@
   final ClassHierarchy hierarchy;
   final bool ignoreSdk;
   TypeEnvironment environment;
+  Library currentLibrary;
+  InterfaceType currentThisType;
 
   TypeChecker(this.coreTypes, this.hierarchy, {this.ignoreSdk: true})
       : environment = new TypeEnvironment(coreTypes, hierarchy);
@@ -34,9 +36,11 @@
     }
     var visitor = new TypeCheckingVisitor(this, environment, hierarchy);
     for (var library in component.libraries) {
+      currentLibrary = library;
       if (ignoreSdk && library.importUri.scheme == 'dart') continue;
       for (var class_ in library.classes) {
-        environment.thisType = class_.thisType;
+        currentThisType = coreTypes.thisInterfaceType(
+            class_, class_.enclosingLibrary.nonNullable);
         for (var field in class_.fields) {
           visitor.visitField(field);
         }
@@ -47,13 +51,14 @@
           visitor.visitProcedure(procedure);
         }
       }
-      environment.thisType = null;
+      currentThisType = null;
       for (var procedure in library.procedures) {
         visitor.visitProcedure(procedure);
       }
       for (var field in library.fields) {
         visitor.visitField(field);
       }
+      currentLibrary = null;
     }
   }
 
@@ -117,7 +122,13 @@
   final ClassHierarchy hierarchy;
 
   CoreTypes get coreTypes => environment.coreTypes;
-  Class get currentClass => environment.thisType.classNode;
+  Library get currentLibrary => checker.currentLibrary;
+  Class get currentClass => checker.currentThisType.classNode;
+  InterfaceType get currentThisType => checker.currentThisType;
+
+  DartType currentReturnType;
+  DartType currentYieldType;
+  AsyncMarker currentAsyncMarker = AsyncMarker.Sync;
 
   TypeCheckingVisitor(this.checker, this.environment, this.hierarchy);
 
@@ -181,26 +192,26 @@
   }
 
   visitConstructor(Constructor node) {
-    environment.returnType = null;
-    environment.yieldType = null;
+    currentReturnType = null;
+    currentYieldType = null;
     node.initializers.forEach(visitInitializer);
     handleFunctionNode(node.function);
   }
 
   visitProcedure(Procedure node) {
-    environment.returnType = _getInternalReturnType(node.function);
-    environment.yieldType = _getYieldType(node.function);
+    currentReturnType = _getInternalReturnType(node.function);
+    currentYieldType = _getYieldType(node.function);
     handleFunctionNode(node.function);
   }
 
   visitRedirectingFactoryConstructor(RedirectingFactoryConstructor node) {
-    environment.returnType = null;
-    environment.yieldType = null;
+    currentReturnType = null;
+    currentYieldType = null;
   }
 
   void handleFunctionNode(FunctionNode node) {
-    var oldAsyncMarker = environment.currentAsyncMarker;
-    environment.currentAsyncMarker = node.asyncMarker;
+    var oldAsyncMarker = currentAsyncMarker;
+    currentAsyncMarker = node.asyncMarker;
     node.positionalParameters
         .skip(node.requiredParameterCount)
         .forEach(handleOptionalParameter);
@@ -208,17 +219,17 @@
     if (node.body != null) {
       visitStatement(node.body);
     }
-    environment.currentAsyncMarker = oldAsyncMarker;
+    currentAsyncMarker = oldAsyncMarker;
   }
 
   void handleNestedFunctionNode(FunctionNode node) {
-    var oldReturn = environment.returnType;
-    var oldYield = environment.yieldType;
-    environment.returnType = _getInternalReturnType(node);
-    environment.yieldType = _getYieldType(node);
+    var oldReturn = currentReturnType;
+    var oldYield = currentYieldType;
+    currentReturnType = _getInternalReturnType(node);
+    currentYieldType = _getYieldType(node);
     handleFunctionNode(node);
-    environment.returnType = oldReturn;
-    environment.yieldType = oldYield;
+    currentReturnType = oldReturn;
+    currentYieldType = oldYield;
   }
 
   void handleOptionalParameter(VariableDeclaration parameter) {
@@ -427,7 +438,7 @@
     handleCall(arguments, target.function.thisFunctionType,
         typeParameters: class_.typeParameters);
     return new InterfaceType(
-        target.enclosingClass, Nullability.legacy, arguments.types);
+        target.enclosingClass, currentLibrary.nonNullable, arguments.types);
   }
 
   @override
@@ -516,7 +527,8 @@
       node.expressions[i] =
           checkAndDowncastExpression(node.expressions[i], node.typeArgument);
     }
-    return environment.literalListType(node.typeArgument);
+    return environment.literalListType(
+        node.typeArgument, currentLibrary.nonNullable);
   }
 
   @override
@@ -525,7 +537,8 @@
       node.expressions[i] =
           checkAndDowncastExpression(node.expressions[i], node.typeArgument);
     }
-    return environment.literalSetType(node.typeArgument);
+    return environment.literalSetType(
+        node.typeArgument, currentLibrary.nonNullable);
   }
 
   @override
@@ -543,7 +556,8 @@
       entry.key = checkAndDowncastExpression(entry.key, node.keyType);
       entry.value = checkAndDowncastExpression(entry.value, node.valueType);
     }
-    return environment.literalMapType(node.keyType, node.valueType);
+    return environment.literalMapType(
+        node.keyType, node.valueType, currentLibrary.nonNullable);
   }
 
   DartType handleDynamicCall(DartType receiver, Arguments arguments) {
@@ -693,7 +707,8 @@
 
   @override
   DartType visitListConcatenation(ListConcatenation node) {
-    DartType type = environment.literalListType(node.typeArgument);
+    DartType type = environment.literalListType(
+        node.typeArgument, currentLibrary.nonNullable);
     for (Expression part in node.lists) {
       DartType partType = visitExpression(part);
       checkAssignable(node, type, partType);
@@ -703,7 +718,8 @@
 
   @override
   DartType visitSetConcatenation(SetConcatenation node) {
-    DartType type = environment.literalSetType(node.typeArgument);
+    DartType type = environment.literalSetType(
+        node.typeArgument, currentLibrary.nonNullable);
     for (Expression part in node.sets) {
       DartType partType = visitExpression(part);
       checkAssignable(node, type, partType);
@@ -713,7 +729,8 @@
 
   @override
   DartType visitMapConcatenation(MapConcatenation node) {
-    DartType type = environment.literalMapType(node.keyType, node.valueType);
+    DartType type = environment.literalMapType(
+        node.keyType, node.valueType, currentLibrary.nonNullable);
     for (Expression part in node.maps) {
       DartType partType = visitExpression(part);
       checkAssignable(node, type, partType);
@@ -731,7 +748,7 @@
       checkAssignable(node, fieldType, valueType);
     });
     return new InterfaceType(
-        node.classNode, Nullability.legacy, node.typeArguments);
+        node.classNode, currentLibrary.nonNullable, node.typeArguments);
   }
 
   @override
@@ -747,8 +764,8 @@
   @override
   DartType visitSuperMethodInvocation(SuperMethodInvocation node) {
     if (node.interfaceTarget == null) {
-      checkUnresolvedInvocation(environment.thisType, node);
-      return handleDynamicCall(environment.thisType, node.arguments);
+      checkUnresolvedInvocation(currentThisType, node);
+      return handleDynamicCall(currentThisType, node.arguments);
     } else {
       return handleCall(node.arguments, node.interfaceTarget.getterType,
           receiver: getSuperReceiverType(node.interfaceTarget));
@@ -758,7 +775,7 @@
   @override
   DartType visitSuperPropertyGet(SuperPropertyGet node) {
     if (node.interfaceTarget == null) {
-      checkUnresolvedInvocation(environment.thisType, node);
+      checkUnresolvedInvocation(currentThisType, node);
       return const DynamicType();
     } else {
       var receiver = getSuperReceiverType(node.interfaceTarget);
@@ -777,7 +794,7 @@
           receiver.substituteType(node.interfaceTarget.setterType,
               contravariant: true));
     } else {
-      checkUnresolvedInvocation(environment.thisType, node);
+      checkUnresolvedInvocation(currentThisType, node);
     }
     return value;
   }
@@ -789,7 +806,7 @@
 
   @override
   DartType visitThisExpression(ThisExpression node) {
-    return environment.thisType;
+    return currentThisType;
   }
 
   @override
@@ -817,7 +834,8 @@
 
   @override
   DartType visitLoadLibrary(LoadLibrary node) {
-    return environment.futureType(const DynamicType(), Nullability.legacy);
+    return environment.futureType(
+        const DynamicType(), currentLibrary.nonNullable);
   }
 
   @override
@@ -952,14 +970,14 @@
   @override
   visitReturnStatement(ReturnStatement node) {
     if (node.expression != null) {
-      if (environment.returnType == null) {
+      if (currentReturnType == null) {
         fail(node, 'Return of a value from void method');
       } else {
         var type = visitExpression(node.expression);
-        if (environment.currentAsyncMarker == AsyncMarker.Async) {
+        if (currentAsyncMarker == AsyncMarker.Async) {
           type = environment.unfutureType(type);
         }
-        checkAssignable(node.expression, type, environment.returnType);
+        checkAssignable(node.expression, type, currentReturnType);
       }
     }
   }
@@ -1005,7 +1023,7 @@
   @override
   visitYieldStatement(YieldStatement node) {
     if (node.isYieldStar) {
-      Class container = environment.currentAsyncMarker == AsyncMarker.AsyncStar
+      Class container = currentAsyncMarker == AsyncMarker.AsyncStar
           ? coreTypes.streamClass
           : coreTypes.iterableClass;
       var type = visitExpression(node.expression);
@@ -1013,14 +1031,14 @@
           ? hierarchy.getTypeAsInstanceOf(type, container)
           : null;
       if (asContainer != null) {
-        checkAssignable(node.expression, asContainer.typeArguments[0],
-            environment.yieldType);
+        checkAssignable(
+            node.expression, asContainer.typeArguments[0], currentYieldType);
       } else {
         fail(node.expression, '$type is not an instance of $container');
       }
     } else {
       node.expression =
-          checkAndDowncastExpression(node.expression, environment.yieldType);
+          checkAndDowncastExpression(node.expression, currentYieldType);
     }
   }
 
diff --git a/pkg/kernel/lib/type_environment.dart b/pkg/kernel/lib/type_environment.dart
index 028df5e..dabc13c 100644
--- a/pkg/kernel/lib/type_environment.dart
+++ b/pkg/kernel/lib/type_environment.dart
@@ -17,12 +17,6 @@
 abstract class TypeEnvironment extends SubtypeTester {
   final CoreTypes coreTypes;
 
-  InterfaceType thisType;
-
-  DartType returnType;
-  DartType yieldType;
-  AsyncMarker currentAsyncMarker = AsyncMarker.Sync;
-
   /// An error handler for use in debugging, or `null` if type errors should not
   /// be tolerated.  See [typeError].
   ErrorHandler errorHandler;
@@ -44,33 +38,33 @@
   InterfaceType get nullType => coreTypes.nullType;
   InterfaceType get functionLegacyRawType => coreTypes.functionLegacyRawType;
 
-  InterfaceType literalListType(DartType elementType) {
+  InterfaceType literalListType(DartType elementType, Nullability nullability) {
     return new InterfaceType(
-        coreTypes.listClass, Nullability.legacy, <DartType>[elementType]);
+        coreTypes.listClass, nullability, <DartType>[elementType]);
   }
 
-  InterfaceType literalSetType(DartType elementType) {
+  InterfaceType literalSetType(DartType elementType, Nullability nullability) {
     return new InterfaceType(
-        coreTypes.setClass, Nullability.legacy, <DartType>[elementType]);
+        coreTypes.setClass, nullability, <DartType>[elementType]);
   }
 
-  InterfaceType literalMapType(DartType key, DartType value) {
+  InterfaceType literalMapType(
+      DartType key, DartType value, Nullability nullability) {
     return new InterfaceType(
-        coreTypes.mapClass, Nullability.legacy, <DartType>[key, value]);
+        coreTypes.mapClass, nullability, <DartType>[key, value]);
   }
 
-  InterfaceType iterableType(DartType type) {
+  InterfaceType iterableType(DartType type, Nullability nullability) {
     return new InterfaceType(
-        coreTypes.iterableClass, Nullability.legacy, <DartType>[type]);
+        coreTypes.iterableClass, nullability, <DartType>[type]);
   }
 
-  InterfaceType streamType(DartType type) {
+  InterfaceType streamType(DartType type, Nullability nullability) {
     return new InterfaceType(
-        coreTypes.streamClass, Nullability.legacy, <DartType>[type]);
+        coreTypes.streamClass, nullability, <DartType>[type]);
   }
 
-  InterfaceType futureType(DartType type,
-      [Nullability nullability = Nullability.legacy]) {
+  InterfaceType futureType(DartType type, Nullability nullability) {
     return new InterfaceType(
         coreTypes.futureClass, nullability, <DartType>[type]);
   }
@@ -159,6 +153,17 @@
 
     return coreTypes.numRawType(type1.nullability);
   }
+
+  /// Returns the possibly abstract interface member of [class_] with the given
+  /// [name].
+  ///
+  /// If [setter] is `false`, only fields, methods, and getters with that name
+  /// will be found.  If [setter] is `true`, only non-final fields and setters
+  /// will be found.
+  ///
+  /// If multiple members with that name are inherited and not overridden, the
+  /// member from the first declared supertype is returned.
+  Member getInterfaceMember(Class cls, Name name, {bool setter: false});
 }
 
 /// Tri-state logical result of a nullability-aware subtype check.
@@ -235,6 +240,16 @@
   /// types `List<int>?` and `List<num>*`.
   factory IsSubtypeOf.basedSolelyOnNullabilities(
       DartType subtype, DartType supertype) {
+    if (subtype is InvalidType) {
+      if (supertype is InvalidType) {
+        return const IsSubtypeOf.always();
+      }
+      return const IsSubtypeOf.onlyIfIgnoringNullabilities();
+    }
+    if (supertype is InvalidType) {
+      return const IsSubtypeOf.onlyIfIgnoringNullabilities();
+    }
+
     if (subtype.isPotentiallyNullable && supertype.isPotentiallyNonNullable) {
       return const IsSubtypeOf.onlyIfIgnoringNullabilities();
     }
@@ -332,8 +347,7 @@
   Class get objectClass;
   Class get functionClass;
   Class get futureOrClass;
-  InterfaceType futureType(DartType type,
-      [Nullability nullability = Nullability.legacy]);
+  InterfaceType futureType(DartType type, Nullability nullability);
 
   static List<Object> typeChecks;
 
@@ -560,8 +574,8 @@
       for (int i = 0; i < subtype.typeParameters.length; ++i) {
         var subParameter = subtype.typeParameters[i];
         var superParameter = supertype.typeParameters[i];
-        substitution[subParameter] =
-            new TypeParameterType(superParameter, Nullability.legacy);
+        substitution[subParameter] = new TypeParameterType.forAlphaRenaming(
+            subParameter, superParameter);
       }
       for (int i = 0; i < subtype.typeParameters.length; ++i) {
         var subParameter = subtype.typeParameters[i];
@@ -615,3 +629,266 @@
         .and(new IsSubtypeOf.basedSolelyOnNullabilities(subtype, supertype));
   }
 }
+
+/// Context object needed for computing `Expression.getStaticType`.
+///
+/// The [StaticTypeContext] provides access to the [TypeEnvironment] and the
+/// current 'this type' as well as determining the nullability state of the
+/// enclosing library.
+// TODO(johnniwinther): Support static type caching through [StaticTypeContext].
+class StaticTypeContext {
+  /// The [TypeEnvironment] used for the static type computation.
+  ///
+  /// This provides access to the core types and the class hierarchy.
+  final TypeEnvironment typeEnvironment;
+
+  /// The library in which the static type is computed.
+  ///
+  /// The `library.isNonNullableByDefault` property is used to determine the
+  /// nullabilities of the static types.
+  final Library _library;
+
+  /// The static type of a `this` expression.
+  final InterfaceType thisType;
+
+  /// Creates a static type context for computing static types in the body
+  /// of [member].
+  StaticTypeContext(Member member, this.typeEnvironment)
+      : _library = member.enclosingLibrary,
+        thisType = member.enclosingClass?.getThisType(
+            typeEnvironment.coreTypes, member.enclosingLibrary.nonNullable);
+
+  /// Creates a static type context for computing static types of annotations
+  /// in [library].
+  StaticTypeContext.forAnnotations(this._library, this.typeEnvironment)
+      : thisType = null;
+
+  /// The [Nullability] used for non-nullable types.
+  ///
+  /// For opt out libraries this is [Nullability.legacy].
+  Nullability get nonNullable => _library.nonNullable;
+
+  /// The [Nullability] used for nullable types.
+  ///
+  /// For opt out libraries this is [Nullability.legacy].
+  Nullability get nullable => _library.nullable;
+}
+
+/// Implementation of [StaticTypeContext] that update its state when entering
+/// and leaving libraries and members.
+abstract class StatefulStaticTypeContext implements StaticTypeContext {
+  @override
+  final TypeEnvironment typeEnvironment;
+
+  /// Creates a [StatefulStaticTypeContext] that supports entering multiple
+  /// libraries and/or members successively.
+  factory StatefulStaticTypeContext.stacked(TypeEnvironment typeEnvironment) =
+      _StackedStatefulStaticTypeContext;
+
+  /// Creates a [StatefulStaticTypeContext] that only supports entering one
+  /// library and/or member at a time.
+  factory StatefulStaticTypeContext.flat(TypeEnvironment typeEnvironment) =
+      _FlatStatefulStaticTypeContext;
+
+  StatefulStaticTypeContext._internal(this.typeEnvironment);
+
+  /// Updates the [nonNullable] and [thisType] to match static type context for
+  /// the member [node].
+  ///
+  /// This should be called before computing static types on the body of member
+  /// [node].
+  void enterMember(Member node);
+
+  /// Reverts the [nonNullable] and [thisType] values to the previous state.
+  ///
+  /// This should be called after computing static types on the body of member
+  /// [node].
+  void leaveMember(Member node);
+
+  /// Updates the [nonNullable] and [thisType] to match static type context for
+  /// the library [node].
+  ///
+  /// This should be called before computing static types on annotations in the
+  /// library [node].
+  void enterLibrary(Library node);
+
+  /// Reverts the [nonNullable] and [thisType] values to the previous state.
+  ///
+  /// This should be called after computing static types on annotations in the
+  /// library [node].
+  void leaveLibrary(Library node);
+}
+
+/// Implementation of [StatefulStaticTypeContext] that only supports entering
+/// one library and/or at a time.
+class _FlatStatefulStaticTypeContext extends StatefulStaticTypeContext {
+  Library _currentLibrary;
+  Member _currentMember;
+
+  _FlatStatefulStaticTypeContext(TypeEnvironment typeEnvironment)
+      : super._internal(typeEnvironment);
+
+  @override
+  Library get _library {
+    Library library = _currentLibrary ?? _currentMember?.enclosingLibrary;
+    assert(library != null,
+        "No library currently associated with StaticTypeContext.");
+    return library;
+  }
+
+  @override
+  InterfaceType get thisType {
+    assert(_currentMember != null,
+        "No member currently associated with StaticTypeContext.");
+    return _currentMember?.enclosingClass?.getThisType(
+        typeEnvironment.coreTypes, _currentMember.enclosingLibrary.nonNullable);
+  }
+
+  @override
+  Nullability get nonNullable => _library?.nonNullable;
+
+  @override
+  Nullability get nullable => _library?.nullable;
+
+  /// Updates the [nonNullable] and [thisType] to match static type context for
+  /// the member [node].
+  ///
+  /// This should be called before computing static types on the body of member
+  /// [node].
+  ///
+  /// Only one member can be entered at a time.
+  @override
+  void enterMember(Member node) {
+    assert(_currentMember == null, "Already in context of $_currentMember");
+    _currentMember = node;
+  }
+
+  /// Reverts the [nonNullable] and [thisType] values to the previous state.
+  ///
+  /// This should be called after computing static types on the body of member
+  /// [node].
+  @override
+  void leaveMember(Member node) {
+    assert(
+        _currentMember == node,
+        "Inconsistent static type context stack: "
+        "Trying to leave $node but current is ${_currentMember}.");
+    _currentMember = null;
+  }
+
+  /// Updates the [nonNullable] and [thisType] to match static type context for
+  /// the library [node].
+  ///
+  /// This should be called before computing static types on annotations in the
+  /// library [node].
+  ///
+  /// Only one library can be entered at a time, and not while a member is
+  /// entered through [enterMember].
+  @override
+  void enterLibrary(Library node) {
+    assert(_currentLibrary == null, "Already in context of $_currentLibrary");
+    assert(_currentMember == null, "Already in context of $_currentMember");
+    _currentLibrary = node;
+  }
+
+  /// Reverts the [nonNullable] and [thisType] values to the previous state.
+  ///
+  /// This should be called after computing static types on annotations in the
+  /// library [node].
+  @override
+  void leaveLibrary(Library node) {
+    assert(
+        _currentLibrary == node,
+        "Inconsistent static type context stack: "
+        "Trying to leave $node but current is ${_currentLibrary}.");
+    _currentLibrary = null;
+  }
+}
+
+/// Implementation of [StatefulStaticTypeContext] that use a stack to change state
+/// when entering and leaving libraries and members.
+class _StackedStatefulStaticTypeContext extends StatefulStaticTypeContext {
+  final List<_StaticTypeContextState> _contextStack =
+      <_StaticTypeContextState>[];
+
+  _StackedStatefulStaticTypeContext(TypeEnvironment typeEnvironment)
+      : super._internal(typeEnvironment);
+
+  @override
+  Library get _library {
+    assert(_contextStack.isNotEmpty,
+        "No library currently associated with StaticTypeContext.");
+    return _contextStack.last._library;
+  }
+
+  @override
+  InterfaceType get thisType {
+    assert(_contextStack.isNotEmpty,
+        "No this type currently associated with StaticTypeContext.");
+    return _contextStack.last._thisType;
+  }
+
+  @override
+  Nullability get nonNullable => _library?.nonNullable;
+
+  @override
+  Nullability get nullable => _library?.nullable;
+
+  /// Updates the [library] and [thisType] to match static type context for
+  /// the member [node].
+  ///
+  /// This should be called before computing static types on the body of member
+  /// [node].
+  @override
+  void enterMember(Member node) {
+    _contextStack.add(new _StaticTypeContextState(
+        node,
+        node.enclosingLibrary,
+        node.enclosingClass?.getThisType(
+            typeEnvironment.coreTypes, node.enclosingLibrary.nonNullable)));
+  }
+
+  /// Reverts the [library] and [thisType] values to the previous state.
+  ///
+  /// This should be called after computing static types on the body of member
+  /// [node].
+  @override
+  void leaveMember(Member node) {
+    _StaticTypeContextState state = _contextStack.removeLast();
+    assert(
+        state._node == node,
+        "Inconsistent static type context stack: "
+        "Trying to leave $node but current is ${state._node}.");
+  }
+
+  /// Updates the [library] and [thisType] to match static type context for
+  /// the library [node].
+  ///
+  /// This should be called before computing static types on annotations in the
+  /// library [node].
+  @override
+  void enterLibrary(Library node) {
+    _contextStack.add(new _StaticTypeContextState(node, node, null));
+  }
+
+  /// Reverts the [library] and [thisType] values to the previous state.
+  ///
+  /// This should be called after computing static types on annotations in the
+  /// library [node].
+  @override
+  void leaveLibrary(Library node) {
+    _StaticTypeContextState state = _contextStack.removeLast();
+    assert(
+        state._node == node,
+        "Inconsistent static type context stack: "
+        "Trying to leave $node but current is ${state._node}.");
+  }
+}
+
+class _StaticTypeContextState {
+  final TreeNode _node;
+  final Library _library;
+  final InterfaceType _thisType;
+
+  _StaticTypeContextState(this._node, this._library, this._thisType);
+}
diff --git a/pkg/kernel/lib/verifier.dart b/pkg/kernel/lib/verifier.dart
index f47c3e7..c37656d 100644
--- a/pkg/kernel/lib/verifier.dart
+++ b/pkg/kernel/lib/verifier.dart
@@ -5,6 +5,7 @@
 
 import 'ast.dart';
 import 'transformations/flags.dart';
+import 'type_environment.dart' show StatefulStaticTypeContext, TypeEnvironment;
 
 void verifyComponent(Component component, {bool isOutline, bool afterConst}) {
   VerifyingVisitor.check(component,
@@ -764,6 +765,65 @@
   }
 }
 
+void verifyGetStaticType(TypeEnvironment env, Component component) {
+  component.accept(new VerifyGetStaticType(env));
+}
+
+class VerifyGetStaticType extends RecursiveVisitor {
+  final TypeEnvironment env;
+  Member currentMember;
+  final StatefulStaticTypeContext _staticTypeContext;
+
+  VerifyGetStaticType(this.env)
+      : _staticTypeContext = new StatefulStaticTypeContext.stacked(env);
+
+  @override
+  visitLibrary(Library node) {
+    _staticTypeContext.enterLibrary(node);
+    super.visitLibrary(node);
+    _staticTypeContext.leaveLibrary(node);
+  }
+
+  @override
+  visitField(Field node) {
+    currentMember = node;
+    _staticTypeContext.enterMember(node);
+    super.visitField(node);
+    _staticTypeContext.leaveMember(node);
+    currentMember = node;
+  }
+
+  @override
+  visitProcedure(Procedure node) {
+    currentMember = node;
+    _staticTypeContext.enterMember(node);
+    super.visitProcedure(node);
+    _staticTypeContext.leaveMember(node);
+    currentMember = node;
+  }
+
+  @override
+  visitConstructor(Constructor node) {
+    currentMember = node;
+    _staticTypeContext.enterMember(node);
+    super.visitConstructor(node);
+    _staticTypeContext.leaveMember(node);
+    currentMember = null;
+  }
+
+  @override
+  defaultExpression(Expression node) {
+    try {
+      node.getStaticType(_staticTypeContext);
+    } catch (_) {
+      print('Error in $currentMember in ${currentMember?.fileUri}: '
+          '$node (${node.runtimeType})');
+      rethrow;
+    }
+    super.defaultExpression(node);
+  }
+}
+
 class CheckParentPointers extends Visitor {
   static void check(TreeNode node) {
     node.accept(new CheckParentPointers(node.parent));
diff --git a/pkg/kernel/test/text_serializer_from_kernel_nodes_test.dart b/pkg/kernel/test/text_serializer_from_kernel_nodes_test.dart
index ad2354e..7eb39c7 100644
--- a/pkg/kernel/test/text_serializer_from_kernel_nodes_test.dart
+++ b/pkg/kernel/test/text_serializer_from_kernel_nodes_test.dart
@@ -59,9 +59,9 @@
               type: const DynamicType(), initializer: new IntLiteral(42));
           return new ExpressionStatement(new Let(x, new VariableGet(x)));
         }(),
-        expectation: ""
-            "(expr (let (var \"x^0\" (dynamic) (int 42) ())"
-            " (get-var \"x^0\" _)))"),
+        expectation: ''
+            '(expr (let (var "x^0" (dynamic) (int 42) ())'
+            ' (get-var "x^0" _)))'),
     new TestCase(
         name: "let dynamic x = 42 in let Bottom x^0 = null in x;",
         node: () {
@@ -72,10 +72,10 @@
           return new ExpressionStatement(new Let(outterLetVar,
               new Let(innerLetVar, new VariableGet(outterLetVar))));
         }(),
-        expectation: ""
-            "(expr (let (var \"x^0\" (dynamic) (int 42) ())"
-            " (let (var \"x^1\" (bottom) (null) ())"
-            " (get-var \"x^0\" _))))"),
+        expectation: ''
+            '(expr (let (var "x^0" (dynamic) (int 42) ())'
+            ' (let (var "x^1" (bottom) (null) ())'
+            ' (get-var "x^0" _))))'),
     new TestCase(
         name: "let dynamic x = 42 in let Bottom x^0 = null in x^0;",
         node: () {
@@ -86,17 +86,17 @@
           return new ExpressionStatement(new Let(outterLetVar,
               new Let(innerLetVar, new VariableGet(innerLetVar))));
         }(),
-        expectation: ""
-            "(expr (let (var \"x^0\" (dynamic) (int 42) ())"
-            " (let (var \"x^1\" (bottom) (null) ())"
-            " (get-var \"x^1\" _))))"),
+        expectation: ''
+            '(expr (let (var "x^0" (dynamic) (int 42) ())'
+            ' (let (var "x^1" (bottom) (null) ())'
+            ' (get-var "x^1" _))))'),
     () {
       VariableDeclaration x =
           new VariableDeclaration("x", type: const DynamicType());
       return new TestCase(
           name: "/* suppose: dynamic x; */ x = 42;",
           node: new ExpressionStatement(new VariableSet(x, new IntLiteral(42))),
-          expectation: "(expr (set-var \"x^0\" (int 42)))",
+          expectation: '(expr (set-var "x^0" (int 42)))',
           serializationState: new SerializationState(
             new SerializationEnvironment(null)
               ..addBinder(x, "x^0")
@@ -118,8 +118,8 @@
       return new TestCase(
           name: "/* suppose top-level: dynamic field; */ field;",
           node: new ExpressionStatement(new StaticGet(field)),
-          expectation: ""
-              "(expr (get-static \"package:foo/bar.dart::@fields::field\"))",
+          expectation: ''
+              '(expr (get-static "package:foo/bar.dart::@fields::field"))',
           serializationState: new SerializationState(null),
           deserializationState: new DeserializationState(null, component.root));
     }(),
@@ -134,9 +134,9 @@
           name: "/* suppose top-level: dynamic field; */ field = 1;",
           node:
               new ExpressionStatement(new StaticSet(field, new IntLiteral(1))),
-          expectation: ""
-              "(expr"
-              " (set-static \"package:foo/bar.dart::@fields::field\" (int 1)))",
+          expectation: ''
+              '(expr'
+              ' (set-static "package:foo/bar.dart::@fields::field" (int 1)))',
           serializationState: new SerializationState(null),
           deserializationState: new DeserializationState(null, component.root));
     }(),
@@ -159,9 +159,9 @@
               topLevelProcedure.reference,
               new Arguments(<Expression>[new IntLiteral(42)]),
               isConst: false)),
-          expectation: ""
-              "(expr (invoke-static \"package:foo/bar.dart::@methods::foo\""
-              " () ((int 42)) ()))",
+          expectation: ''
+              '(expr (invoke-static "package:foo/bar.dart::@methods::foo"'
+              ' () ((int 42)) ()))',
           serializationState: new SerializationState(null),
           deserializationState: new DeserializationState(null, component.root));
     }(),
@@ -183,10 +183,10 @@
           node: new ExpressionStatement(new StaticInvocation.byReference(
               factoryConstructor.reference, new Arguments([]),
               isConst: true)),
-          expectation: ""
-              "(expr (invoke-const-static"
-              " \"package:foo/bar.dart::A::@factories::foo\""
-              " () () ()))",
+          expectation: ''
+              '(expr (invoke-const-static'
+              ' "package:foo/bar.dart::A::@factories::foo"'
+              ' () () ()))',
           serializationState: new SerializationState(null),
           deserializationState: new DeserializationState(null, component.root));
     }(),
@@ -205,9 +205,9 @@
           name: "/* suppose A {dynamic field;} A x; */ x.{A::field};",
           node: new ExpressionStatement(new DirectPropertyGet.byReference(
               new VariableGet(x), field.reference)),
-          expectation: ""
-              "(expr (get-direct-prop (get-var \"x^0\" _)"
-              " \"package:foo/bar.dart::A::@fields::field\"))",
+          expectation: ''
+              '(expr (get-direct-prop (get-var "x^0" _)'
+              ' "package:foo/bar.dart::A::@fields::field"))',
           serializationState:
               new SerializationState(new SerializationEnvironment(null)
                 ..addBinder(x, "x^0")
@@ -233,9 +233,9 @@
           name: "/* suppose A {dynamic field;} A x; */ x.{A::field} = 42;",
           node: new ExpressionStatement(new DirectPropertySet.byReference(
               new VariableGet(x), field.reference, new IntLiteral(42))),
-          expectation: ""
-              "(expr (set-direct-prop (get-var \"x^0\" _)"
-              " \"package:foo/bar.dart::A::@fields::field\" (int 42)))",
+          expectation: ''
+              '(expr (set-direct-prop (get-var "x^0" _)'
+              ' "package:foo/bar.dart::A::@fields::field" (int 42)))',
           serializationState:
               new SerializationState(new SerializationEnvironment(null)
                 ..addBinder(x, "x^0")
@@ -263,10 +263,10 @@
           name: "/* suppose A {foo() {...}} A x; */ x.{A::foo}();",
           node: new ExpressionStatement(new DirectMethodInvocation.byReference(
               new VariableGet(x), method.reference, new Arguments([]))),
-          expectation: ""
-              "(expr (invoke-direct-method (get-var \"x^0\" _)"
-              " \"package:foo/bar.dart::A::@methods::foo\""
-              " () () ()))",
+          expectation: ''
+              '(expr (invoke-direct-method (get-var "x^0" _)'
+              ' "package:foo/bar.dart::A::@methods::foo"'
+              ' () () ()))',
           serializationState:
               new SerializationState(new SerializationEnvironment(null)
                 ..addBinder(x, "x^0")
@@ -291,10 +291,10 @@
           name: "/* suppose A {A.foo();} */ new A();",
           node: new ExpressionStatement(new ConstructorInvocation.byReference(
               constructor.reference, new Arguments([]))),
-          expectation: ""
-              "(expr (invoke-constructor"
-              " \"package:foo/bar.dart::A::@constructors::foo\""
-              " () () ()))",
+          expectation: ''
+              '(expr (invoke-constructor'
+              ' "package:foo/bar.dart::A::@constructors::foo"'
+              ' () () ()))',
           serializationState: new SerializationState(null),
           deserializationState: new DeserializationState(null, component.root));
     }(),
@@ -313,10 +313,10 @@
           node: new ExpressionStatement(new ConstructorInvocation.byReference(
               constructor.reference, new Arguments([]),
               isConst: true)),
-          expectation: ""
-              "(expr (invoke-const-constructor"
-              " \"package:foo/bar.dart::A::@constructors::foo\""
-              " () () ()))",
+          expectation: ''
+              '(expr (invoke-const-constructor'
+              ' "package:foo/bar.dart::A::@constructors::foo"'
+              ' () () ()))',
           serializationState: new SerializationState(null),
           deserializationState: new DeserializationState(null, component.root));
     }(),
@@ -338,10 +338,36 @@
               new TypeParameterType(outterParam, Nullability.legacy),
               Nullability.legacy,
               typeParameters: [outterParam]))),
-          expectation: ""
-              "(expr (type (-> (\"T^0\") ((dynamic)) ((dynamic)) "
-              "((-> (\"T^1\") ((dynamic)) ((dynamic)) () () () "
-              "(par \"T^1\" _))) () () (par \"T^0\" _))))",
+          expectation: ''
+              '(expr (type (-> ("T^0") ((dynamic)) ((dynamic)) '
+              '((-> ("T^1") ((dynamic)) ((dynamic)) () () () '
+              '(par "T^1" _))) () () (par "T^0" _))))',
+          serializationState:
+              new SerializationState(new SerializationEnvironment(null)),
+          deserializationState: new DeserializationState(
+              new DeserializationEnvironment(null), null));
+    }(),
+    () {
+      TypeParameter t =
+          new TypeParameter("T", const DynamicType(), const DynamicType());
+      VariableDeclaration t1 = new VariableDeclaration("t1",
+          type: new TypeParameterType(t, Nullability.legacy));
+      VariableDeclaration t2 = new VariableDeclaration("t2",
+          type: new TypeParameterType(t, Nullability.legacy));
+      return new TestCase(
+          name: "/* <T>(T t1, [T t2]) => t1; */",
+          node: new ExpressionStatement(new FunctionExpression(new FunctionNode(
+              new ReturnStatement(new VariableGet(t1)),
+              typeParameters: [t],
+              positionalParameters: [t1, t2],
+              requiredParameterCount: 1,
+              namedParameters: [],
+              returnType: new TypeParameterType(t, Nullability.legacy),
+              asyncMarker: AsyncMarker.Sync))),
+          expectation: ''
+              '(expr (fun (sync ("T^0") ((dynamic)) ((dynamic)) ((var '
+              '"t1^1" (par "T^0" _) _ ())) ((var "t2^2" (par "T^0" _) '
+              '_ ())) () (par "T^0" _) (ret (get-var "t1^1" _)))))',
           serializationState:
               new SerializationState(new SerializationEnvironment(null)),
           deserializationState: new DeserializationState(
diff --git a/pkg/kernel/test/text_serializer_test.dart b/pkg/kernel/test/text_serializer_test.dart
index ae80281..fadf1e2 100644
--- a/pkg/kernel/test/text_serializer_test.dart
+++ b/pkg/kernel/test/text_serializer_test.dart
@@ -35,61 +35,61 @@
 void test() {
   List<String> failures = [];
   List<String> tests = [
-    "(get-prop (int 0) (public \"hashCode\"))",
-    "(get-super (public \"hashCode\"))",
-    "(invoke-method (int 0) (public \"foo\") () ((int 1) (int 2)) ())",
-    "(invoke-method (int 0) (public \"foo\") ((dynamic) (void)) "
-        "((int 1) (int 2)) (\"others\" (list (dynamic) ((int 3) (int 4)))))",
-    "(let (var \"x^0\" (dynamic) (int 0) ()) (null))",
-    "(let (var \"x^0\" (dynamic) _ ()) (null))",
-    "(let (const \"x^0\" (dynamic) (int 0) ()) (null))",
-    "(let (const \"x^0\" (dynamic) _ ()) (null))",
-    "(let (final \"x^0\" (dynamic) (int 0) ()) (null))",
-    "(let (final \"x^0\" (dynamic) _ ()) (null))",
-    "(string \"Hello, 'string'!\")",
-    "(string \"Hello, \\\"string\\\"!\")",
-    "(string \"Yeah nah yeah, here is\\nthis really long string haiku\\n"
-        "blowing in the wind\\n\")",
-    "(int 42)",
-    "(int 0)",
-    "(int -1001)",
-    "(double 3.14159)",
-    "(bool true)",
-    "(bool false)",
-    "(null)",
-    "(invalid \"You can't touch this\")",
-    "(not (bool true))",
-    "(&& (bool true) (bool false))",
-    "(|| (&& (bool true) (not (bool true))) (bool true))",
-    "(concat ((string \"The opposite of \") (int 3) "
-        "(string \" is \") (int 7)))",
-    "(symbol \"unquote-splicing\")",
-    "(this)",
-    "(rethrow)",
-    "(throw (string \"error\"))",
-    "(await (null))",
-    "(cond (bool true) (dynamic) (int 0) (int 1))",
-    "(is (bool true) (invalid))",
-    "(as (bool true) (void))",
-    "(type (bottom))",
-    "(list (dynamic) ((null) (null) (null)))",
-    "(const-list (dynamic) ((int 0) (int 1) (int 2)))",
-    "(set (dynamic) ((bool true) (bool false) (int 0)))",
-    "(const-set (dynamic) ((int 0) (int 1) (int 2)))",
-    "(map (dynamic) (void) ((int 0) (null) (int 1) (null) (int 2) (null)))",
-    "(const-map (dynamic) (void) ((int 0) (null) (int 1) (null) "
-        "(int 2) (null)))",
-    "(type (-> () () () ((dynamic)) () () (dynamic)))",
-    "(type (-> () () () () ((dynamic)) () (dynamic)))",
-    "(type (-> () () () ((dynamic) (dynamic)) () () (dynamic)))",
-    "(type (-> () () () () () () (dynamic)))",
-    "(type (-> () () () ((-> () () () ((dynamic)) () () (dynamic))) () () "
-        "(dynamic)))",
-    "(type (-> (\"T^0\") ((dynamic)) ((dynamic)) () () () (dynamic)))",
-    "(type (-> (\"T^0\") ((dynamic)) ((dynamic)) ((par \"T^0\" _)) () () "
-        "(par \"T^0\" _)))",
-    "(type (-> (\"T^0\" \"S^1\") ((par \"S^1\" _) (par \"T^0\" _)) ((dynamic) "
-        "(dynamic)) () () () (dynamic)))",
+    '(get-prop (int 0) (public "hashCode"))',
+    '(get-super (public "hashCode"))',
+    '(invoke-method (int 0) (public "foo") () ((int 1) (int 2)) ())',
+    '(invoke-method (int 0) (public "foo") ((dynamic) (void)) '
+        '((int 1) (int 2)) ("others" (list (dynamic) ((int 3) (int 4)))))',
+    '(let (var "x^0" (dynamic) (int 0) ()) (null))',
+    '(let (var "x^0" (dynamic) _ ()) (null))',
+    '(let (const "x^0" (dynamic) (int 0) ()) (null))',
+    '(let (const "x^0" (dynamic) _ ()) (null))',
+    '(let (final "x^0" (dynamic) (int 0) ()) (null))',
+    '(let (final "x^0" (dynamic) _ ()) (null))',
+    r'''(string "Hello, 'string'!")''',
+    r'''(string "Hello, \"string\"!")''',
+    r'''(string "Yeah nah yeah, here is\nthis really long string haiku\n'''
+        r'''blowing in the wind\n")''',
+    '(int 42)',
+    '(int 0)',
+    '(int -1001)',
+    '(double 3.14159)',
+    '(bool true)',
+    '(bool false)',
+    '(null)',
+    r'''(invalid "You can't touch this")''',
+    '(not (bool true))',
+    '(&& (bool true) (bool false))',
+    '(|| (&& (bool true) (not (bool true))) (bool true))',
+    '(concat ((string "The opposite of ") (int 3) '
+        '(string " is ") (int 7)))',
+    '(symbol "unquote-splicing")',
+    '(this)',
+    '(rethrow)',
+    '(throw (string "error"))',
+    '(await (null))',
+    '(cond (bool true) (dynamic) (int 0) (int 1))',
+    '(is (bool true) (invalid))',
+    '(as (bool true) (void))',
+    '(type (bottom))',
+    '(list (dynamic) ((null) (null) (null)))',
+    '(const-list (dynamic) ((int 0) (int 1) (int 2)))',
+    '(set (dynamic) ((bool true) (bool false) (int 0)))',
+    '(const-set (dynamic) ((int 0) (int 1) (int 2)))',
+    '(map (dynamic) (void) ((int 0) (null) (int 1) (null) (int 2) (null)))',
+    '(const-map (dynamic) (void) ((int 0) (null) (int 1) (null) '
+        '(int 2) (null)))',
+    '(type (-> () () () ((dynamic)) () () (dynamic)))',
+    '(type (-> () () () () ((dynamic)) () (dynamic)))',
+    '(type (-> () () () ((dynamic) (dynamic)) () () (dynamic)))',
+    '(type (-> () () () () () () (dynamic)))',
+    '(type (-> () () () ((-> () () () ((dynamic)) () () (dynamic))) () () '
+        '(dynamic)))',
+    '(type (-> ("T^0") ((dynamic)) ((dynamic)) () () () (dynamic)))',
+    '(type (-> ("T^0") ((dynamic)) ((dynamic)) ((par "T^0" _)) () () '
+        '(par "T^0" _)))',
+    '(type (-> ("T^0" "S^1") ((par "S^1" _) (par "T^0" _)) ((dynamic) '
+        '(dynamic)) () () () (dynamic)))',
   ];
   for (var test in tests) {
     var literal = readExpression(test);
diff --git a/pkg/nnbd_migration/lib/instrumentation.dart b/pkg/nnbd_migration/lib/instrumentation.dart
index 31872c2..013e433 100644
--- a/pkg/nnbd_migration/lib/instrumentation.dart
+++ b/pkg/nnbd_migration/lib/instrumentation.dart
@@ -131,19 +131,30 @@
   dynamicAssignment,
   expressionChecks,
   fieldFormalParameter,
+  fieldNotInitialized,
   forEachVariable,
   greatestLowerBound,
   ifNull,
   implicitMixinSuperCall,
-  inheritance,
   initializerInference,
+  instanceCreation,
   instantiateToBounds,
   isCheckComponentType,
   isCheckMainType,
+  literal,
   namedParameterNotSupplied,
+  nonNullableBoolType,
+  nonNullableObjectSuperclass,
+  nonNullableUsage,
   nonNullAssertion,
   nullabilityComment,
   optionalFormalParameter,
+  parameterInheritance,
+  returnTypeInheritance,
+  stackTraceTypeOrigin,
+  thisOrSuper,
+  throw_,
+  uninitializedRead,
 }
 
 /// Interface used by the migration engine to expose information to its client
@@ -180,8 +191,8 @@
   /// and why it was created.
   void graphEdge(EdgeInfo edge, EdgeOriginInfo originInfo);
 
-  /// Called when the migration engine start up, to report information about the
-  /// immutable migration nodes [never] and [always] that are used as the
+  /// Called when the migration engine starts up, to report information about
+  /// the immutable migration nodes [never] and [always] that are used as the
   /// starting point for nullability propagation.
   void immutableNodes(NullabilityNodeInfo never, NullabilityNodeInfo always);
 
@@ -226,6 +237,17 @@
 /// Information exposed to the migration client about a single node in the
 /// nullability graph.
 abstract class NullabilityNodeInfo implements FixReasonInfo {
+  /// List of compound nodes wrapping this node.
+  final List<NullabilityNodeInfo> outerCompoundNodes = <NullabilityNodeInfo>[];
+
+  /// Some nodes get nullability from downstream, so the downstream edges are
+  /// available to query as well.
+  Iterable<EdgeInfo> get downstreamEdges;
+
+  /// After migration is complete, this getter can be used to query whether
+  /// the type associated with this node was determined to be "exact nullable."
+  bool get isExactNullable;
+
   /// Indicates whether the node is immutable.  The only immutable nodes in the
   /// nullability graph are the nodes `never` and `always` that are used as the
   /// starting points for nullability propagation.
diff --git a/pkg/nnbd_migration/lib/nnbd_migration.dart b/pkg/nnbd_migration/lib/nnbd_migration.dart
index 145054a..b81c0c6 100644
--- a/pkg/nnbd_migration/lib/nnbd_migration.dart
+++ b/pkg/nnbd_migration/lib/nnbd_migration.dart
@@ -16,46 +16,65 @@
   /// "then" branch discarded.
   static const discardThen = const NullabilityFixDescription._(
     appliedMessage: 'Discarded an unreachable conditional then branch',
+    kind: NullabilityFixKind.discardThen,
   );
 
   /// An if-test or conditional expression needs to have its condition
   /// discarded.
   static const discardCondition = const NullabilityFixDescription._(
     appliedMessage: 'Discarded a condition which is always true',
+    kind: NullabilityFixKind.discardCondition,
   );
 
   /// An if-test or conditional expression needs to have its condition and
   /// "else" branch discarded.
   static const discardElse = const NullabilityFixDescription._(
     appliedMessage: 'Discarded an unreachable conditional else branch',
+    kind: NullabilityFixKind.discardElse,
   );
 
   /// An expression's value needs to be null-checked.
   static const checkExpression = const NullabilityFixDescription._(
     appliedMessage: 'Added a non-null assertion to nullable expression',
+    kind: NullabilityFixKind.checkExpression,
   );
 
   /// A message used by dartfix to indicate a fix has been applied.
   final String appliedMessage;
 
+  /// The kind of fix described.
+  final NullabilityFixKind kind;
+
   /// A formal parameter needs to have a required keyword added.
   factory NullabilityFixDescription.addRequired(
           String className, String functionName, String paramName) =>
       NullabilityFixDescription._(
-          appliedMessage:
-              "Add 'required' keyword to parameter '$paramName' in " +
-                  (className == null
-                      ? functionName
-                      : "'$className.$functionName'"));
+        appliedMessage: "Add 'required' keyword to parameter '$paramName' in " +
+            (className == null ? functionName : "'$className.$functionName'"),
+        kind: NullabilityFixKind.addRequired,
+      );
 
   /// An explicit type mentioned in the source program needs to be made
   /// nullable.
   factory NullabilityFixDescription.makeTypeNullable(String type) =>
       NullabilityFixDescription._(
         appliedMessage: "Changed type '$type' to be nullable",
+        kind: NullabilityFixKind.makeTypeNullable,
       );
 
-  const NullabilityFixDescription._({@required this.appliedMessage});
+  const NullabilityFixDescription._(
+      {@required this.appliedMessage, @required this.kind});
+}
+
+/// An enumeration of the various kinds of nullability fixes.
+enum NullabilityFixKind {
+  addRequired,
+  checkExpression,
+  discardCondition,
+  discardElse,
+  discardThen,
+  makeTypeNullable,
+  noModification,
 }
 
 /// Provisional API for DartFix to perform nullability migration.
@@ -106,8 +125,8 @@
   /// What kind of fix this is.
   NullabilityFixDescription get description;
 
-  /// Location of the change, for reporting to the user.
-  Location get location;
+  /// Locations of the change, for reporting to the user.
+  List<Location> get locations;
 
   /// File to change.
   Source get source;
diff --git a/pkg/nnbd_migration/lib/src/decorated_type.dart b/pkg/nnbd_migration/lib/src/decorated_type.dart
index a7a3a60..48e41f2 100644
--- a/pkg/nnbd_migration/lib/src/decorated_type.dart
+++ b/pkg/nnbd_migration/lib/src/decorated_type.dart
@@ -149,10 +149,8 @@
   factory DecoratedType.forImplicitType(
       TypeProvider typeProvider, DartType type, NullabilityGraph graph,
       {List<DecoratedType> typeArguments}) {
-    if (type.isDynamic || type.isVoid) {
-      assert(typeArguments == null);
-      return DecoratedType(type, graph.always);
-    } else if (type is InterfaceType) {
+    var nullabilityNode = NullabilityNode.forInferredType();
+    if (type is InterfaceType) {
       assert(() {
         if (typeArguments != null) {
           assert(typeArguments.length == type.typeArguments.length);
@@ -166,24 +164,17 @@
       typeArguments ??= type.typeArguments
           .map((t) => DecoratedType.forImplicitType(typeProvider, t, graph))
           .toList();
-      return DecoratedType(type, NullabilityNode.forInferredType(),
-          typeArguments: typeArguments);
+      return DecoratedType(type, nullabilityNode, typeArguments: typeArguments);
     } else if (type is FunctionType) {
       if (typeArguments != null) {
         throw "Not supported: implicit function type with explicit type arguments";
       }
       return DecoratedType.forImplicitFunction(
-          typeProvider, type, NullabilityNode.forInferredType(), graph);
-    } else if (type is TypeParameterType) {
+          typeProvider, type, nullabilityNode, graph);
+    } else {
       assert(typeArguments == null);
-      return DecoratedType(type, NullabilityNode.forInferredType());
-    } else if (type is NeverTypeImpl) {
-      assert(typeArguments == null);
-      return DecoratedType(type, NullabilityNode.forInferredType());
+      return DecoratedType(type, nullabilityNode);
     }
-    // TODO(paulberry)
-    throw UnimplementedError(
-        'DecoratedType.forImplicitType(${type.runtimeType})');
   }
 
   /// Creates a [DecoratedType] for a synthetic type parameter, to be used
diff --git a/pkg/nnbd_migration/lib/src/edge_builder.dart b/pkg/nnbd_migration/lib/src/edge_builder.dart
index ac9aecd..f44ba67 100644
--- a/pkg/nnbd_migration/lib/src/edge_builder.dart
+++ b/pkg/nnbd_migration/lib/src/edge_builder.dart
@@ -8,11 +8,12 @@
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/dart/element/type_system.dart';
 import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
 import 'package:analyzer/src/dart/element/member.dart';
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/dart/resolver/flow_analysis_visitor.dart';
-import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
 import 'package:analyzer/src/generated/source.dart';
 import 'package:meta/meta.dart';
 import 'package:nnbd_migration/instrumentation.dart';
@@ -119,18 +120,6 @@
   /// information  used in flow analysis.  Otherwise `null`.
   AssignedVariables<AstNode, PromotableElement> _assignedVariables;
 
-  /// For convenience, a [DecoratedType] representing non-nullable `Object`.
-  final DecoratedType _notNullType;
-
-  /// For convenience, a [DecoratedType] representing non-nullable `bool`.
-  final DecoratedType _nonNullableBoolType;
-
-  /// For convenience, a [DecoratedType] representing non-nullable `Type`.
-  final DecoratedType _nonNullableTypeType;
-
-  /// For convenience, a [DecoratedType] representing `dynamic`.
-  final DecoratedType _dynamicType;
-
   /// The [DecoratedType] of the innermost function or method being visited, or
   /// `null` if the visitor is not inside any function or method.
   ///
@@ -191,16 +180,19 @@
   /// of the cascade.  Otherwise `null`.
   DecoratedType _currentCascadeTargetType;
 
+  /// While visiting a class declaration, set of class fields that lack
+  /// initializers at their declaration sites.
+  Set<FieldElement> _fieldsNotInitializedAtDeclaration;
+
+  /// While visiting a constructor, set of class fields that lack initializers
+  /// at their declaration sites *and* for which we haven't yet found an
+  /// initializer in the constructor declaration.
+  Set<FieldElement> _fieldsNotInitializedByConstructor;
+
   EdgeBuilder(this.typeProvider, this._typeSystem, this._variables, this._graph,
       this.source, this.listener, this._decoratedClassHierarchy,
       {this.instrumentation})
-      : _inheritanceManager = InheritanceManager3(_typeSystem),
-        _notNullType = DecoratedType(typeProvider.objectType, _graph.never),
-        _nonNullableBoolType =
-            DecoratedType(typeProvider.boolType, _graph.never),
-        _nonNullableTypeType =
-            DecoratedType(typeProvider.typeType, _graph.never),
-        _dynamicType = DecoratedType(typeProvider.dynamicType, _graph.always);
+      : _inheritanceManager = InheritanceManager3();
 
   /// Gets the decorated type of [element] from [_variables], performing any
   /// necessary substitutions.
@@ -223,13 +215,16 @@
       var variable = baseElement.variable;
       var decoratedElementType = _variables.decoratedElementType(variable);
       if (baseElement.isGetter) {
-        decoratedBaseType = DecoratedType(baseElement.type, _graph.never,
+        decoratedBaseType = DecoratedType(
+            baseElement.type, NullabilityNode.forInferredType(),
             returnType: decoratedElementType);
       } else {
         assert(baseElement.isSetter);
-        decoratedBaseType = DecoratedType(baseElement.type, _graph.never,
+        decoratedBaseType = DecoratedType(
+            baseElement.type, NullabilityNode.forInferredType(),
             positionalParameters: [decoratedElementType],
-            returnType: DecoratedType(VoidTypeImpl.instance, _graph.always));
+            returnType: DecoratedType(
+                VoidTypeImpl.instance, NullabilityNode.forInferredType()));
       }
     } else {
       decoratedBaseType = _variables.decoratedElementType(baseElement);
@@ -266,9 +261,8 @@
     if (identical(_conditionInfo?.condition, node.condition)) {
       var intentNode = _conditionInfo.trueDemonstratesNonNullIntent;
       if (intentNode != null && _conditionInfo.postDominatingIntent) {
-        _graph.connect(_conditionInfo.trueDemonstratesNonNullIntent,
-            _graph.never, NonNullAssertionOrigin(source, node),
-            hard: true);
+        _graph.makeNonNullable(_conditionInfo.trueDemonstratesNonNullIntent,
+            NonNullAssertionOrigin(source, node));
       }
     }
     _flowAnalysis.assert_afterCondition(node.condition);
@@ -284,9 +278,8 @@
     if (identical(_conditionInfo?.condition, node.condition)) {
       var intentNode = _conditionInfo.trueDemonstratesNonNullIntent;
       if (intentNode != null && _conditionInfo.postDominatingIntent) {
-        _graph.connect(_conditionInfo.trueDemonstratesNonNullIntent,
-            _graph.never, NonNullAssertionOrigin(source, node),
-            hard: true);
+        _graph.makeNonNullable(_conditionInfo.trueDemonstratesNonNullIntent,
+            NonNullAssertionOrigin(source, node));
       }
     }
     _flowAnalysis.assert_afterCondition(node.condition);
@@ -353,7 +346,7 @@
             falseDemonstratesNonNullIntent: leftType.node);
         _conditionInfo = notEqual ? conditionInfo.not(node) : conditionInfo;
       }
-      return _nonNullableBoolType;
+      return _makeNonNullableBoolType(node);
     } else if (operatorType == TokenType.AMPERSAND_AMPERSAND ||
         operatorType == TokenType.BAR_BAR) {
       bool isAnd = operatorType == TokenType.AMPERSAND_AMPERSAND;
@@ -362,7 +355,7 @@
       _postDominatedLocals.doScoped(
           action: () => _checkExpressionNotNull(rightOperand));
       _flowAnalysis.logicalBinaryOp_end(node, rightOperand, isAnd: isAnd);
-      return _nonNullableBoolType;
+      return _makeNonNullableBoolType(node);
     } else if (operatorType == TokenType.QUESTION_QUESTION) {
       DecoratedType expressionType;
       var leftType = leftOperand.accept(this);
@@ -390,7 +383,7 @@
       var callee = node.staticElement;
       if (callee == null) {
         rightOperand.accept(this);
-        return _dynamicType;
+        return _makeNullableDynamicType(node);
       } else {
         var calleeType =
             getOrComputeElementType(callee, targetType: targetType);
@@ -411,7 +404,7 @@
   @override
   DecoratedType visitBooleanLiteral(BooleanLiteral node) {
     _flowAnalysis.booleanLiteral(node, node.value);
-    return DecoratedType(node.staticType, _graph.never);
+    return _makeNonNullLiteralType(node);
   }
 
   @override
@@ -453,8 +446,18 @@
 
   @override
   DecoratedType visitClassDeclaration(ClassDeclaration node) {
+    _fieldsNotInitializedAtDeclaration = {
+      for (var member in node.members)
+        if (member is FieldDeclaration)
+          for (var field in member.fields.variables)
+            if (field.initializer == null) field.declaredElement as FieldElement
+    };
+    if (node.declaredElement.unnamedConstructor?.isSynthetic == true) {
+      _handleUninitializedFields(node, _fieldsNotInitializedAtDeclaration);
+    }
     node.metadata.accept(this);
     node.members.accept(this);
+    _fieldsNotInitializedAtDeclaration = null;
     return null;
   }
 
@@ -515,6 +518,8 @@
 
   @override
   DecoratedType visitConstructorDeclaration(ConstructorDeclaration node) {
+    _fieldsNotInitializedByConstructor =
+        _fieldsNotInitializedAtDeclaration.toSet();
     _handleExecutableDeclaration(
         node,
         node.declaredElement,
@@ -524,12 +529,14 @@
         node.initializers,
         node.body,
         node.redirectedConstructor);
+    _fieldsNotInitializedByConstructor = null;
     return null;
   }
 
   @override
   DecoratedType visitConstructorFieldInitializer(
       ConstructorFieldInitializer node) {
+    _fieldsNotInitializedByConstructor.remove(node.fieldName.staticElement);
     _handleAssignment(node.expression,
         destinationType: getOrComputeElementType(node.fieldName.staticElement));
     return null;
@@ -556,9 +563,7 @@
         // Nothing to do; the implicit default value of `null` will never be
         // reached.
       } else {
-        _connect(
-            _graph.always,
-            getOrComputeElementType(node.declaredElement).node,
+        _graph.makeNullable(getOrComputeElementType(node.declaredElement).node,
             OptionalFormalParameterOrigin(source, node));
       }
     } else {
@@ -581,7 +586,7 @@
 
   @override
   DecoratedType visitDoubleLiteral(DoubleLiteral node) {
-    return DecoratedType(node.staticType, _graph.never);
+    return _makeNonNullLiteralType(node);
   }
 
   @override
@@ -602,7 +607,9 @@
   DecoratedType visitFieldFormalParameter(FieldFormalParameter node) {
     var parameterElement = node.declaredElement as FieldFormalParameterElement;
     var parameterType = _variables.decoratedElementType(parameterElement);
-    var fieldType = _variables.decoratedElementType(parameterElement.field);
+    var field = parameterElement.field;
+    _fieldsNotInitializedByConstructor.remove(field);
+    var fieldType = _variables.decoratedElementType(field);
     var origin = FieldFormalParameterOrigin(source, node);
     if (node.type == null) {
       _unionDecoratedTypes(parameterType, fieldType, origin);
@@ -637,8 +644,8 @@
       // Initialize a new postDominator scope that contains only the parameters.
       try {
         node.functionExpression.accept(this);
-      } finally {
         _flowAnalysis.finish();
+      } finally {
         _flowAnalysis = null;
         _assignedVariables = null;
       }
@@ -767,7 +774,7 @@
       // Dynamic dispatch.  The return type is `dynamic`.
       // TODO(paulberry): would it be better to assume a return type of `Never`
       // so that we don't unnecessarily propagate nullabilities everywhere?
-      return _dynamicType;
+      return _makeNullableDynamicType(node);
     }
     var calleeType = getOrComputeElementType(callee, targetType: targetType);
     // TODO(paulberry): substitute if necessary
@@ -808,7 +815,10 @@
         decoratedTypeArguments = const [];
       }
     }
-    var createdType = DecoratedType(node.staticType, _graph.never,
+    var nullabilityNode = NullabilityNode.forInferredType();
+    _graph.makeNonNullable(
+        nullabilityNode, InstanceCreationOrigin(source, node));
+    var createdType = DecoratedType(node.staticType, nullabilityNode,
         typeArguments: decoratedTypeArguments);
     var calleeType = getOrComputeElementType(callee, targetType: createdType);
     _handleInvocationArguments(node, node.argumentList.arguments, typeArguments,
@@ -818,7 +828,7 @@
 
   @override
   DecoratedType visitIntegerLiteral(IntegerLiteral node) {
-    return DecoratedType(node.staticType, _graph.never);
+    return _makeNonNullLiteralType(node);
   }
 
   @override
@@ -829,14 +839,13 @@
     if (type is NamedType) {
       // The main type of the is check historically could not be nullable.
       // Making it nullable could change runtime behavior.
-      _connect(decoratedType.node, _graph.never,
-          IsCheckMainTypeOrigin(source, type));
+      _graph.makeNonNullable(
+          decoratedType.node, IsCheckMainTypeOrigin(source, type));
       if (type.typeArguments != null) {
         // TODO(mfairhurst): connect arguments to the expression type when they
         // relate.
         type.typeArguments.arguments.forEach((argument) {
-          _connect(
-              _graph.always,
+          _graph.makeNullable(
               _variables.decoratedTypeAnnotation(source, argument).node,
               IsCheckComponentTypeOrigin(source, argument));
         });
@@ -849,7 +858,7 @@
     expression.accept(this);
     _flowAnalysis.isExpression_end(
         node, expression, node.notOperator != null, decoratedType);
-    return DecoratedType(node.staticType, _graph.never);
+    return _makeNonNullableBoolType(node);
   }
 
   @override
@@ -881,7 +890,7 @@
             source, node.typeArguments.arguments[0]);
       }
       node.elements.forEach(_handleCollectionElement);
-      return DecoratedType(listType, _graph.never,
+      return _makeNonNullLiteralType(node,
           typeArguments: [_currentLiteralElementType]);
     } finally {
       _currentLiteralElementType = previousLiteralType;
@@ -930,7 +939,7 @@
       // so that we don't unnecessarily propagate nullabilities everywhere?
       node.typeArguments?.accept(this);
       node.argumentList.accept(this);
-      return _dynamicType;
+      return _makeNullableDynamicType(node);
     } else if (callee is VariableElement) {
       // Function expression invocation that looks like a method invocation.
       return _handleFunctionExpressionInvocation(node, node.methodName,
@@ -968,8 +977,7 @@
     _flowAnalysis.nullLiteral(node);
     var decoratedType =
         DecoratedType.forImplicitType(typeProvider, node.staticType, _graph);
-    _graph.makeNullable(
-        decoratedType.node, AlwaysNullableTypeOrigin(source, node));
+    _graph.makeNullable(decoratedType.node, LiteralOrigin(source, node));
     return decoratedType;
   }
 
@@ -998,7 +1006,7 @@
         // Dynamic dispatch.  The return type is `dynamic`.
         // TODO(paulberry): would it be better to assume a return type of `Never`
         // so that we don't unnecessarily propagate nullabilities everywhere?
-        writeType = _dynamicType;
+        writeType = _makeNullableDynamicType(node);
       } else {
         var calleeType =
             getOrComputeElementType(callee, targetType: targetType);
@@ -1034,7 +1042,7 @@
     var operatorType = node.operator.type;
     if (operatorType == TokenType.BANG) {
       _flowAnalysis.logicalNot_end(node, operand);
-      return _nonNullableBoolType;
+      return _makeNonNullableBoolType(node);
     } else {
       var callee = node.staticElement;
       var isIncrementOrDecrement = operatorType.isIncrementOperator;
@@ -1043,7 +1051,7 @@
         // Dynamic dispatch.  The return type is `dynamic`.
         // TODO(paulberry): would it be better to assume a return type of `Never`
         // so that we don't unnecessarily propagate nullabilities everywhere?
-        staticType = _dynamicType;
+        staticType = _makeNullableDynamicType(node);
       } else {
         var calleeType =
             getOrComputeElementType(callee, targetType: targetType);
@@ -1085,7 +1093,9 @@
   @override
   DecoratedType visitRethrowExpression(RethrowExpression node) {
     _flowAnalysis.handleExit();
-    return DecoratedType(node.staticType, _graph.never);
+    var nullabilityNode = NullabilityNode.forInferredType();
+    _graph.makeNonNullable(nullabilityNode, ThrowOrigin(source, node));
+    return DecoratedType(node.staticType, nullabilityNode);
   }
 
   @override
@@ -1136,7 +1146,7 @@
               _variables.decoratedTypeAnnotation(source, typeArguments[0]);
         }
         node.elements.forEach(_handleCollectionElement);
-        return DecoratedType(setOrMapType, _graph.never,
+        return _makeNonNullLiteralType(node,
             typeArguments: [_currentLiteralElementType]);
       } finally {
         _currentLiteralElementType = previousLiteralType;
@@ -1166,7 +1176,7 @@
         }
 
         node.elements.forEach(_handleCollectionElement);
-        return DecoratedType(setOrMapType, _graph.never,
+        return _makeNonNullLiteralType(node,
             typeArguments: [_currentMapKeyType, _currentMapValueType]);
       } finally {
         _currentMapKeyType = previousKeyType;
@@ -1183,7 +1193,13 @@
         var promotedType = _flowAnalysis.variableRead(node, staticElement);
         if (promotedType != null) return promotedType;
       }
-      return getOrComputeElementType(staticElement);
+      var type = getOrComputeElementType(staticElement);
+      if (!node.inDeclarationContext() &&
+          node.inGetterContext() &&
+          !_flowAnalysis.isAssigned(staticElement)) {
+        _graph.makeNullable(type.node, UninitializedReadOrigin(source, node));
+      }
+      return type;
     } else if (staticElement is FunctionElement ||
         staticElement is MethodElement) {
       return getOrComputeElementType(staticElement);
@@ -1193,7 +1209,7 @@
           ? elementType.returnType
           : elementType.positionalParameters[0];
     } else if (staticElement is TypeDefiningElement) {
-      return _nonNullableTypeType;
+      return _makeNonNullLiteralType(node);
     } else {
       // TODO(paulberry)
       _unimplemented(node,
@@ -1239,7 +1255,7 @@
   @override
   DecoratedType visitStringLiteral(StringLiteral node) {
     node.visitChildren(this);
-    return DecoratedType(node.staticType, _graph.never);
+    return _makeNonNullLiteralType(node);
   }
 
   @override
@@ -1268,7 +1284,7 @@
 
   @override
   DecoratedType visitSymbolLiteral(SymbolLiteral node) {
-    return DecoratedType(node.staticType, _graph.never);
+    return _makeNonNullLiteralType(node);
   }
 
   @override
@@ -1281,7 +1297,9 @@
     node.expression.accept(this);
     // TODO(paulberry): do we need to check the expression type?  I think not.
     _flowAnalysis.handleExit();
-    return DecoratedType(node.staticType, _graph.never);
+    var nullabilityNode = NullabilityNode.forInferredType();
+    _graph.makeNonNullable(nullabilityNode, ThrowOrigin(source, node));
+    return DecoratedType(node.staticType, nullabilityNode);
   }
 
   @override
@@ -1346,7 +1364,7 @@
         }
       }
     }
-    return _nonNullableTypeType;
+    return null;
   }
 
   @override
@@ -1355,7 +1373,6 @@
     bool isTopLevel =
         parent is FieldDeclaration || parent is TopLevelVariableDeclaration;
     node.metadata.accept(this);
-    var typeAnnotation = node.type;
     for (var variable in node.variables) {
       variable.metadata.accept(this);
       var initializer = variable.initializer;
@@ -1372,22 +1389,13 @@
             _flowAnalysis.initialize(declaredElement);
           }
           var destinationType = getOrComputeElementType(declaredElement);
-          if (typeAnnotation == null) {
-            var initializerType = initializer.accept(this);
-            if (initializerType == null) {
-              throw StateError(
-                  'No type computed for ${initializer.runtimeType} '
-                  '(${initializer.toSource()}) offset=${initializer.offset}');
-            }
-            _unionDecoratedTypes(initializerType, destinationType,
-                InitializerInferenceOrigin(source, variable));
-          } else {
-            _handleAssignment(initializer, destinationType: destinationType);
-          }
+          _handleAssignment(initializer, destinationType: destinationType);
+        }
+        if (isTopLevel) {
+          _flowAnalysis.finish();
         }
       } finally {
         if (isTopLevel) {
-          _flowAnalysis.finish();
           _flowAnalysis = null;
           _assignedVariables = null;
         }
@@ -1433,14 +1441,22 @@
   ///
   /// Returns the decorated type of [expression].
   DecoratedType _checkExpressionNotNull(Expression expression) {
-    // Note: it's not necessary for `destinationType` to precisely match the
-    // type of the expression, since all we are doing is causing a single graph
-    // edge to be built; it is sufficient to pass in any decorated type whose
-    // node is `never`.
     if (_isPrefix(expression)) {
       throw ArgumentError('cannot check non-nullability of a prefix');
     }
-    return _handleAssignment(expression, destinationType: _notNullType);
+    DecoratedType sourceType = expression.accept(this);
+    if (sourceType == null) {
+      throw StateError('No type computed for ${expression.runtimeType} '
+          '(${expression.toSource()}) offset=${expression.offset}');
+    }
+    var origin = _makeEdgeOrigin(sourceType, expression);
+    var edge = _graph.makeNonNullable(sourceType.node, origin,
+        hard: _postDominatedLocals.isReferenceInScope(expression),
+        guards: _guards);
+    if (origin is ExpressionChecksOrigin) {
+      origin.checks.edges.add(edge);
+    }
+    return sourceType;
   }
 
   @override
@@ -1463,21 +1479,35 @@
             PromotableElement, DecoratedType>(
         DecoratedTypeOperations(_typeSystem, _variables, _graph),
         _assignedVariables);
+    if (parameters != null) {
+      for (var parameter in parameters.parameters) {
+        _flowAnalysis.initialize(parameter.declaredElement);
+      }
+    }
+  }
+
+  /// Creates a type that can be used to check that an expression's value is
+  /// non-nullable.
+  DecoratedType _createNonNullableType(Expression expression) {
+    // Note: it's not necessary for the type to precisely match the type of the
+    // expression, since all we are going to do is cause a single graph edge to
+    // be built; it is sufficient to pass in any decorated type whose node is
+    // non-nullable.  So we use `Object`.
+    var nullabilityNode = NullabilityNode.forInferredType();
+    _graph.makeNonNullable(
+        nullabilityNode, NonNullableUsageOrigin(source, expression));
+    return DecoratedType(typeProvider.objectType, nullabilityNode);
   }
 
   DecoratedType _decorateUpperOrLowerBound(AstNode astNode, DartType type,
       DecoratedType left, DecoratedType right, bool isLUB,
       {NullabilityNode node}) {
-    if (type.isDynamic || type.isVoid) {
-      if (type.isDynamic) {
-        _unimplemented(astNode, 'LUB/GLB with dynamic');
-      }
-      return DecoratedType(type, _graph.always);
-    }
     node ??= isLUB
         ? NullabilityNode.forLUB(left.node, right.node)
         : _nullabilityNodeForGLB(astNode, left.node, right.node);
-    if (type is InterfaceType) {
+    if (type.isDynamic || type.isVoid) {
+      return DecoratedType(type, node);
+    } else if (type is InterfaceType) {
       if (type.typeArguments.isEmpty) {
         return DecoratedType(type, node);
       } else {
@@ -1625,28 +1655,14 @@
         throw StateError('No type computed for ${expression.runtimeType} '
             '(${expression.toSource()}) offset=${expression.offset}');
       }
-      EdgeOrigin edgeOrigin;
-      if (sourceType.type.isDynamic) {
-        edgeOrigin = DynamicAssignmentOrigin(source, expression);
-      } else {
-        if (fromDefaultValue) {
-          edgeOrigin = DefaultValueOrigin(source, expression);
-        } else {
-          ExpressionChecksOrigin expressionChecksOrigin =
-              ExpressionChecksOrigin(
-                  source, expression, ExpressionChecks(expression.end));
-          _variables.recordExpressionChecks(
-              source, expression, expressionChecksOrigin);
-          edgeOrigin = expressionChecksOrigin;
-        }
-      }
+      EdgeOrigin edgeOrigin = _makeEdgeOrigin(sourceType, expression);
       if (compoundOperatorInfo != null) {
         var compoundOperatorMethod = compoundOperatorInfo.staticElement;
         if (compoundOperatorMethod != null) {
           _checkAssignment(
               CompoundAssignmentOrigin(source, compoundOperatorInfo),
               source: destinationType,
-              destination: _notNullType,
+              destination: _createNonNullableType(compoundOperatorInfo),
               hard: _postDominatedLocals
                   .isReferenceInScope(destinationExpression));
           DecoratedType compoundOperatorType = getOrComputeElementType(
@@ -1665,7 +1681,7 @@
               destination: destinationType,
               hard: false);
         } else {
-          sourceType = _dynamicType;
+          sourceType = _makeNullableDynamicType(compoundOperatorInfo);
         }
       } else {
         _checkAssignment(edgeOrigin,
@@ -1743,13 +1759,17 @@
     _postDominatedLocals.pushScope(elements: declaredElement.parameters);
     try {
       initializers?.accept(this);
+      if (declaredElement is ConstructorElement &&
+          !declaredElement.isFactory &&
+          declaredElement.redirectedConstructor == null) {
+        _handleUninitializedFields(node, _fieldsNotInitializedByConstructor);
+      }
       body.accept(this);
       if (redirectedConstructor != null) {
         _handleConstructorRedirection(parameters, redirectedConstructor);
       }
       if (declaredElement is! ConstructorElement) {
         var classElement = declaredElement.enclosingElement as ClassElement;
-        var origin = InheritanceOrigin(source, node);
         for (var overriddenElement in _inheritanceManager.getOverridden(
                 classElement.thisType,
                 Name(classElement.library.source.uri, declaredElement.name)) ??
@@ -1765,10 +1785,12 @@
           var overriddenFunctionType =
               decoratedOverriddenFunctionType.substitute(substitution);
           if (returnType == null) {
-            _unionDecoratedTypes(_currentFunctionType.returnType,
-                overriddenFunctionType.returnType, origin);
+            _unionDecoratedTypes(
+                _currentFunctionType.returnType,
+                overriddenFunctionType.returnType,
+                ReturnTypeInheritanceOrigin(source, node));
           } else {
-            _checkAssignment(origin,
+            _checkAssignment(ReturnTypeInheritanceOrigin(source, node),
                 source: _currentFunctionType.returnType,
                 destination: overriddenFunctionType.returnType,
                 hard: true);
@@ -1805,6 +1827,7 @@
                 positionalParameterCount++;
               }
               if (overriddenParameterType != null) {
+                var origin = ParameterInheritanceOrigin(source, node);
                 if (_isUntypedParameter(normalParameter)) {
                   _unionDecoratedTypes(
                       overriddenParameterType, currentParameterType, origin);
@@ -1819,8 +1842,8 @@
           }
         }
       }
-    } finally {
       _flowAnalysis.finish();
+    } finally {
       _flowAnalysis = null;
       _assignedVariables = null;
       _currentFunctionType = null;
@@ -1871,7 +1894,7 @@
       _flowAnalysis.forEach_bodyBegin(
           node,
           lhsElement is PromotableElement ? lhsElement : null,
-          elementType ?? _dynamicType);
+          elementType ?? _makeNullableDynamicType(node));
     }
 
     // The condition may fail/iterable may be empty, so the body gets a new
@@ -1903,7 +1926,7 @@
       // Invocation of type `dynamic` or `Function`.
       typeArguments?.accept(this);
       argumentList.accept(this);
-      return _dynamicType;
+      return _makeNullableDynamicType(node);
     }
   }
 
@@ -2012,7 +2035,7 @@
     }
     if (callee == null) {
       // Dynamic dispatch.
-      return _dynamicType;
+      return _makeNullableDynamicType(node);
     }
     var calleeType = getOrComputeElementType(callee, targetType: targetType);
     // TODO(paulberry): substitute if necessary
@@ -2044,17 +2067,30 @@
 
   DecoratedType _handleThisOrSuper(Expression node) {
     var type = node.staticType as InterfaceType;
-    // Instantiate the type, and any type arguments, with `_graph.never`,
+    // Instantiate the type, and any type arguments, with non-nullable types,
     // because the type of `this` is always `ClassName<Param, Param, ...>` with
     // no `?`s.  (Even if some of the type parameters are allowed to be
     // instantiated with nullable types at runtime, a reference to `this` can't
     // be migrated in such a way that forces them to be nullable).
-    return DecoratedType(type, _graph.never,
+    NullabilityNode makeNonNullableNode() {
+      var nullabilityNode = NullabilityNode.forInferredType();
+      _graph.makeNonNullable(nullabilityNode, ThisOrSuperOrigin(source, node));
+      return nullabilityNode;
+    }
+
+    return DecoratedType(type, makeNonNullableNode(),
         typeArguments: type.typeArguments
-            .map((t) => DecoratedType(t, _graph.never))
+            .map((t) => DecoratedType(t, makeNonNullableNode()))
             .toList());
   }
 
+  void _handleUninitializedFields(AstNode node, Set<FieldElement> fields) {
+    for (var field in fields) {
+      _graph.makeNullable(_variables.decoratedElementType(field).node,
+          FieldNotInitializedOrigin(source, node));
+    }
+  }
+
   bool _isPrefix(Expression e) =>
       e is SimpleIdentifier && e.staticElement is PrefixElement;
 
@@ -2068,6 +2104,42 @@
     }
   }
 
+  EdgeOrigin _makeEdgeOrigin(DecoratedType sourceType, Expression expression) {
+    if (sourceType.type.isDynamic) {
+      return DynamicAssignmentOrigin(source, expression);
+    } else {
+      ExpressionChecksOrigin expressionChecksOrigin = ExpressionChecksOrigin(
+          source, expression, ExpressionChecks(expression.end));
+      _variables.recordExpressionChecks(
+          source, expression, expressionChecksOrigin);
+      return expressionChecksOrigin;
+    }
+  }
+
+  DecoratedType _makeNonNullableBoolType(Expression expression) {
+    assert(expression.staticType.isDartCoreBool);
+    var nullabilityNode = NullabilityNode.forInferredType();
+    _graph.makeNonNullable(
+        nullabilityNode, NonNullableBoolTypeOrigin(source, expression));
+    return DecoratedType(typeProvider.boolType, nullabilityNode);
+  }
+
+  DecoratedType _makeNonNullLiteralType(Expression expression,
+      {List<DecoratedType> typeArguments = const []}) {
+    var nullabilityNode = NullabilityNode.forInferredType();
+    _graph.makeNonNullable(nullabilityNode, LiteralOrigin(source, expression));
+    return DecoratedType(expression.staticType, nullabilityNode,
+        typeArguments: typeArguments);
+  }
+
+  DecoratedType _makeNullableDynamicType(AstNode astNode) {
+    var decoratedType = DecoratedType.forImplicitType(
+        typeProvider, typeProvider.dynamicType, _graph);
+    _graph.makeNullable(
+        decoratedType.node, AlwaysNullableTypeOrigin(source, astNode));
+    return decoratedType;
+  }
+
   NullabilityNode _nullabilityNodeForGLB(
       AstNode astNode, NullabilityNode leftNode, NullabilityNode rightNode) {
     var node = NullabilityNode.forGLB();
@@ -2145,8 +2217,6 @@
 
   DecoratedClassHierarchy get _decoratedClassHierarchy;
 
-  NullabilityGraph get _graph;
-
   TypeSystem get _typeSystem;
 
   /// Creates the necessary constraint(s) for an assignment from [source] to
@@ -2336,18 +2406,12 @@
               'downcast to type parameters with bounds not supported');
         }
       }
-
-      for (final arg in destination.typeArguments) {
-        // We cannot assume we're downcasting to C<T!>. Downcast to C<T?>.
-        _checkDowncast(origin, source: source, destination: arg, hard: false);
-      }
     } else if (destinationType is TypeParameterType &&
         source.type is! TypeParameterType) {
       // Assume an assignment to the type parameter's bound.
       _checkAssignment(origin,
           source: source,
-          destination:
-              _getTypeParameterTypeBound(destination).withNode(_graph.always),
+          destination: _getTypeParameterTypeBound(destination),
           hard: false);
     } else if (destinationType is InterfaceType) {
       assert(source.typeArguments.isEmpty,
@@ -2356,13 +2420,6 @@
         assert(param.bound == null,
             'downcast to type parameters with bounds not supported');
       }
-      for (final arg in destination.typeArguments) {
-        // We cannot assume we're downcasting to C<T!>. Downcast to C<T?>.
-        _checkDowncast(origin,
-            source: DecoratedType(typeProvider.dynamicType, _graph.always),
-            destination: arg,
-            hard: false);
-      }
     } else {
       assert(
           false,
diff --git a/pkg/nnbd_migration/lib/src/edge_origin.dart b/pkg/nnbd_migration/lib/src/edge_origin.dart
index 2899ee8a..e593c40 100644
--- a/pkg/nnbd_migration/lib/src/edge_origin.dart
+++ b/pkg/nnbd_migration/lib/src/edge_origin.dart
@@ -109,6 +109,19 @@
   EdgeOriginKind get kind => EdgeOriginKind.fieldFormalParameter;
 }
 
+/// An edge origin used for edges that originated because a field was not
+/// initialized.
+///
+/// The AST node associated with the edge is the AST node for the constructor
+/// that failed to initialize the field (or the class, if the constructor is
+/// synthetic).
+class FieldNotInitializedOrigin extends EdgeOrigin {
+  FieldNotInitializedOrigin(Source source, AstNode node) : super(source, node);
+
+  @override
+  EdgeOriginKind get kind => EdgeOriginKind.fieldNotInitialized;
+}
+
 /// Edge origin resulting from the use of an iterable type in a for-each loop.
 ///
 /// For example, in the following code snippet:
@@ -170,14 +183,6 @@
   EdgeOriginKind get kind => EdgeOriginKind.implicitMixinSuperCall;
 }
 
-/// Edge origin resulting from an inheritance relationship between two methods.
-class InheritanceOrigin extends EdgeOrigin {
-  InheritanceOrigin(Source source, AstNode node) : super(source, node);
-
-  @override
-  EdgeOriginKind get kind => EdgeOriginKind.inheritance;
-}
-
 /// Edge origin resulting from a type that is inferred from its initializer.
 class InitializerInferenceOrigin extends EdgeOrigin {
   InitializerInferenceOrigin(Source source, VariableDeclaration node)
@@ -187,6 +192,15 @@
   EdgeOriginKind get kind => EdgeOriginKind.initializerInference;
 }
 
+/// An edge origin used for edges that originated because of an instance
+/// creation expression.
+class InstanceCreationOrigin extends EdgeOrigin {
+  InstanceCreationOrigin(Source source, AstNode node) : super(source, node);
+
+  @override
+  EdgeOriginKind get kind => EdgeOriginKind.instanceCreation;
+}
+
 /// Edge origin resulting from a class that is instantiated to bounds.
 ///
 /// For example, in the following code snippet:
@@ -229,6 +243,15 @@
   EdgeOriginKind get kind => EdgeOriginKind.isCheckMainType;
 }
 
+/// An edge origin used for edges that originated because a literal expression
+/// has a known nullability.
+class LiteralOrigin extends EdgeOrigin {
+  LiteralOrigin(Source source, AstNode node) : super(source, node);
+
+  @override
+  EdgeOriginKind get kind => EdgeOriginKind.literal;
+}
+
 /// Edge origin resulting from a call site that does not supply a named
 /// parameter.
 ///
@@ -249,6 +272,34 @@
   EdgeOriginKind get kind => EdgeOriginKind.namedParameterNotSupplied;
 }
 
+/// Edge origin for the nullability of an expression that whose type is fixed by
+/// the language definition to be non-nullable `bool`.
+class NonNullableBoolTypeOrigin extends EdgeOrigin {
+  NonNullableBoolTypeOrigin(Source source, AstNode node) : super(source, node);
+
+  @override
+  EdgeOriginKind get kind => EdgeOriginKind.nonNullableBoolType;
+}
+
+/// Edge origin resulting from the class/superclass relationship for a class
+/// whose superclass is implicitly `Object`.
+class NonNullableObjectSuperclass extends EdgeOrigin {
+  NonNullableObjectSuperclass(Source source, AstNode node)
+      : super(source, node);
+
+  @override
+  EdgeOriginKind get kind => EdgeOriginKind.nonNullableObjectSuperclass;
+}
+
+/// Edge origin resulting from the usage of a value in a circumstance that
+/// requires it to be non-nullable
+class NonNullableUsageOrigin extends EdgeOrigin {
+  NonNullableUsageOrigin(Source source, AstNode node) : super(source, node);
+
+  @override
+  EdgeOriginKind get kind => EdgeOriginKind.nonNullableUsage;
+}
+
 /// Edge origin resulting from the presence of a non-null assertion.
 ///
 /// For example, in the following code snippet:
@@ -295,3 +346,58 @@
   @override
   EdgeOriginKind get kind => EdgeOriginKind.optionalFormalParameter;
 }
+
+/// Edge origin resulting from an inheritance relationship between two method
+/// parameters.
+class ParameterInheritanceOrigin extends EdgeOrigin {
+  ParameterInheritanceOrigin(Source source, AstNode node) : super(source, node);
+
+  @override
+  EdgeOriginKind get kind => EdgeOriginKind.parameterInheritance;
+}
+
+/// Edge origin resulting from an inheritance relationship between two method
+/// return types.
+class ReturnTypeInheritanceOrigin extends EdgeOrigin {
+  ReturnTypeInheritanceOrigin(Source source, AstNode node)
+      : super(source, node);
+
+  @override
+  EdgeOriginKind get kind => EdgeOriginKind.returnTypeInheritance;
+}
+
+/// Edge origin resulting from the use of a stacktrace parameter in a catch
+/// directive.  The type of such parameters is fixed by the language as
+/// non-nullable `StackTrace`.
+class StackTraceTypeOrigin extends EdgeOrigin {
+  StackTraceTypeOrigin(Source source, AstNode node) : super(source, node);
+
+  @override
+  EdgeOriginKind get kind => EdgeOriginKind.stackTraceTypeOrigin;
+}
+
+/// Edge origin resulting from the use of `this` or `super`.
+class ThisOrSuperOrigin extends EdgeOrigin {
+  ThisOrSuperOrigin(Source source, AstNode node) : super(source, node);
+
+  @override
+  EdgeOriginKind get kind => EdgeOriginKind.thisOrSuper;
+}
+
+/// An edge origin used for edges that originated from the type of a `throw` or
+/// `rethrow`.
+class ThrowOrigin extends EdgeOrigin {
+  ThrowOrigin(Source source, AstNode node) : super(source, node);
+
+  @override
+  EdgeOriginKind get kind => EdgeOriginKind.throw_;
+}
+
+/// Edge origin resulting from the read of a variable that has not been
+/// definitely assigned a value.
+class UninitializedReadOrigin extends EdgeOrigin {
+  UninitializedReadOrigin(Source source, AstNode node) : super(source, node);
+
+  @override
+  EdgeOriginKind get kind => EdgeOriginKind.uninitializedRead;
+}
diff --git a/pkg/nnbd_migration/lib/src/fix_builder.dart b/pkg/nnbd_migration/lib/src/fix_builder.dart
index b812254..6793265 100644
--- a/pkg/nnbd_migration/lib/src/fix_builder.dart
+++ b/pkg/nnbd_migration/lib/src/fix_builder.dart
@@ -75,7 +75,7 @@
   final TypeProvider typeProvider;
 
   /// The type system.
-  final Dart2TypeSystem _typeSystem;
+  final TypeSystemImpl _typeSystem;
 
   /// Variables for this migration run.
   final Variables _variables;
@@ -98,8 +98,8 @@
 
   FixBuilder(this.source, this._decoratedClassHierarchy,
       TypeProvider typeProvider, this._typeSystem, this._variables)
-      : typeProvider = (typeProvider as TypeProviderImpl)
-            .withNullability(NullabilitySuffix.none);
+      : typeProvider =
+            (typeProvider as TypeProviderImpl).asNonNullableByDefault;
 
   /// Called whenever an AST node is found that needs to be changed.
   void addChange(AstNode node, NodeChange change);
diff --git a/pkg/nnbd_migration/lib/src/node_builder.dart b/pkg/nnbd_migration/lib/src/node_builder.dart
index c0d1938..889e44f 100644
--- a/pkg/nnbd_migration/lib/src/node_builder.dart
+++ b/pkg/nnbd_migration/lib/src/node_builder.dart
@@ -63,23 +63,9 @@
 
   final TypeProvider _typeProvider;
 
-  /// For convenience, a [DecoratedType] representing `dynamic`.
-  final DecoratedType _dynamicType;
-
-  /// For convenience, a [DecoratedType] representing non-nullable `Object`.
-  final DecoratedType _nonNullableObjectType;
-
-  /// For convenience, a [DecoratedType] representing non-nullable `StackTrace`.
-  final DecoratedType _nonNullableStackTraceType;
-
   NodeBuilder(this._variables, this.source, this.listener, this._graph,
       this._typeProvider,
-      {this.instrumentation})
-      : _dynamicType = DecoratedType(_typeProvider.dynamicType, _graph.always),
-        _nonNullableObjectType =
-            DecoratedType(_typeProvider.objectType, _graph.never),
-        _nonNullableStackTraceType =
-            DecoratedType(_typeProvider.stackTraceType, _graph.never);
+      {this.instrumentation});
 
   @override
   DecoratedType visitCatchClause(CatchClause node) {
@@ -87,7 +73,8 @@
     if (node.exceptionParameter != null) {
       // If there is no `on Type` part of the catch clause, the type is dynamic.
       if (exceptionType == null) {
-        exceptionType = _dynamicType;
+        exceptionType = DecoratedType.forImplicitType(
+            _typeProvider, _typeProvider.dynamicType, _graph);
         instrumentation?.implicitType(
             source, node.exceptionParameter, exceptionType);
       }
@@ -96,7 +83,11 @@
     }
     if (node.stackTraceParameter != null) {
       // The type of stack traces is always StackTrace (non-nullable).
-      var stackTraceType = _nonNullableStackTraceType;
+      var nullabilityNode = NullabilityNode.forInferredType();
+      _graph.makeNonNullable(nullabilityNode,
+          StackTraceTypeOrigin(source, node.stackTraceParameter));
+      var stackTraceType =
+          DecoratedType(_typeProvider.stackTraceType, nullabilityNode);
       _variables.recordDecoratedElementType(
           node.stackTraceParameter.staticElement, stackTraceType);
       instrumentation?.implicitType(
@@ -115,7 +106,7 @@
     node.nativeClause?.accept(this);
     node.members.accept(this);
     var classElement = node.declaredElement;
-    _handleSupertypeClauses(classElement, node.extendsClause?.superclass,
+    _handleSupertypeClauses(node, classElement, node.extendsClause?.superclass,
         node.withClause, node.implementsClause, null);
     var constructors = classElement.constructors;
     if (constructors.length == 1) {
@@ -140,8 +131,8 @@
     node.name.accept(this);
     node.typeParameters?.accept(this);
     var classElement = node.declaredElement;
-    _handleSupertypeClauses(classElement, node.superclass, node.withClause,
-        node.implementsClause, null);
+    _handleSupertypeClauses(node, classElement, node.superclass,
+        node.withClause, node.implementsClause, null);
     for (var constructorElement in classElement.constructors) {
       assert(constructorElement.isSynthetic);
       var decoratedReturnType =
@@ -325,8 +316,8 @@
     node.name?.accept(this);
     node.typeParameters?.accept(this);
     node.members.accept(this);
-    _handleSupertypeClauses(
-        node.declaredElement, null, null, node.implementsClause, node.onClause);
+    _handleSupertypeClauses(node, node.declaredElement, null, null,
+        node.implementsClause, node.onClause);
     return null;
   }
 
@@ -341,8 +332,6 @@
     var type = node.type;
     if (type.isVoid || type.isDynamic) {
       var nullabilityNode = NullabilityNode.forTypeAnnotation(node.end);
-      _graph.connect(_graph.always, nullabilityNode,
-          AlwaysNullableTypeOrigin(source, node));
       var decoratedType = DecoratedType(type, nullabilityNode);
       _variables.recordDecoratedTypeAnnotation(
           source, node, decoratedType, null);
@@ -431,13 +420,12 @@
     var commentToken = node.endToken.next.precedingComments;
     switch (_classifyComment(commentToken)) {
       case _NullabilityComment.bang:
-        _graph.connect(decoratedType.node, _graph.never,
-            NullabilityCommentOrigin(source, node),
-            hard: true);
+        _graph.makeNonNullable(
+            decoratedType.node, NullabilityCommentOrigin(source, node));
         break;
       case _NullabilityComment.question:
-        _graph.union(_graph.always, decoratedType.node,
-            NullabilityCommentOrigin(source, node));
+        _graph.makeNullableUnion(
+            decoratedType.node, NullabilityCommentOrigin(source, node));
         break;
       case _NullabilityComment.none:
         break;
@@ -457,8 +445,6 @@
       decoratedBound = bound.accept(this);
     } else {
       var nullabilityNode = NullabilityNode.forInferredType();
-      _graph.union(_graph.always, nullabilityNode,
-          AlwaysNullableTypeOrigin(source, node));
       decoratedBound = DecoratedType(_typeProvider.objectType, nullabilityNode);
     }
     _typeFormalBounds?.add(decoratedBound);
@@ -623,6 +609,7 @@
   }
 
   void _handleSupertypeClauses(
+      NamedCompilationUnitMember astNode,
       ClassElement declaredElement,
       TypeName superclass,
       WithClause withClause,
@@ -643,7 +630,11 @@
     for (var supertype in supertypes) {
       DecoratedType decoratedSupertype;
       if (supertype == null) {
-        decoratedSupertype = _nonNullableObjectType;
+        var nullabilityNode = NullabilityNode.forInferredType();
+        _graph.makeNonNullable(
+            nullabilityNode, NonNullableObjectSuperclass(source, astNode));
+        decoratedSupertype =
+            DecoratedType(_typeProvider.objectType, nullabilityNode);
       } else {
         decoratedSupertype = supertype.accept(this);
       }
diff --git a/pkg/nnbd_migration/lib/src/nullability_migration_impl.dart b/pkg/nnbd_migration/lib/src/nullability_migration_impl.dart
index 0f778dd..40925c4 100644
--- a/pkg/nnbd_migration/lib/src/nullability_migration_impl.dart
+++ b/pkg/nnbd_migration/lib/src/nullability_migration_impl.dart
@@ -121,30 +121,30 @@
   @override
   final NullabilityFixDescription description;
 
-  Location _location;
+  List<Location> _locations;
 
   factory _SingleNullabilityFix(Source source,
       PotentialModification potentialModification, LineInfo lineInfo) {
-    Location location;
+    List<Location> locations = [];
 
-    if (potentialModification.modifications.isNotEmpty) {
-      final locationInfo = lineInfo
-          .getLocation(potentialModification.modifications.first.offset);
-      location = new Location(
+    for (var modification in potentialModification.modifications) {
+      final locationInfo = lineInfo.getLocation(modification.offset);
+      locations.add(new Location(
         source.fullName,
-        potentialModification.modifications.first.offset,
-        potentialModification.modifications.first.length,
+        modification.offset,
+        modification.length,
         locationInfo.lineNumber,
         locationInfo.columnNumber,
-      );
+      ));
     }
 
     return _SingleNullabilityFix._(source, potentialModification.description,
-        location: location);
+        locations: locations);
   }
 
-  _SingleNullabilityFix._(this.source, this.description, {Location location})
-      : this._location = location;
+  _SingleNullabilityFix._(this.source, this.description,
+      {List<Location> locations})
+      : this._locations = locations;
 
-  Location get location => _location;
+  List<Location> get locations => _locations;
 }
diff --git a/pkg/nnbd_migration/lib/src/nullability_node.dart b/pkg/nnbd_migration/lib/src/nullability_node.dart
index 8812789..04db7be 100644
--- a/pkg/nnbd_migration/lib/src/nullability_node.dart
+++ b/pkg/nnbd_migration/lib/src/nullability_node.dart
@@ -160,8 +160,9 @@
 
   /// Creates a graph edge that will try to force the given [node] to be
   /// non-nullable.
-  void makeNonNullable(NullabilityNode node, EdgeOrigin origin) {
-    connect(node, never, origin, hard: true);
+  NullabilityEdge makeNonNullable(NullabilityNode node, EdgeOrigin origin,
+      {bool hard: true, List<NullabilityNode> guards: const []}) {
+    return connect(node, never, origin, hard: hard, guards: guards);
   }
 
   /// Creates a graph edge that will try to force the given [node] to be
@@ -171,6 +172,13 @@
     connect(always, node, origin, guards: guards);
   }
 
+  /// Creates a `union` graph edge that will try to force the given [node] to be
+  /// nullable.  This is a stronger signal than [makeNullable] (it overrides
+  /// [makeNonNullable]).
+  void makeNullableUnion(NullabilityNode node, EdgeOrigin origin) {
+    union(always, node, origin);
+  }
+
   /// Record source as code that is being migrated.
   void migrating(Source source) {
     _sourcesBeingMigrated.add(source);
@@ -360,6 +368,8 @@
         for (var edge in node._upstreamEdges) {
           pendingEdges.add(edge);
         }
+
+        // TODO(mfairhurst): should this propagate back up outerContainerNodes?
       }
     }
     while (pendingEdges.isNotEmpty) {
@@ -460,6 +470,9 @@
   /// List of edges that have this node as their destination.
   final _upstreamEdges = <NullabilityEdge>[];
 
+  /// List of compound nodes wrapping this node.
+  final List<NullabilityNode> outerCompoundNodes = <NullabilityNode>[];
+
   /// Creates a [NullabilityNode] representing the nullability of a variable
   /// whose type comes from an already-migrated library.
   factory NullabilityNode.forAlreadyMigrated() =>
@@ -583,7 +596,10 @@
 
   final NullabilityNode right;
 
-  NullabilityNodeForLUB._(this.left, this.right);
+  NullabilityNodeForLUB._(this.left, this.right) {
+    left.outerCompoundNodes.add(this);
+    right.outerCompoundNodes.add(this);
+  }
 
   @override
   Iterable<NullabilityNode> get _components => [left, right];
@@ -602,7 +618,10 @@
   @override
   final NullabilityNode outerNode;
 
-  NullabilityNodeForSubstitution._(this.innerNode, this.outerNode);
+  NullabilityNodeForSubstitution._(this.innerNode, this.outerNode) {
+    innerNode.outerCompoundNodes.add(this);
+    outerNode.outerCompoundNodes.add(this);
+  }
 
   @override
   Iterable<NullabilityNode> get _components => [innerNode, outerNode];
@@ -672,14 +691,18 @@
   String get debugSuffix => isNullable ? '?' : '';
 
   @override
-  bool get isExactNullable => isNullable;
+  // Note: the node "always" is not exact nullable, because exact nullability is
+  // a concept for contravariant generics which propagates upstream instead of
+  // downstream. "always" is not a contravariant generic, and does not have any
+  // upstream nodes, so it should not be considered *exact* nullable.
+  bool get isExactNullable => false;
 
   @override
   bool get isImmutable => true;
 
   @override
   NullabilityState get _state => isNullable
-      ? NullabilityState.exactNullable
+      ? NullabilityState.ordinaryNullable
       : NullabilityState.nonNullable;
 }
 
diff --git a/pkg/nnbd_migration/test/already_migrated_code_decorator_test.dart b/pkg/nnbd_migration/test/already_migrated_code_decorator_test.dart
index d8131a2..eaf987b 100644
--- a/pkg/nnbd_migration/test/already_migrated_code_decorator_test.dart
+++ b/pkg/nnbd_migration/test/already_migrated_code_decorator_test.dart
@@ -39,8 +39,13 @@
   Element element = _MockElement();
 
   _AlreadyMigratedCodeDecoratorTestBase(NullabilitySuffix nullabilitySuffix)
-      : this._(nullabilitySuffix, NullabilityGraphForTesting(),
-            TestTypeProvider(nullabilitySuffix: nullabilitySuffix));
+      : this._(
+          nullabilitySuffix,
+          NullabilityGraphForTesting(),
+          TestTypeProvider(
+              isNonNullableByDefault:
+                  nullabilitySuffix == NullabilitySuffix.none),
+        );
 
   _AlreadyMigratedCodeDecoratorTestBase._(
       this.suffix, this.graph, this.typeProvider)
diff --git a/pkg/nnbd_migration/test/api_test.dart b/pkg/nnbd_migration/test/api_test.dart
index 91a9d171..a2efe64 100644
--- a/pkg/nnbd_migration/test/api_test.dart
+++ b/pkg/nnbd_migration/test/api_test.dart
@@ -100,7 +100,6 @@
     await _checkSingleFileChanges(content, expected);
   }
 
-  @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/38341')
   test_back_propagation_stops_at_implicitly_typed_variables() async {
     var content = '''
 class C {
@@ -1030,13 +1029,17 @@
     await _checkSingleFileChanges(content, expected);
   }
 
+  @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/39368')
   test_downcast_widest_type_from_top_type_parameters() async {
     var content = '''
 List<int> f1(dynamic a) => a;
 List<int> f2(Object b) => b;
 ''';
+    // Note: even though the type `dynamic` permits `null`, the migration engine
+    // sees that there is no code path that could cause `f1` to be passed a null
+    // value, so it leaves its return type as non-nullable.
     var expected = '''
-List<int?>? f1(dynamic a) => a;
+List<int?> f1(dynamic a) => a;
 List<int?> f2(Object b) => b;
 ''';
     await _checkSingleFileChanges(content, expected);
@@ -1209,6 +1212,76 @@
     await _checkSingleFileChanges(content, expected);
   }
 
+  test_field_initialized_at_declaration_site() async {
+    var content = '''
+class C {
+  int i = 0;
+  C();
+}
+''';
+    var expected = '''
+class C {
+  int i = 0;
+  C();
+}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
+  test_field_initialized_at_declaration_site_no_constructor() async {
+    var content = '''
+class C {
+  int i = 0;
+}
+''';
+    var expected = '''
+class C {
+  int i = 0;
+}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
+  test_field_initialized_in_constructor() async {
+    var content = '''
+class C {
+  int i;
+  C() : i = 0;
+}
+''';
+    var expected = '''
+class C {
+  int i;
+  C() : i = 0;
+}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
+  test_field_initialized_in_constructor_with_factories_and_redirects() async {
+    var content = '''
+class C {
+  int i;
+  C() : i = 0;
+  factory C.factoryConstructor => C();
+  factory C.factoryRedirect = D;
+  C.redirect : this();
+}
+class D extends C {}
+''';
+    var expected = '''
+class C {
+  int i;
+  C() : i = 0;
+  factory C.factoryConstructor => C();
+  factory C.factoryRedirect = D;
+  C.redirect : this();
+}
+class D extends C {}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
   test_field_initializer_simple() async {
     var content = '''
 class C {
@@ -1295,6 +1368,37 @@
     await _checkSingleFileChanges(content, expected);
   }
 
+  test_field_not_initialized() async {
+    var content = '''
+class C {
+  int i;
+  C();
+}
+''';
+    var expected = '''
+class C {
+  int? i;
+  C();
+}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
+  test_field_not_initialized_no_constructor() async {
+    var content = '''
+class C {
+  int i;
+}
+''';
+    var expected = '''
+class C {
+  int? i;
+}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
+  @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/39404')
   test_field_type_inferred() async {
     var content = '''
 int f() => null;
@@ -1305,15 +1409,14 @@
   }
 }
 ''';
-    // The type of x is inferred from its initializer, so it is non-nullable,
-    // even though we try to assign a nullable value to it.  So a null check
-    // must be added.
+    // The type of x is inferred as non-nullable from its initializer, but we
+    // try to assign a nullable value to it.  So an explicit type must be added.
     var expected = '''
 int? f() => null;
 class C {
-  var x = 1;
+  int? x = 1;
   void g() {
-    x = f()!;
+    x = f();
   }
 }
 ''';
@@ -1583,11 +1686,15 @@
 }
 Object g(C c) => c.f()();
 ''';
+    // Note: even though the type `dynamic` permits `null`, the migration engine
+    // sees that there is no code path that could cause `g` to return a null
+    // value, so it leaves its return type as `Object`, and there is an implicit
+    // downcast.
     var expected = '''
 abstract class C {
   Function() f();
 }
-Object? g(C c) => c.f()();
+Object g(C c) => c.f()();
 ''';
     await _checkSingleFileChanges(content, expected);
   }
@@ -1657,6 +1764,31 @@
     await _checkSingleFileChanges(content, expected);
   }
 
+  @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/39376')
+  test_infer_required() async {
+    var content = '''
+void _f(bool b, {int x}) {
+  if (b) {
+    print(x + 1);
+  }
+}
+main() {
+  _f(true, x: 1);
+}
+''';
+    var expected = '''
+void _f(bool b, {required int x}) {
+  if (b) {
+    print(x + 1);
+  }
+}
+main() {
+  _f(true, x: 1);
+}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
   test_inferred_method_parameter_type_non_nullable() async {
     var content = '''
 class B {
@@ -1895,6 +2027,7 @@
     await _checkSingleFileChanges(content, expected);
   }
 
+  @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/39404')
   test_localVariable_type_inferred() async {
     var content = '''
 int f() => null;
@@ -1903,14 +2036,13 @@
   x = f();
 }
 ''';
-    // The type of x is inferred from its initializer, so it is non-nullable,
-    // even though we try to assign a nullable value to it.  So a null check
-    // must be added.
+    // The type of x is inferred as non-nullable from its initializer, but we
+    // try to assign a nullable value to it.  So an explicit type must be added.
     var expected = '''
 int? f() => null;
 void main() {
-  var x = 1;
-  x = f()!;
+  int? x = 1;
+  x = f();
 }
 ''';
     await _checkSingleFileChanges(content, expected);
@@ -2279,7 +2411,6 @@
     await _checkSingleFileChanges(content, expected);
   }
 
-  @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/38344')
   test_not_definitely_assigned_value() async {
     var content = '''
 String f(bool b) {
@@ -2829,12 +2960,16 @@
     var content = '''
 Object f(x) => x;
 ''';
+    // Note: even though the type `dynamic` permits `null`, the migration engine
+    // sees that there is no code path that passes a null value to `f`, so it
+    // leaves its return type as `Object`, and there is an implicit downcast.
     var expected = '''
-Object? f(x) => x;
+Object f(x) => x;
 ''';
     await _checkSingleFileChanges(content, expected);
   }
 
+  @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/39369')
   test_topLevelFunction_returnType_implicit_dynamic() async {
     var content = '''
 f() {}
@@ -2847,6 +2982,7 @@
     await _checkSingleFileChanges(content, expected);
   }
 
+  @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/39404')
   test_topLevelVariable_type_inferred() async {
     var content = '''
 int f() => null;
@@ -2855,14 +2991,13 @@
   x = f();
 }
 ''';
-    // The type of x is inferred from its initializer, so it is non-nullable,
-    // even though we try to assign a nullable value to it.  So a null check
-    // must be added.
+    // The type of x is inferred as non-nullable from its initializer, but we
+    // try to assign a nullable value to it.  So an explicit type must be added.
     var expected = '''
 int? f() => null;
-var x = 1;
+int? x = 1;
 void main() {
-  x = f()!;
+  x = f();
 }
 ''';
     await _checkSingleFileChanges(content, expected);
diff --git a/pkg/nnbd_migration/test/edge_builder_flow_analysis_test.dart b/pkg/nnbd_migration/test/edge_builder_flow_analysis_test.dart
index 06c8b3c..25a7d20 100644
--- a/pkg/nnbd_migration/test/edge_builder_flow_analysis_test.dart
+++ b/pkg/nnbd_migration/test/edge_builder_flow_analysis_test.dart
@@ -219,9 +219,9 @@
     var iNode = decoratedTypeAnnotation('int i').node;
     var jNode = decoratedTypeAnnotation('int j').node;
     // No edge from i to `never` because i's type is promoted to non-nullable
-    assertNoEdge(iNode, never);
+    assertNoEdge(iNode, inSet(pointsToNever));
     // But there is an edge from j to `never`.
-    assertEdge(jNode, never, hard: true);
+    assertEdge(jNode, inSet(pointsToNever), hard: true);
   }
 
   test_binaryExpression_ampersandAmpersand_right() async {
@@ -236,9 +236,9 @@
     var iNode = decoratedTypeAnnotation('int i').node;
     var jNode = decoratedTypeAnnotation('int j').node;
     // No edge from i to `never` because i's type is promoted to non-nullable
-    assertNoEdge(iNode, never);
+    assertNoEdge(iNode, inSet(pointsToNever));
     // But there is an edge from j to `never`.
-    assertEdge(jNode, never, hard: false);
+    assertEdge(jNode, inSet(pointsToNever), hard: false);
   }
 
   test_binaryExpression_barBar_left() async {
@@ -249,9 +249,9 @@
     var iNode = decoratedTypeAnnotation('int i').node;
     var jNode = decoratedTypeAnnotation('int j').node;
     // No edge from i to `never` because i's type is promoted to non-nullable
-    assertNoEdge(iNode, never);
+    assertNoEdge(iNode, inSet(pointsToNever));
     // But there is an edge from j to `never`.
-    assertEdge(jNode, never, hard: true);
+    assertEdge(jNode, inSet(pointsToNever), hard: true);
   }
 
   test_binaryExpression_barBar_right() async {
@@ -266,9 +266,9 @@
     var iNode = decoratedTypeAnnotation('int i').node;
     var jNode = decoratedTypeAnnotation('int j').node;
     // No edge from i to `never` because i's type is promoted to non-nullable
-    assertNoEdge(iNode, never);
+    assertNoEdge(iNode, inSet(pointsToNever));
     // But there is an edge from j to `never`.
-    assertEdge(jNode, never, hard: false);
+    assertEdge(jNode, inSet(pointsToNever), hard: false);
   }
 
   test_booleanLiteral_false() async {
@@ -284,9 +284,9 @@
     var jNode = decoratedTypeAnnotation('int j').node;
     // No edge from i to never i is known to be non-nullable at the site of
     // the call to i.isEven
-    assertNoEdge(iNode, never);
+    assertNoEdge(iNode, inSet(pointsToNever));
     // But there is an edge from j to never
-    assertEdge(jNode, never, hard: false);
+    assertEdge(jNode, inSet(pointsToNever), hard: false);
   }
 
   test_booleanLiteral_true() async {
@@ -302,9 +302,9 @@
     var jNode = decoratedTypeAnnotation('int j').node;
     // No edge from i to never i is known to be non-nullable at the site of
     // the call to i.isEven
-    assertNoEdge(iNode, never);
+    assertNoEdge(iNode, inSet(pointsToNever));
     // But there is an edge from j to never
-    assertEdge(jNode, never, hard: false);
+    assertEdge(jNode, inSet(pointsToNever), hard: false);
   }
 
   test_break_labeled() async {
@@ -458,10 +458,10 @@
     var jNode = decoratedTypeAnnotation('int j').node;
     var kNode = decoratedTypeAnnotation('int k').node;
     // No edge from i to never because i is promoted.
-    assertNoEdge(iNode, never);
+    assertNoEdge(iNode, inSet(pointsToNever));
     // But there are edges from j and k to never.
-    assertEdge(jNode, never, hard: false);
-    assertEdge(kNode, never, hard: false);
+    assertEdge(jNode, inSet(pointsToNever), hard: false);
+    assertEdge(kNode, inSet(pointsToNever), hard: false);
   }
 
   test_constructorDeclaration_assert() async {
@@ -473,9 +473,9 @@
     var iNode = decoratedTypeAnnotation('int i').node;
     var jNode = decoratedTypeAnnotation('int j').node;
     // No edge from i to `never` because i's type is promoted to non-nullable
-    assertNoEdge(iNode, never);
+    assertNoEdge(iNode, inSet(pointsToNever));
     // But there is an edge from j to `never`.
-    assertEdge(jNode, never, hard: true);
+    assertEdge(jNode, inSet(pointsToNever), hard: true);
   }
 
   test_constructorDeclaration_initializer() async {
@@ -489,9 +489,9 @@
     var iNode = decoratedTypeAnnotation('int i').node;
     var jNode = decoratedTypeAnnotation('int j').node;
     // No edge from i to `never` because i's type is promoted to non-nullable
-    assertNoEdge(iNode, never);
+    assertNoEdge(iNode, inSet(pointsToNever));
     // But there is an edge from j to `never`.
-    assertEdge(jNode, never, hard: true);
+    assertEdge(jNode, inSet(pointsToNever), hard: true);
   }
 
   test_constructorDeclaration_redirection() async {
@@ -504,9 +504,9 @@
     var iNode = decoratedTypeAnnotation('int i').node;
     var jNode = decoratedTypeAnnotation('int j').node;
     // No edge from i to `never` because i's type is promoted to non-nullable
-    assertNoEdge(iNode, never);
+    assertNoEdge(iNode, inSet(pointsToNever));
     // But there is an edge from j to `never`.
-    assertEdge(jNode, never, hard: true);
+    assertEdge(jNode, inSet(pointsToNever), hard: true);
   }
 
   test_continue_labeled() async {
@@ -595,9 +595,9 @@
     var iNode = decoratedTypeAnnotation('int i').node;
     var jNode = decoratedTypeAnnotation('int j').node;
     // No edge from i to never because is is promoted.
-    assertNoEdge(iNode, never);
+    assertNoEdge(iNode, inSet(pointsToNever));
     // But there is an edge from j to never because its promotion was cancelled.
-    assertEdge(jNode, never, hard: false);
+    assertEdge(jNode, inSet(pointsToNever), hard: false);
   }
 
   test_do_cancels_promotions_for_assignments_in_condition() async {
@@ -612,9 +612,9 @@
     var iNode = decoratedTypeAnnotation('int i').node;
     var jNode = decoratedTypeAnnotation('int j').node;
     // No edge from i to never because is is promoted.
-    assertNoEdge(iNode, never);
+    assertNoEdge(iNode, inSet(pointsToNever));
     // But there is an edge from j to never because its promotion was cancelled.
-    assertEdge(jNode, never, hard: false);
+    assertEdge(jNode, inSet(pointsToNever), hard: false);
   }
 
   test_do_continue_target() async {
@@ -740,9 +740,9 @@
     var iNode = decoratedTypeAnnotation('int i').node;
     var jNode = decoratedTypeAnnotation('int j').node;
     // No edge from i to never because is is promoted.
-    assertNoEdge(iNode, never);
+    assertNoEdge(iNode, inSet(pointsToNever));
     // But there is an edge from j to never because its promotion was cancelled.
-    assertEdge(jNode, never, hard: false);
+    assertEdge(jNode, inSet(pointsToNever), hard: false);
   }
 
   test_for_cancels_promotions_for_assignments_in_updaters() async {
@@ -759,9 +759,9 @@
     var iNode = decoratedTypeAnnotation('int i').node;
     var jNode = decoratedTypeAnnotation('int j').node;
     // No edge from i to never because is is promoted.
-    assertNoEdge(iNode, never);
+    assertNoEdge(iNode, inSet(pointsToNever));
     // But there is an edge from j to never because its promotion was cancelled.
-    assertEdge(jNode, never, hard: false);
+    assertEdge(jNode, inSet(pointsToNever), hard: false);
   }
 
   test_for_collection_cancels_promotions_for_assignments_in_body() async {
@@ -775,9 +775,9 @@
     var iNode = decoratedTypeAnnotation('int i').node;
     var jNode = decoratedTypeAnnotation('int j').node;
     // No edge from i to never because is is promoted.
-    assertNoEdge(iNode, never);
+    assertNoEdge(iNode, inSet(pointsToNever));
     // But there is an edge from j to never because its promotion was cancelled.
-    assertEdge(jNode, never, hard: false);
+    assertEdge(jNode, inSet(pointsToNever), hard: false);
   }
 
   test_for_collection_cancels_promotions_for_assignments_in_updaters() async {
@@ -791,9 +791,9 @@
     var iNode = decoratedTypeAnnotation('int i').node;
     var jNode = decoratedTypeAnnotation('int j').node;
     // No edge from i to never because is is promoted.
-    assertNoEdge(iNode, never);
+    assertNoEdge(iNode, inSet(pointsToNever));
     // But there is an edge from j to never because its promotion was cancelled.
-    assertEdge(jNode, never, hard: false);
+    assertEdge(jNode, inSet(pointsToNever), hard: false);
   }
 
   test_for_collection_preserves_promotions_for_assignments_in_initializer() async {
@@ -808,9 +808,9 @@
     var iNode = decoratedTypeAnnotation('int i').node;
     var jNode = decoratedTypeAnnotation('int j').node;
     // No edge from i to never because it is promoted.
-    assertNoEdge(iNode, never);
+    assertNoEdge(iNode, inSet(pointsToNever));
     // But there is an edge from j to never.
-    assertEdge(jNode, never, hard: false);
+    assertEdge(jNode, inSet(pointsToNever), hard: false);
   }
 
   test_for_continue_target() async {
@@ -881,9 +881,9 @@
     var iNode = decoratedTypeAnnotation('int i').node;
     var jNode = decoratedTypeAnnotation('int j').node;
     // No edge from i to never because is is promoted.
-    assertNoEdge(iNode, never);
+    assertNoEdge(iNode, inSet(pointsToNever));
     // But there is an edge from j to never because its promotion was cancelled.
-    assertEdge(jNode, never, hard: false);
+    assertEdge(jNode, inSet(pointsToNever), hard: false);
   }
 
   test_for_each_collection_assigns_to_declared_var() async {
@@ -922,9 +922,9 @@
     var iNode = decoratedTypeAnnotation('int i').node;
     var jNode = decoratedTypeAnnotation('int j').node;
     // No edge from i to never because is is promoted.
-    assertNoEdge(iNode, never);
+    assertNoEdge(iNode, inSet(pointsToNever));
     // But there is an edge from j to never because its promotion was cancelled.
-    assertEdge(jNode, never, hard: false);
+    assertEdge(jNode, inSet(pointsToNever), hard: false);
   }
 
   test_for_each_collection_preserves_promotions_for_assignments_in_iterable() async {
@@ -939,9 +939,9 @@
     var iNode = decoratedTypeAnnotation('int i').node;
     var jNode = decoratedTypeAnnotation('int j').node;
     // No edge from i to never because it is promoted.
-    assertNoEdge(iNode, never);
+    assertNoEdge(iNode, inSet(pointsToNever));
     // But there is an edge from j to never.
-    assertEdge(jNode, never, hard: false);
+    assertEdge(jNode, inSet(pointsToNever), hard: false);
   }
 
   test_for_each_preserves_promotions_for_assignments_in_iterable() async {
@@ -956,9 +956,9 @@
     var iNode = decoratedTypeAnnotation('int i').node;
     var jNode = decoratedTypeAnnotation('int j').node;
     // No edge from i to never because it is promoted.
-    assertNoEdge(iNode, never);
+    assertNoEdge(iNode, inSet(pointsToNever));
     // But there is an edge from j to never.
-    assertEdge(jNode, never, hard: false);
+    assertEdge(jNode, inSet(pointsToNever), hard: false);
   }
 
   test_for_preserves_promotions_for_assignments_in_initializer() async {
@@ -973,9 +973,9 @@
     var iNode = decoratedTypeAnnotation('int i').node;
     var jNode = decoratedTypeAnnotation('int j').node;
     // No edge from i to never because it is promoted.
-    assertNoEdge(iNode, never);
+    assertNoEdge(iNode, inSet(pointsToNever));
     // But there is an edge from j to never.
-    assertEdge(jNode, never, hard: false);
+    assertEdge(jNode, inSet(pointsToNever), hard: false);
   }
 
   test_functionDeclaration() async {
@@ -989,9 +989,9 @@
     var iNode = decoratedTypeAnnotation('int i').node;
     var jNode = decoratedTypeAnnotation('int j').node;
     // No edge from i to `never` because i's type is promoted to non-nullable
-    assertNoEdge(iNode, never);
+    assertNoEdge(iNode, inSet(pointsToNever));
     // But there is an edge from j to `never`.
-    assertEdge(jNode, never, hard: false);
+    assertEdge(jNode, inSet(pointsToNever), hard: false);
   }
 
   test_functionDeclaration_expression_body() async {
@@ -1002,9 +1002,9 @@
     var iNode = decoratedTypeAnnotation('int i').node;
     var jNode = decoratedTypeAnnotation('int j').node;
     // No edge from i to `never` because i's type is promoted to non-nullable
-    assertNoEdge(iNode, never);
+    assertNoEdge(iNode, inSet(pointsToNever));
     // But there is an edge from j to `never`.
-    assertEdge(jNode, never, hard: true);
+    assertEdge(jNode, inSet(pointsToNever), hard: true);
   }
 
   test_functionDeclaration_resets_unconditional_control_flow() async {
@@ -1036,9 +1036,9 @@
     var iNode = decoratedTypeAnnotation('int i').node;
     var jNode = decoratedTypeAnnotation('int j').node;
     // No edge from i to `never` because i's type is promoted to non-nullable
-    assertNoEdge(iNode, never);
+    assertNoEdge(iNode, inSet(pointsToNever));
     // But there is an edge from j to `never`.
-    assertEdge(jNode, never, hard: false);
+    assertEdge(jNode, inSet(pointsToNever), hard: false);
   }
 
   test_if() async {
@@ -1159,9 +1159,9 @@
     var iNode = decoratedTypeAnnotation('int i').node;
     var jNode = decoratedTypeAnnotation('int j').node;
     // No edge from i to `never` because i's type is promoted to non-nullable
-    assertNoEdge(iNode, never);
+    assertNoEdge(iNode, inSet(pointsToNever));
     // But there is an edge from j to `never`.
-    assertEdge(jNode, never, hard: false);
+    assertEdge(jNode, inSet(pointsToNever), hard: false);
   }
 
   test_not() async {
@@ -1302,9 +1302,9 @@
     var iNode = decoratedTypeAnnotation('int i').node;
     var jNode = decoratedTypeAnnotation('int j').node;
     // No edge from i to `never` because i's type is promoted to non-nullable
-    assertNoEdge(iNode, never);
+    assertNoEdge(iNode, inSet(pointsToNever));
     // But there is an edge from j to `never`.
-    assertEdge(jNode, never, hard: false);
+    assertEdge(jNode, inSet(pointsToNever), hard: false);
   }
 
   test_return() async {
@@ -1318,9 +1318,9 @@
     var iNode = decoratedTypeAnnotation('int i').node;
     var jNode = decoratedTypeAnnotation('int j').node;
     // No edge from i to `never` because i's type is promoted to non-nullable
-    assertNoEdge(iNode, never);
+    assertNoEdge(iNode, inSet(pointsToNever));
     // But there is an edge from j to `never`.
-    assertEdge(jNode, never, hard: false);
+    assertEdge(jNode, inSet(pointsToNever), hard: false);
   }
 
   test_switch_break_target() async {
@@ -1403,10 +1403,10 @@
     var jNode = decoratedTypeAnnotation('int j').node;
     // No edge from i to `never` because the switch statement is guaranteed to
     // complete by returning, so i is promoted to non-nullable.
-    assertNoEdge(iNode, never);
+    assertNoEdge(iNode, inSet(pointsToNever));
     // But there is an edge from j to never, because the switch statement is not
     // guaranteed to complete by returning, so j is not promoted.
-    assertEdge(jNode, never, hard: false);
+    assertEdge(jNode, inSet(pointsToNever), hard: false);
   }
 
   test_throw() async {
@@ -1420,9 +1420,9 @@
     var iNode = decoratedTypeAnnotation('int i').node;
     var jNode = decoratedTypeAnnotation('int j').node;
     // No edge from i to `never` because i's type is promoted to non-nullable
-    assertNoEdge(iNode, never);
+    assertNoEdge(iNode, inSet(pointsToNever));
     // But there is an edge from j to `never`.
-    assertEdge(jNode, never, hard: true);
+    assertEdge(jNode, inSet(pointsToNever), hard: true);
   }
 
   test_topLevelVar_initializer() async {
@@ -1499,9 +1499,9 @@
     var iNode = decoratedTypeAnnotation('int i').node;
     var jNode = decoratedTypeAnnotation('int j').node;
     // No edge from i to never because is is promoted.
-    assertNoEdge(iNode, never);
+    assertNoEdge(iNode, inSet(pointsToNever));
     // But there is an edge from j to never because its promotion was cancelled.
-    assertEdge(jNode, never, hard: false);
+    assertEdge(jNode, inSet(pointsToNever), hard: false);
   }
 
   test_while_cancels_promotions_for_assignments_in_condition() async {
@@ -1516,9 +1516,9 @@
     var iNode = decoratedTypeAnnotation('int i').node;
     var jNode = decoratedTypeAnnotation('int j').node;
     // No edge from i to never because is is promoted.
-    assertNoEdge(iNode, never);
+    assertNoEdge(iNode, inSet(pointsToNever));
     // But there is an edge from j to never because its promotion was cancelled.
-    assertEdge(jNode, never, hard: false);
+    assertEdge(jNode, inSet(pointsToNever), hard: false);
   }
 
   test_while_promotes() async {
@@ -1533,8 +1533,8 @@
     var iNode = decoratedTypeAnnotation('int i').node;
     var jNode = decoratedTypeAnnotation('int j').node;
     // No edge from i to never because is is promoted.
-    assertNoEdge(iNode, never);
+    assertNoEdge(iNode, inSet(pointsToNever));
     // But there is an edge from j to never.
-    assertEdge(jNode, never, hard: false);
+    assertEdge(jNode, inSet(pointsToNever), hard: false);
   }
 }
diff --git a/pkg/nnbd_migration/test/edge_builder_test.dart b/pkg/nnbd_migration/test/edge_builder_test.dart
index 9bf66c5..3ccc983 100644
--- a/pkg/nnbd_migration/test/edge_builder_test.dart
+++ b/pkg/nnbd_migration/test/edge_builder_test.dart
@@ -48,8 +48,16 @@
     var typeProvider = TestTypeProvider();
     var graph = NullabilityGraphForTesting();
     var decoratedClassHierarchy = _DecoratedClassHierarchyForTesting();
-    var checker = AssignmentCheckerForTesting(Dart2TypeSystem(typeProvider),
-        typeProvider, graph, decoratedClassHierarchy);
+    var checker = AssignmentCheckerForTesting(
+        TypeSystemImpl(
+          implicitCasts: true,
+          isNonNullableByDefault: false,
+          strictInference: false,
+          typeProvider: typeProvider,
+        ),
+        typeProvider,
+        graph,
+        decoratedClassHierarchy);
     var assignmentCheckerTest =
         AssignmentCheckerTest._(typeProvider, graph, checker);
     decoratedClassHierarchy.assignmentCheckerTest = assignmentCheckerTest;
@@ -97,7 +105,7 @@
     var t2 = typeParameterType(typeParameter('T', bound));
     assign(t1, t2, hard: true);
     assertEdge(t1.node, t2.node, hard: true);
-    assertNoEdge(t1.node, bound.node);
+    assertEdge(t1.node, bound.node, hard: false);
     assertEdge(t1.typeArguments[0].node, bound.typeArguments[0].node,
         hard: false);
   }
@@ -457,7 +465,7 @@
     var parameterType = decoratedTypeAnnotation('List<int> x');
     var tType = decoratedTypeAnnotation('T f');
     assertEdge(parameterType.node, tType.node, hard: true);
-    assertNoEdge(parameterType.node, boundType.node);
+    assertEdge(parameterType.node, boundType.node, hard: false);
     // TODO(mfairhurst): Confirm we want this edge.
     assertEdge(
         parameterType.typeArguments[0].node, boundType.typeArguments[0].node,
@@ -522,7 +530,7 @@
 
     assertEdge(
         substitutionNode(
-            decoratedTypeAnnotation('int> x').node, inSet(neverClosure)),
+            decoratedTypeAnnotation('int> x').node, inSet(pointsToNever)),
         decoratedTypeAnnotation('int> f').node,
         hard: false);
     assertNoEdge(decoratedTypeAnnotation('int> x').node,
@@ -600,7 +608,7 @@
     var listInt = decoratedTypeAnnotation('List<int>');
     assertEdge(listInt.node, iterableInt.node, hard: true);
     assertEdge(
-        substitutionNode(listInt.typeArguments[0].node, inSet(neverClosure)),
+        substitutionNode(listInt.typeArguments[0].node, inSet(pointsToNever)),
         iterableInt.typeArguments[0].node,
         hard: false);
   }
@@ -622,8 +630,9 @@
 C f(C y, C z) => (y += z);
 ''';
     await analyze(code);
-    var targetEdge =
-        assertEdge(decoratedTypeAnnotation('C y').node, never, hard: true);
+    var targetEdge = assertEdge(
+        decoratedTypeAnnotation('C y').node, inSet(pointsToNever),
+        hard: true);
     expect(
         (graph.getEdgeOrigin(targetEdge) as CompoundAssignmentOrigin)
             .node
@@ -660,8 +669,9 @@
 C<int> f(C<int> y, C<int> z) => (y += z);
 ''';
     await analyze(code);
-    var targetEdge =
-        assertEdge(decoratedTypeAnnotation('C<int> y').node, never, hard: true);
+    var targetEdge = assertEdge(
+        decoratedTypeAnnotation('C<int> y').node, inSet(pointsToNever),
+        hard: true);
     expect(
         (graph.getEdgeOrigin(targetEdge) as CompoundAssignmentOrigin)
             .node
@@ -1041,7 +1051,8 @@
         decoratedTypeAnnotation('int z').node,
         hard: true);
     assertNoEdge(decoratedTypeAnnotation('int g').node, anyNode);
-    assertEdge(always, decoratedTypeAnnotation('Object f').node, hard: false);
+    assertEdge(inSet(alwaysPlus), decoratedTypeAnnotation('Object f').node,
+        hard: false);
   }
 
   test_binaryExpression_lt_result_not_null() async {
@@ -1165,7 +1176,7 @@
 
     assertNullCheck(
         checkExpression('j;'),
-        assertEdge(decoratedTypeAnnotation('int j').node, inSet(neverClosure),
+        assertEdge(decoratedTypeAnnotation('int j').node, inSet(pointsToNever),
             hard: true));
   }
 
@@ -1508,7 +1519,7 @@
     var yType = decoratedGenericFunctionTypeAnnotation('void Function() y');
     var resultType = decoratedExpressionType('(b ?');
     assertLUB(resultType.node, xType.node, yType.node);
-    expect(resultType.returnType.node, same(always));
+    expect(resultType.returnType.node.isImmutable, false);
   }
 
   test_conditionalExpression_general() async {
@@ -1772,7 +1783,7 @@
 ''');
     var xType =
         variables.decoratedElementType(findNode.simple('x').staticElement);
-    assertUnion(xType.node, decoratedTypeAnnotation('int').node);
+    assertEdge(decoratedTypeAnnotation('int').node, xType.node, hard: false);
   }
 
   test_fieldFormalParameter_function_typed() async {
@@ -1831,7 +1842,7 @@
     assertEdge(decoratedTypeAnnotation('List<int>').node, never, hard: true);
     assertEdge(
         substitutionNode(
-            decoratedTypeAnnotation('int> l').node, inSet(neverClosure)),
+            decoratedTypeAnnotation('int> l').node, inSet(pointsToNever)),
         decoratedTypeAnnotation('int i').node,
         hard: false);
   }
@@ -1850,7 +1861,7 @@
     assertEdge(decoratedTypeAnnotation('List<int>').node, never, hard: true);
     assertEdge(
         substitutionNode(
-            decoratedTypeAnnotation('int> l').node, inSet(neverClosure)),
+            decoratedTypeAnnotation('int> l').node, inSet(pointsToNever)),
         iNode,
         hard: false);
   }
@@ -1865,7 +1876,7 @@
     assertEdge(decoratedTypeAnnotation('List<int>').node, never, hard: true);
     assertEdge(
         substitutionNode(
-            decoratedTypeAnnotation('int> l').node, inSet(neverClosure)),
+            decoratedTypeAnnotation('int> l').node, inSet(pointsToNever)),
         decoratedTypeAnnotation('int x').node,
         hard: false);
   }
@@ -1879,7 +1890,7 @@
     assertEdge(decoratedTypeAnnotation('List<int>').node, never, hard: true);
     assertEdge(
         substitutionNode(
-            decoratedTypeAnnotation('int> l').node, inSet(neverClosure)),
+            decoratedTypeAnnotation('int> l').node, inSet(pointsToNever)),
         decoratedTypeAnnotation('int i').node,
         hard: false);
   }
@@ -1900,7 +1911,7 @@
     assertEdge(decoratedTypeAnnotation('List<int>').node, never, hard: true);
     assertEdge(
         substitutionNode(
-            decoratedTypeAnnotation('int> l').node, inSet(neverClosure)),
+            decoratedTypeAnnotation('int> l').node, inSet(pointsToNever)),
         iNode,
         hard: false);
   }
@@ -1915,7 +1926,7 @@
     assertEdge(decoratedTypeAnnotation('List<int>').node, never, hard: true);
     assertEdge(
         substitutionNode(
-            decoratedTypeAnnotation('int> l').node, inSet(neverClosure)),
+            decoratedTypeAnnotation('int> l').node, inSet(pointsToNever)),
         decoratedTypeAnnotation('int x').node,
         hard: false);
   }
@@ -2545,7 +2556,8 @@
 ''');
     // We assume that the index expression might evaluate to anything, including
     // `null`.
-    assertEdge(always, decoratedTypeAnnotation('int f').node, hard: false);
+    assertEdge(inSet(alwaysPlus), decoratedTypeAnnotation('int f').node,
+        hard: false);
   }
 
   test_indexExpression_index() async {
@@ -2787,21 +2799,24 @@
     await analyze('''
 int f(dynamic g) => g();
 ''');
-    assertEdge(always, decoratedTypeAnnotation('int f').node, hard: false);
+    assertEdge(inSet(alwaysPlus), decoratedTypeAnnotation('int f').node,
+        hard: false);
   }
 
   test_invocation_dynamic_parenthesized() async {
     await analyze('''
 int f(dynamic g) => (g)();
 ''');
-    assertEdge(always, decoratedTypeAnnotation('int f').node, hard: false);
+    assertEdge(inSet(alwaysPlus), decoratedTypeAnnotation('int f').node,
+        hard: false);
   }
 
   test_invocation_function() async {
     await analyze('''
 int f(Function g) => g();
 ''');
-    assertEdge(always, decoratedTypeAnnotation('int f').node, hard: false);
+    assertEdge(inSet(alwaysPlus), decoratedTypeAnnotation('int f').node,
+        hard: false);
     assertNullCheck(
         checkExpression('g('),
         assertEdge(decoratedTypeAnnotation('Function g').node, never,
@@ -2812,7 +2827,8 @@
     await analyze('''
 int f(Function g) => (g)();
 ''');
-    assertEdge(always, decoratedTypeAnnotation('int f').node, hard: false);
+    assertEdge(inSet(alwaysPlus), decoratedTypeAnnotation('int f').node,
+        hard: false);
     assertNullCheck(
         checkExpression('g)('),
         assertEdge(decoratedTypeAnnotation('Function g').node, never,
@@ -2878,7 +2894,7 @@
 bool f(a) => a is String;
 ''');
     assertNoUpstreamNullability(decoratedTypeAnnotation('bool').node);
-    assertEdge(decoratedTypeAnnotation('String').node, never, hard: false);
+    assertEdge(decoratedTypeAnnotation('String').node, never, hard: true);
   }
 
   test_isExpression_typeName_typeArguments() async {
@@ -2886,7 +2902,7 @@
 bool f(a) => a is List<int>;
 ''');
     assertNoUpstreamNullability(decoratedTypeAnnotation('bool').node);
-    assertEdge(decoratedTypeAnnotation('List').node, never, hard: false);
+    assertEdge(decoratedTypeAnnotation('List').node, never, hard: true);
     assertEdge(always, decoratedTypeAnnotation('int').node, hard: false);
   }
 
@@ -2973,7 +2989,7 @@
 ''');
     var xType =
         variables.decoratedElementType(findNode.simple('x').staticElement);
-    assertUnion(xType.node, decoratedTypeAnnotation('int').node);
+    assertEdge(decoratedTypeAnnotation('int').node, xType.node, hard: false);
   }
 
   test_method_parameterType_inferred() async {
@@ -3070,7 +3086,8 @@
     assertNoEdge(decoratedTypeAnnotation('int g').node,
         decoratedTypeAnnotation('int f').node);
     // We do, however, assume that it might return anything, including `null`.
-    assertEdge(always, decoratedTypeAnnotation('int f').node, hard: false);
+    assertEdge(inSet(alwaysPlus), decoratedTypeAnnotation('int f').node,
+        hard: false);
   }
 
   test_methodInvocation_dynamic_arguments() async {
@@ -3238,7 +3255,7 @@
 ''');
     var nullable_j = decoratedTypeAnnotation('int j');
     assertNullCheck(checkExpression('j/*check*/'),
-        assertEdge(nullable_j.node, inSet(neverClosure), hard: true));
+        assertEdge(nullable_j.node, inSet(pointsToNever), hard: true));
   }
 
   test_methodInvocation_resolves_to_getter() async {
@@ -4415,7 +4432,7 @@
     assertNullCheck(check_b, assertEdge(nullable_b, never, hard: true));
 
     var return_f = decoratedTypeAnnotation('bool f').node;
-    assertEdge(never, return_f, hard: false);
+    assertEdge(inSet(pointsToNever), return_f, hard: false);
   }
 
   test_prefixExpression_bang_dynamic() async {
@@ -4425,7 +4442,7 @@
 }
 ''');
     var return_f = decoratedTypeAnnotation('Object f').node;
-    assertEdge(never, return_f, hard: false);
+    assertEdge(inSet(pointsToNever), return_f, hard: false);
   }
 
   test_prefixExpression_minus() async {
@@ -4446,7 +4463,7 @@
     await analyze('''
 Object test(dynamic d) => -d;
 ''');
-    assertEdge(always, decoratedTypeAnnotation('Object test').node,
+    assertEdge(inSet(alwaysPlus), decoratedTypeAnnotation('Object test').node,
         hard: false);
     assertEdge(decoratedTypeAnnotation('dynamic d').node, never, hard: true);
   }
@@ -4483,7 +4500,7 @@
     assertNullCheck(use, assertEdge(declaration, never, hard: true));
 
     var returnType = decoratedTypeAnnotation('int f').node;
-    assertEdge(inSet(neverClosure), returnType, hard: false);
+    assertEdge(inSet(pointsToNever), returnType, hard: false);
   }
 
   test_prefixExpression_plusPlus() async {
@@ -4498,7 +4515,7 @@
     assertNullCheck(use, assertEdge(declaration, never, hard: true));
 
     var returnType = decoratedTypeAnnotation('int f').node;
-    assertEdge(inSet(neverClosure), returnType, hard: false);
+    assertEdge(inSet(pointsToNever), returnType, hard: false);
   }
 
   test_prefixExpression_plusPlus_dynamic() async {
@@ -4508,7 +4525,7 @@
 }
 ''');
     var returnType = decoratedTypeAnnotation('Object f').node;
-    assertEdge(always, returnType, hard: false);
+    assertEdge(inSet(alwaysPlus), returnType, hard: false);
   }
 
   test_prefixExpression_plusPlus_substituted() async {
@@ -4544,7 +4561,8 @@
     assertNoEdge(decoratedTypeAnnotation('int get g').node,
         decoratedTypeAnnotation('int f').node);
     // We do, however, assume that it might return anything, including `null`.
-    assertEdge(always, decoratedTypeAnnotation('int f').node, hard: false);
+    assertEdge(inSet(alwaysPlus), decoratedTypeAnnotation('int f').node,
+        hard: false);
   }
 
   test_propertyAccess_object_property() async {
@@ -5199,7 +5217,8 @@
 ''');
     assertEdge(
         substitutionNode(
-            substitutionNode(never, decoratedTypeAnnotation('T> {').node),
+            substitutionNode(
+                inSet(pointsToNever), decoratedTypeAnnotation('T> {').node),
             decoratedTypeAnnotation('U g').node),
         decoratedTypeAnnotation('T f').node,
         hard: false);
@@ -5248,7 +5267,7 @@
 main() { x = 1; }
 ''');
     var setXType = decoratedTypeAnnotation('int value');
-    assertEdge(never, setXType.node, hard: false);
+    assertEdge(inSet(pointsToNever), setXType.node, hard: false);
   }
 
   test_topLevelSetter_nullable() async {
@@ -5291,7 +5310,7 @@
 double get myPi => pi;
 ''');
     var myPiType = decoratedTypeAnnotation('double get');
-    assertEdge(inSet(neverClosure), myPiType.node, hard: false);
+    assertEdge(inSet(pointsToNever), myPiType.node, hard: false);
   }
 
   test_topLevelVariable_type_inferred() async {
@@ -5301,7 +5320,7 @@
 ''');
     var xType =
         variables.decoratedElementType(findNode.simple('x').staticElement);
-    assertUnion(xType.node, decoratedTypeAnnotation('int').node);
+    assertEdge(decoratedTypeAnnotation('int').node, xType.node, hard: false);
   }
 
   test_type_argument_explicit_bound() async {
@@ -5362,7 +5381,8 @@
 import 'dart:async' as a;
 Type f() => a.Future;
 ''');
-    assertEdge(never, decoratedTypeAnnotation('Type').node, hard: false);
+    assertEdge(inSet(neverClosure), decoratedTypeAnnotation('Type').node,
+        hard: false);
   }
 
   test_typeName_functionTypeAlias() async {
diff --git a/pkg/nnbd_migration/test/fix_builder_test.dart b/pkg/nnbd_migration/test/fix_builder_test.dart
index 6f1b668..76f7720 100644
--- a/pkg/nnbd_migration/test/fix_builder_test.dart
+++ b/pkg/nnbd_migration/test/fix_builder_test.dart
@@ -3,7 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/element/nullability_suffix.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/type_provider.dart';
@@ -31,8 +30,7 @@
   DartType get objectType => postMigrationTypeProvider.objectType;
 
   TypeProvider get postMigrationTypeProvider =>
-      (typeProvider as TypeProviderImpl)
-          .withNullability(NullabilitySuffix.none);
+      (typeProvider as TypeProviderImpl).asNonNullableByDefault;
 
   @override
   Future<CompilationUnit> analyze(String code) async {
@@ -2152,12 +2150,8 @@
 
   final Map<AstNode, Set<Problem>> problems = {};
 
-  _FixBuilder(
-      Source source,
-      DecoratedClassHierarchy decoratedClassHierarchy,
-      TypeProvider typeProvider,
-      Dart2TypeSystem typeSystem,
-      Variables variables)
+  _FixBuilder(Source source, DecoratedClassHierarchy decoratedClassHierarchy,
+      TypeProvider typeProvider, TypeSystemImpl typeSystem, Variables variables)
       : super(source, decoratedClassHierarchy, typeProvider, typeSystem,
             variables);
 
diff --git a/pkg/nnbd_migration/test/instrumentation_test.dart b/pkg/nnbd_migration/test/instrumentation_test.dart
index 38bdd97..5c97c1f 100644
--- a/pkg/nnbd_migration/test/instrumentation_test.dart
+++ b/pkg/nnbd_migration/test/instrumentation_test.dart
@@ -215,8 +215,9 @@
 }
 ''');
     var yUsage = findNode.simple('y);');
-    var entry =
-        fixes.entries.where((e) => e.key.location.offset == yUsage.end).single;
+    var entry = fixes.entries
+        .where((e) => e.key.locations.single.offset == yUsage.end)
+        .single;
     var reasons = entry.value;
     expect(reasons, hasLength(1));
     var edge = reasons[0] as EdgeInfo;
@@ -235,7 +236,7 @@
     var entries = fixes.entries.toList();
     expect(entries, hasLength(1));
     var intAnnotation = findNode.typeAnnotation('int');
-    expect(entries.single.key.location.offset, intAnnotation.end);
+    expect(entries.single.key.locations.single.offset, intAnnotation.end);
     var reasons = entries.single.value;
     expect(reasons, hasLength(1));
     expect(reasons.single, same(explicitTypeNullability[intAnnotation]));
@@ -562,6 +563,7 @@
         hasLength(1));
   }
 
+  @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/39370')
   test_implicitReturnType_functionTypeAlias() async {
     await analyze('''
 typedef F();
@@ -889,7 +891,7 @@
         explicitTypeNullability[findNode.typeAnnotation('String')];
     expect(
         edges.where((e) =>
-            e.sourceNode == never &&
+            _pointsToNeverHard(e.sourceNode) &&
             e.destinationNode == implicitMapLiteralKeyNode),
         hasLength(1));
     expect(
@@ -992,4 +994,9 @@
     return edges
         .any((e) => e.sourceNode == always && e.destinationNode == node);
   }
+
+  bool _pointsToNeverHard(NullabilityNodeInfo node) {
+    return edges.any(
+        (e) => e.sourceNode == node && e.destinationNode == never && e.isHard);
+  }
 }
diff --git a/pkg/nnbd_migration/test/migration_visitor_test_base.dart b/pkg/nnbd_migration/test/migration_visitor_test_base.dart
index c62a340..afee88d 100644
--- a/pkg/nnbd_migration/test/migration_visitor_test_base.dart
+++ b/pkg/nnbd_migration/test/migration_visitor_test_base.dart
@@ -180,6 +180,11 @@
     return result;
   }
 
+  /// Gets the set of nodes with hard edges pointing to never.
+  Set<NullabilityNode> get pointsToNever {
+    return {for (var edge in getEdges(anyNode, graph.never)) edge.sourceNode};
+  }
+
   /// Asserts that an edge exists with a node matching [source] and a node
   /// matching [destination], and with the given [hard]ness and [guards].
   ///
@@ -344,8 +349,8 @@
 
   TypeProvider get typeProvider => testAnalysisResult.typeProvider;
 
-  Dart2TypeSystem get typeSystem =>
-      testAnalysisResult.typeSystem as Dart2TypeSystem;
+  TypeSystemImpl get typeSystem =>
+      testAnalysisResult.typeSystem as TypeSystemImpl;
 
   Future<CompilationUnit> analyze(String code) async {
     await resolveTestUnit(code);
diff --git a/pkg/nnbd_migration/test/node_builder_test.dart b/pkg/nnbd_migration/test/node_builder_test.dart
index 963d3cf..708c1f6 100644
--- a/pkg/nnbd_migration/test/node_builder_test.dart
+++ b/pkg/nnbd_migration/test/node_builder_test.dart
@@ -39,7 +39,7 @@
     expect(exceptionType.node, TypeMatcher<NullabilityNodeMutable>());
     var stackTraceType =
         variables.decoratedElementType(findNode.simple('st').staticElement);
-    expect(stackTraceType.node, never);
+    assertEdge(stackTraceType.node, never, hard: true);
   }
 
   test_catch_clause_with_stacktrace_without_on() async {
@@ -50,10 +50,10 @@
 ''');
     var exceptionType =
         variables.decoratedElementType(findNode.simple('ex').staticElement);
-    expect(exceptionType.node, always);
+    expect(exceptionType.node.isImmutable, false);
     var stackTraceType =
         variables.decoratedElementType(findNode.simple('st').staticElement);
-    expect(stackTraceType.node, never);
+    assertEdge(stackTraceType.node, never, hard: true);
   }
 
   test_catch_clause_without_catch() async {
@@ -85,7 +85,7 @@
 ''');
     var exceptionType =
         variables.decoratedElementType(findNode.simple('ex').staticElement);
-    expect(exceptionType.node, always);
+    expect(exceptionType.node.isImmutable, false);
   }
 
   test_class_alias_synthetic_constructors_no_parameters() async {
@@ -312,7 +312,7 @@
     var types = decoratedDirectSupertypes('C');
     var decorated = types[typeProvider.objectType.element];
     expect(decorated.type.toString(), 'Object');
-    expect(decorated.node, same(never));
+    assertEdge(decorated.node, never, hard: true);
     expect(decorated.typeArguments, isEmpty);
   }
 
@@ -418,7 +418,7 @@
     var types = decoratedDirectSupertypes('C');
     var decorated = types[typeProvider.objectType.element];
     expect(decorated.type.toString(), 'Object');
-    expect(decorated.node, same(never));
+    assertEdge(decorated.node, never, hard: true);
     expect(decorated.typeArguments, isEmpty);
   }
 
@@ -460,7 +460,7 @@
 ''');
     var decoratedType = decoratedTypeAnnotation('dynamic');
     expect(decoratedFunctionType('f').returnType, same(decoratedType));
-    assertEdge(always, decoratedType.node, hard: false);
+    assertNoEdge(always, decoratedType.node);
   }
 
   test_field_type_implicit_dynamic() async {
@@ -471,7 +471,7 @@
 ''');
     var decoratedType =
         variables.decoratedElementType(findNode.simple('x').staticElement);
-    expect(decoratedType.node, same(always));
+    expect(decoratedType.node.isImmutable, false);
   }
 
   test_field_type_inferred() async {
@@ -494,7 +494,7 @@
 ''');
     var decoratedType =
         variables.decoratedElementType(findNode.simple('x').staticElement);
-    expect(decoratedType.node, same(always));
+    expect(decoratedType.node.isImmutable, false);
   }
 
   test_field_type_simple() async {
@@ -542,7 +542,7 @@
     expect(ctorType.positionalParameters[0], same(ctorParamType));
     expect(ctorParamType.node, TypeMatcher<NullabilityNodeMutable>());
     expect(ctorParamType.namedParameters['i'].type.toString(), 'dynamic');
-    expect(ctorParamType.namedParameters['i'].node, same(always));
+    expect(ctorParamType.namedParameters['i'].node.isImmutable, false);
   }
 
   test_fieldFormalParameter_function_positionalParameter_typed() async {
@@ -576,7 +576,7 @@
     expect(ctorType.positionalParameters[0], same(ctorParamType));
     expect(ctorParamType.node, TypeMatcher<NullabilityNodeMutable>());
     expect(ctorParamType.positionalParameters[0].type.toString(), 'dynamic');
-    expect(ctorParamType.positionalParameters[0].node, same(always));
+    expect(ctorParamType.positionalParameters[0].node.isImmutable, false);
   }
 
   test_fieldFormalParameter_function_return_typed() async {
@@ -609,7 +609,7 @@
     expect(ctorType.positionalParameters[0], same(ctorParamType));
     expect(ctorParamType.node, TypeMatcher<NullabilityNodeMutable>());
     expect(ctorParamType.returnType.type.toString(), 'dynamic');
-    expect(ctorParamType.returnType.node, same(always));
+    expect(ctorParamType.returnType.node.isImmutable, false);
   }
 
   test_fieldFormalParameter_typed() async {
@@ -665,7 +665,7 @@
     var decoratedType = decoratedFunctionType('f');
     var bound = decoratedTypeParameterBound('T>');
     expect(decoratedType.typeFormalBounds[0], same(bound));
-    assertUnion(always, bound.node);
+    assertNoEdge(always, bound.node);
     expect(bound.type, same(typeProvider.objectType));
   }
 
@@ -717,7 +717,7 @@
     await analyze('''
 typedef T F<T, U>(U u);
 ''');
-    var element = findElement.genericTypeAlias('F');
+    var element = findElement.functionTypeAlias('F');
     var decoratedType = variables.decoratedElementType(element);
     var t = element.typeParameters[0];
     var u = element.typeParameters[1];
@@ -743,9 +743,9 @@
 typedef F();
 ''');
     var decoratedType =
-        variables.decoratedElementType(findElement.genericTypeAlias('F'));
+        variables.decoratedElementType(findElement.functionTypeAlias('F'));
     expect(decoratedType.returnType.type.isDynamic, isTrue);
-    expect(decoratedType.returnType.node, same(always));
+    expect(decoratedType.returnType.node.isImmutable, false);
     expect(decoratedType.typeFormals, isEmpty);
   }
 
@@ -754,7 +754,7 @@
 typedef int F(String s);
 ''');
     var decoratedType =
-        variables.decoratedElementType(findElement.genericTypeAlias('F'));
+        variables.decoratedElementType(findElement.functionTypeAlias('F'));
     expect(decoratedType.returnType, same(decoratedTypeAnnotation('int')));
     expect(decoratedType.typeFormals, isEmpty);
     expect(decoratedType.positionalParameters[0],
@@ -785,7 +785,7 @@
     expect(fType.positionalParameters[0], same(gType));
     expect(gType.node, TypeMatcher<NullabilityNodeMutable>());
     expect(gType.namedParameters['i'].type.toString(), 'dynamic');
-    expect(gType.namedParameters['i'].node, same(always));
+    expect(gType.namedParameters['i'].node.isImmutable, false);
   }
 
   test_functionTypedFormalParameter_positionalParameter_typed() async {
@@ -812,7 +812,7 @@
     expect(fType.positionalParameters[0], same(gType));
     expect(gType.node, TypeMatcher<NullabilityNodeMutable>());
     expect(gType.positionalParameters[0].type.toString(), 'dynamic');
-    expect(gType.positionalParameters[0].node, same(always));
+    expect(gType.positionalParameters[0].node.isImmutable, false);
   }
 
   test_functionTypedFormalParameter_return_typed() async {
@@ -839,7 +839,7 @@
     expect(fType.positionalParameters[0], same(gType));
     expect(gType.node, TypeMatcher<NullabilityNodeMutable>());
     expect(gType.returnType.type.toString(), 'dynamic');
-    expect(gType.returnType.node, same(always));
+    expect(gType.returnType.node.isImmutable, false);
   }
 
   test_generic_function_type_syntax_inferred_dynamic_return() async {
@@ -852,7 +852,7 @@
     var decoratedFReturnType = decoratedFType.returnType;
     var decoratedFReturnReturnType = decoratedFReturnType.returnType;
     expect(decoratedFReturnReturnType.type.toString(), 'dynamic');
-    expect(decoratedFReturnReturnType.node, same(always));
+    expect(decoratedFReturnReturnType.node.isImmutable, false);
   }
 
   test_genericFunctionType_formal_bounds() async {
@@ -932,7 +932,7 @@
     await analyze('''
 typedef F = T Function<T, U>(U u);
 ''');
-    var element = findElement.genericTypeAlias('F');
+    var element = findElement.functionTypeAlias('F');
     var decoratedType = variables.decoratedElementType(element);
     expect(decoratedType,
         same(decoratedGenericFunctionTypeAnnotation('T Function')));
@@ -956,7 +956,7 @@
     await analyze('''
 typedef F<T, U> = T Function(U u);
 ''');
-    var element = findElement.genericTypeAlias('F');
+    var element = findElement.functionTypeAlias('F');
     var decoratedType = variables.decoratedElementType(element);
     expect(decoratedType,
         same(decoratedGenericFunctionTypeAnnotation('T Function')));
@@ -984,11 +984,11 @@
 typedef F = Function();
 ''');
     var decoratedType =
-        variables.decoratedElementType(findElement.genericTypeAlias('F'));
+        variables.decoratedElementType(findElement.functionTypeAlias('F'));
     expect(decoratedType,
         same(decoratedGenericFunctionTypeAnnotation('Function')));
     expect(decoratedType.returnType.type.isDynamic, isTrue);
-    expect(decoratedType.returnType.node, same(always));
+    expect(decoratedType.returnType.node.isImmutable, false);
     expect(decoratedType.typeFormals, isEmpty);
   }
 
@@ -997,7 +997,7 @@
 typedef F = int Function(String s);
 ''');
     var decoratedType =
-        variables.decoratedElementType(findElement.genericTypeAlias('F'));
+        variables.decoratedElementType(findElement.functionTypeAlias('F'));
     expect(decoratedType,
         same(decoratedGenericFunctionTypeAnnotation('int Function')));
     expect(decoratedType.returnType, same(decoratedTypeAnnotation('int')));
@@ -1016,7 +1016,7 @@
     expect(decoratedListType.node, isNotNull);
     expect(decoratedListType.node, isNot(never));
     var decoratedArgType = decoratedListType.typeArguments[0];
-    expect(decoratedArgType.node, same(always));
+    expect(decoratedArgType.node.isImmutable, false);
   }
 
   test_interfaceType_generic_instantiate_to_function_type() async {
@@ -1051,7 +1051,7 @@
     expect(decoratedArgType.node, TypeMatcher<NullabilityNodeMutable>());
     expect(decoratedArgType.typeArguments, isEmpty);
     var decoratedArgReturnType = decoratedArgType.returnType;
-    expect(decoratedArgReturnType.node, same(always));
+    expect(decoratedArgReturnType.node.isImmutable, false);
     expect(decoratedArgReturnType.typeArguments, isEmpty);
   }
 
@@ -1156,7 +1156,7 @@
 ''');
     var decoratedType =
         variables.decoratedElementType(findNode.simple('x').staticElement);
-    expect(decoratedType.node, same(always));
+    expect(decoratedType.node.isImmutable, false);
   }
 
   test_localVariable_type_inferred() async {
@@ -1179,7 +1179,7 @@
 ''');
     var decoratedType =
         variables.decoratedElementType(findNode.simple('x').staticElement);
-    expect(decoratedType.node, same(always));
+    expect(decoratedType.node.isImmutable, false);
   }
 
   test_method_generic_bounded() async {
@@ -1205,7 +1205,7 @@
     var decoratedType = decoratedMethodType('f');
     var bound = decoratedTypeParameterBound('T>');
     expect(decoratedType.typeFormalBounds[0], same(bound));
-    assertUnion(always, bound.node);
+    assertNoEdge(always, bound.node);
     expect(bound.type, same(typeProvider.objectType));
   }
 
@@ -1231,7 +1231,7 @@
 }
 ''');
     var decoratedType = decoratedMethodType('f').positionalParameters[0];
-    expect(decoratedType.node, same(always));
+    expect(decoratedType.node.isImmutable, false);
   }
 
   test_method_parameterType_implicit_dynamic_named() async {
@@ -1241,7 +1241,7 @@
 }
 ''');
     var decoratedType = decoratedMethodType('f').namedParameters['x'];
-    expect(decoratedType.node, same(always));
+    expect(decoratedType.node.isImmutable, false);
   }
 
   test_method_parameterType_inferred() async {
@@ -1267,7 +1267,7 @@
 }
 ''');
     var decoratedType = decoratedMethodType('f/*C*/').positionalParameters[0];
-    expect(decoratedType.node, same(always));
+    expect(decoratedType.node.isImmutable, false);
   }
 
   test_method_parameterType_inferred_dynamic_named() async {
@@ -1280,7 +1280,7 @@
 }
 ''');
     var decoratedType = decoratedMethodType('f/*C*/').namedParameters['x'];
-    expect(decoratedType.node, same(always));
+    expect(decoratedType.node.isImmutable, false);
   }
 
   test_method_parameterType_inferred_generic_function_typed_no_bound() async {
@@ -1339,7 +1339,7 @@
 }
 ''');
     var decoratedType = decoratedMethodType('f').returnType;
-    expect(decoratedType.node, same(always));
+    expect(decoratedType.node.isImmutable, false);
   }
 
   test_method_returnType_inferred() async {
@@ -1365,7 +1365,7 @@
 }
 ''');
     var decoratedType = decoratedMethodType('f/*C*/').returnType;
-    expect(decoratedType.node, same(always));
+    expect(decoratedType.node.isImmutable, false);
   }
 
   test_parameters() async {
@@ -1474,7 +1474,7 @@
 ''');
     var decoratedType =
         variables.decoratedElementType(findNode.simple('x').staticElement);
-    expect(decoratedType.node, same(always));
+    expect(decoratedType.node.isImmutable, false);
   }
 
   test_topLevelVariable_type_inferred() async {
@@ -1493,7 +1493,7 @@
 ''');
     var decoratedType =
         variables.decoratedElementType(findNode.simple('x').staticElement);
-    expect(decoratedType.node, same(always));
+    expect(decoratedType.node.isImmutable, false);
   }
 
   test_type_comment_bang() async {
@@ -1528,7 +1528,7 @@
 class C<T> {}
 ''');
     var bound = decoratedTypeParameterBound('T');
-    assertUnion(always, bound.node);
+    assertNoEdge(always, bound.node);
     expect(bound.type, same(typeProvider.objectType));
   }
 
@@ -1542,7 +1542,7 @@
     // This is necessary because there is no guarantee of whether the typedef or
     // its usage will be visited first.
     var typedefDecoratedType =
-        variables.decoratedElementType(findElement.genericTypeAlias('F'));
+        variables.decoratedElementType(findElement.functionTypeAlias('F'));
     var decoratedType = decoratedTypeAnnotation('F<int>');
     expect(decoratedType.node, TypeMatcher<NullabilityNodeMutable>());
     expect(decoratedType.node, isNot(same(typedefDecoratedType.node)));
@@ -1564,7 +1564,7 @@
     // This is necessary because there is no guarantee of whether the typedef or
     // its usage will be visited first.
     var typedefDecoratedType =
-        variables.decoratedElementType(findElement.genericTypeAlias('F'));
+        variables.decoratedElementType(findElement.functionTypeAlias('F'));
     var decoratedType = decoratedTypeAnnotation('F f');
     expect(decoratedType.node, TypeMatcher<NullabilityNodeMutable>());
     expect(decoratedType.node, isNot(same(typedefDecoratedType.node)));
@@ -1589,7 +1589,7 @@
     // This is necessary because there is no guarantee of whether the typedef or
     // its usage will be visited first.
     var typedefDecoratedType =
-        variables.decoratedElementType(findElement.genericTypeAlias('F'));
+        variables.decoratedElementType(findElement.functionTypeAlias('F'));
     var decoratedType = decoratedTypeAnnotation('F f');
     expect(decoratedType.node, TypeMatcher<NullabilityNodeMutable>());
     expect(decoratedType.node, isNot(same(typedefDecoratedType.node)));
@@ -1633,6 +1633,6 @@
 ''');
     var decoratedType = decoratedTypeAnnotation('void');
     expect(decoratedFunctionType('f').returnType, same(decoratedType));
-    assertEdge(always, decoratedType.node, hard: false);
+    assertNoEdge(always, decoratedType.node);
   }
 }
diff --git a/pkg/nnbd_migration/test/nullability_migration_impl_test.dart b/pkg/nnbd_migration/test/nullability_migration_impl_test.dart
index 1ba7901..078cad0 100644
--- a/pkg/nnbd_migration/test/nullability_migration_impl_test.dart
+++ b/pkg/nnbd_migration/test/nullability_migration_impl_test.dart
@@ -32,7 +32,8 @@
     final text = 'void f() {}\nint g() => null;';
     final offset = text.indexOf('int') + 3;
     final potentialModification = _PotentialModificationMock(
-        _NullabilityFixDescriptionMock('Add ?'),
+        _NullabilityFixDescriptionMock(
+            'Add ?', NullabilityFixKind.makeTypeNullable),
         false,
         [SourceEdit(offset, 0, '?')]);
     final listener = NullabilityMigrationListenerMock();
@@ -47,11 +48,12 @@
         as SingleNullabilityFix;
     expect(fix.description.appliedMessage, 'Add ?');
     expect(fix.source, source);
-    expect(fix.location.offset, offset);
-    expect(fix.location.length, 0);
-    expect(fix.location.file, '/test.dart');
-    expect(fix.location.startLine, 2);
-    expect(fix.location.startColumn, 4);
+    Location location = fix.locations.single;
+    expect(location.offset, offset);
+    expect(location.length, 0);
+    expect(location.file, '/test.dart');
+    expect(location.startLine, 2);
+    expect(location.startColumn, 4);
     verifyNever(listener.reportException(any, any, any, any));
     final edit =
         verify(listener.addEdit(fix, captureAny)).captured.single as SourceEdit;
@@ -61,8 +63,9 @@
   }
 
   void test_noModifications_notReported() {
-    final potentialModification =
-        _PotentialModificationMock.empty(_NullabilityFixDescriptionMock('foo'));
+    final potentialModification = _PotentialModificationMock.empty(
+        _NullabilityFixDescriptionMock(
+            'foo', NullabilityFixKind.noModification));
     final listener = NullabilityMigrationListenerMock();
     final source = SourceMock('');
     when(variables.getPotentialModifications()).thenReturn({
@@ -105,8 +108,10 @@
 class _NullabilityFixDescriptionMock implements NullabilityFixDescription {
   @override
   final String appliedMessage;
+  @override
+  final NullabilityFixKind kind;
 
-  _NullabilityFixDescriptionMock(this.appliedMessage);
+  _NullabilityFixDescriptionMock(this.appliedMessage, this.kind);
 }
 
 class _PotentialModificationMock extends PotentialModification {
diff --git a/pkg/nnbd_migration/test/nullability_node_test.dart b/pkg/nnbd_migration/test/nullability_node_test.dart
index e256963e..9f45acc 100644
--- a/pkg/nnbd_migration/test/nullability_node_test.dart
+++ b/pkg/nnbd_migration/test/nullability_node_test.dart
@@ -106,6 +106,15 @@
     assertUnsatisfied([]);
   }
 
+  test_lubNode_relatesInBothDirections() {
+    final nodeA = newNode(1);
+    final nodeB = newNode(2);
+    final lubNode = lub(nodeA, nodeB);
+
+    expect(nodeA.outerCompoundNodes, [lubNode]);
+    expect(nodeB.outerCompoundNodes, [lubNode]);
+  }
+
   test_never_source() {
     // never -> 1
     var n1 = newNode(1);
@@ -600,6 +609,15 @@
     expect(subst(n1, null), same(n1));
   }
 
+  test_substitutionNode_relatesInBothDirections() {
+    final nodeA = newNode(1);
+    final nodeB = newNode(2);
+    final substNode = subst(nodeA, nodeB);
+
+    expect(nodeA.outerCompoundNodes, [substNode]);
+    expect(nodeB.outerCompoundNodes, [substNode]);
+  }
+
   test_unconstrainted_node_non_nullable() {
     var n1 = newNode(1);
     propagate();
diff --git a/pkg/pkg.status b/pkg/pkg.status
index 0769ac3..29fa5d7 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -220,6 +220,9 @@
 [ $arch != x64 || $compiler != none || $mode != release || $runtime != vm ]
 front_end/test/whole_program_test: SkipByDesign
 
+[ $mode == debug || $runtime != vm || $system == android ]
+vm/test/modular_kernel_plus_aot_test: SkipByDesign # This test should only run if binary is run from build dir
+
 [ $mode != release || $runtime != vm ]
 front_end/test/fasta/*: Skip
 front_end/tool/_fasta/*: Skip
diff --git a/pkg/telemetry/lib/crash_reporting.dart b/pkg/telemetry/lib/crash_reporting.dart
index 415950c..285e5ac 100644
--- a/pkg/telemetry/lib/crash_reporting.dart
+++ b/pkg/telemetry/lib/crash_reporting.dart
@@ -16,8 +16,9 @@
 /// Crash backend host.
 const String _crashServerHost = 'clients2.google.com';
 
+// This should be one of 'report' or 'staging_report'.
 /// Path to the crash servlet.
-const String _crashEndpointPath = '/cr/report'; // or, 'staging_report'
+const String _crashEndpointPath = '/cr/staging_report';
 
 /// The field corresponding to the multipart/form-data file attachment where
 /// crash backend expects to find the Dart stack trace.
diff --git a/pkg/test_runner/lib/src/command.dart b/pkg/test_runner/lib/src/command.dart
index bcf4024..8127e35 100644
--- a/pkg/test_runner/lib/src/command.dart
+++ b/pkg/test_runner/lib/src/command.dart
@@ -388,28 +388,25 @@
   Runtime get browser => configuration.runtime;
   final String url;
   final TestConfiguration configuration;
-  final bool retry;
 
-  BrowserTestCommand(this.url, this.configuration, {this.retry, int index = 0})
+  BrowserTestCommand(this.url, this.configuration, {int index = 0})
       : super._(configuration.runtime.name, index: index);
 
   BrowserTestCommand indexedCopy(int index) =>
-      BrowserTestCommand(url, configuration, retry: retry, index: index);
+      BrowserTestCommand(url, configuration, index: index);
 
   void _buildHashCode(HashCodeBuilder builder) {
     super._buildHashCode(builder);
     builder.addJson(browser.name);
     builder.addJson(url);
     builder.add(configuration);
-    builder.add(retry);
   }
 
   bool _equal(BrowserTestCommand other) =>
       super._equal(other) &&
       browser == other.browser &&
       url == other.url &&
-      identical(configuration, other.configuration) &&
-      retry == other.retry;
+      identical(configuration, other.configuration);
 
   String get reproductionCommand {
     var parts = [
diff --git a/pkg/test_runner/lib/src/command_output.dart b/pkg/test_runner/lib/src/command_output.dart
index 9898e75..5f98e9e 100644
--- a/pkg/test_runner/lib/src/command_output.dart
+++ b/pkg/test_runner/lib/src/command_output.dart
@@ -47,7 +47,7 @@
   Expectation result(TestCase testCase) {
     if (hasCrashed) return Expectation.crash;
     if (hasTimedOut) return Expectation.timeout;
-    if (hasFailed(testCase)) return Expectation.fail;
+    if (_didFail(testCase)) return Expectation.fail;
     if (hasNonUtf8) return Expectation.nonUtf8Error;
 
     return Expectation.pass;
@@ -111,23 +111,8 @@
     return !hasTimedOut && exitCode == 0;
   }
 
-  // Reverse result of a negative test.
-  bool hasFailed(TestCase testCase) {
-    return testCase.isNegative ? !_didFail(testCase) : _didFail(testCase);
-  }
-
   bool get hasNonUtf8 => exitCode == nonUtfFakeExitCode;
 
-  Expectation _negateOutcomeIfNegativeTest(
-      Expectation outcome, bool isNegative) {
-    if (!isNegative) return outcome;
-    if (outcome == Expectation.ignore) return outcome;
-    if (outcome.canBeOutcomeOf(Expectation.fail)) {
-      return Expectation.pass;
-    }
-    return Expectation.fail;
-  }
-
   /// Called when producing output for a test failure to describe this output.
   void describe(TestCase testCase, Progress progress, OutputWriter output) {
     output.subsection("exit code");
@@ -282,7 +267,7 @@
     with _UnittestSuiteMessagesMixin {
   final BrowserTestJsonResult _jsonResult;
   final BrowserTestOutput _result;
-  final Expectation _rawOutcome;
+  final Expectation _outcome;
 
   factory BrowserCommandOutput(Command command, BrowserTestOutput result) {
     Expectation outcome;
@@ -317,7 +302,7 @@
   }
 
   BrowserCommandOutput._internal(Command command, BrowserTestOutput result,
-      this._rawOutcome, this._jsonResult, List<int> stdout, List<int> stderr)
+      this._outcome, this._jsonResult, List<int> stdout, List<int> stderr)
       : _result = result,
         super(command, 0, result.didTimeout, stdout, stderr, result.duration,
             false, 0);
@@ -332,11 +317,11 @@
 
     // Multitests are handled specially.
     if (testCase.hasRuntimeError) {
-      if (_rawOutcome == Expectation.runtimeError) return Expectation.pass;
+      if (_outcome == Expectation.runtimeError) return Expectation.pass;
       return Expectation.missingRuntimeError;
     }
 
-    return _negateOutcomeIfNegativeTest(_rawOutcome, testCase.isNegative);
+    return _outcome;
   }
 
   /// Cloned code from member result(), with changes.
@@ -348,7 +333,7 @@
     }
 
     if (hasNonUtf8) return Expectation.nonUtf8Error;
-    return _rawOutcome;
+    return _outcome;
   }
 
   void describe(TestCase testCase, Progress progress, OutputWriter output) {
@@ -509,13 +494,6 @@
       return _validateExpectedErrors(testCase);
     }
 
-    // Handle negative.
-    if (testCase.isNegative) {
-      return errors.isNotEmpty
-          ? Expectation.pass
-          : Expectation.missingCompileTimeError;
-    }
-
     // Handle errors / missing errors.
     if (testCase.hasCompileError) {
       if (errors.isNotEmpty) {
@@ -727,8 +705,7 @@
       outcome = Expectation.fail;
     }
 
-    outcome = _negateOutcomeIfIncompleteAsyncTest(outcome, decodeUtf8(stdout));
-    return _negateOutcomeIfNegativeTest(outcome, testCase.isNegative);
+    return _negateOutcomeIfIncompleteAsyncTest(outcome, decodeUtf8(stdout));
   }
 
   /// Cloned code from member result(), with changes.
@@ -835,9 +812,7 @@
       return Expectation.compileTimeError;
     }
 
-    var outcome =
-        exitCode == 0 ? Expectation.pass : Expectation.compileTimeError;
-    return _negateOutcomeIfNegativeTest(outcome, testCase.isNegative);
+    return exitCode == 0 ? Expectation.pass : Expectation.compileTimeError;
   }
 }
 
@@ -866,9 +841,7 @@
           : Expectation.pass;
     }
 
-    var outcome =
-        exitCode == 0 ? Expectation.pass : Expectation.compileTimeError;
-    return _negateOutcomeIfNegativeTest(outcome, testCase.isNegative);
+    return exitCode == 0 ? Expectation.pass : Expectation.compileTimeError;
   }
 
   /// Cloned code from member result(), with changes.
@@ -930,16 +903,15 @@
     }
 
     // The actual outcome depends on the exitCode.
-    var outcome = Expectation.pass;
     if (exitCode == VMCommandOutput._compileErrorExitCode ||
         exitCode == kBatchModeCompileTimeErrorExit) {
-      outcome = Expectation.compileTimeError;
+      return Expectation.compileTimeError;
     } else if (exitCode != 0) {
       // This is a general fail, in case we get an unknown nonzero exitcode.
-      outcome = Expectation.fail;
+      return Expectation.fail;
     }
 
-    return _negateOutcomeIfNegativeTest(outcome, testCase.isNegative);
+    return Expectation.pass;
   }
 
   /// Cloned code from member result(), with changes.
@@ -1003,8 +975,7 @@
     }
 
     var outcome = exitCode == 0 ? Expectation.pass : Expectation.runtimeError;
-    outcome = _negateOutcomeIfIncompleteAsyncTest(outcome, decodeUtf8(stdout));
-    return _negateOutcomeIfNegativeTest(outcome, testCase.isNegative);
+    return _negateOutcomeIfIncompleteAsyncTest(outcome, decodeUtf8(stdout));
   }
 
   /// Cloned code from member result(), with changes.
diff --git a/pkg/test_runner/lib/src/compiler_configuration.dart b/pkg/test_runner/lib/src/compiler_configuration.dart
index 01389c4..b575952 100644
--- a/pkg/test_runner/lib/src/compiler_configuration.dart
+++ b/pkg/test_runner/lib/src/compiler_configuration.dart
@@ -51,8 +51,6 @@
 
   bool get _isDebug => _configuration.mode.isDebug;
 
-  bool get _isProduct => _configuration.mode == Mode.product;
-
   bool get _isHostChecked => _configuration.isHostChecked;
 
   bool get _useSdk => _configuration.useSdk;
@@ -1051,8 +1049,6 @@
 
   bool get _useSdk;
 
-  bool get _isProduct;
-
   bool get _isAot;
 
   bool get _enableAsserts;
diff --git a/pkg/test_runner/lib/src/options.dart b/pkg/test_runner/lib/src/options.dart
index ce68eba..1dfea78 100644
--- a/pkg/test_runner/lib/src/options.dart
+++ b/pkg/test_runner/lib/src/options.dart
@@ -330,7 +330,7 @@
         '''
 Skip the compilation step, using the compilation artifacts left in
 the output folder from a previous run. This flag will often cause
-false positves and negatives, but can be useful for quick and
+false positives and negatives, but can be useful for quick and
 dirty offline testing when not making changes that affect the
 compiler.''',
         hide: true),
diff --git a/pkg/test_runner/lib/src/runtime_configuration.dart b/pkg/test_runner/lib/src/runtime_configuration.dart
index 5a2b45b..f21d1d5 100644
--- a/pkg/test_runner/lib/src/runtime_configuration.dart
+++ b/pkg/test_runner/lib/src/runtime_configuration.dart
@@ -94,8 +94,6 @@
 
   List<String> dart2jsPreambles(Uri preambleDir) => [];
 
-  bool get shouldSkipNegativeTests => false;
-
   /// Returns the path to the Dart VM executable.
   ///
   /// Controlled by user with the option "--dart".
@@ -389,9 +387,6 @@
             checked: _configuration.isChecked))
         .toList();
   }
-
-  @override
-  bool get shouldSkipNegativeTests => true;
 }
 
 /// Temporary runtime configuration for browser runtimes that haven't been
diff --git a/pkg/test_runner/lib/src/test_case.dart b/pkg/test_runner/lib/src/test_case.dart
index b317545..7ff1410 100644
--- a/pkg/test_runner/lib/src/test_case.dart
+++ b/pkg/test_runner/lib/src/test_case.dart
@@ -75,10 +75,6 @@
   bool get hasSyntaxError => testFile?.hasSyntaxError ?? false;
   bool get hasCompileError => testFile?.hasCompileError ?? false;
   bool get hasCrash => testFile?.hasCrash ?? false;
-  bool get isNegative =>
-      hasCompileError ||
-      hasRuntimeError && configuration.runtime != Runtime.none ||
-      displayName.contains("negative_test");
 
   bool get unexpectedOutput {
     var outcome = result;
@@ -109,9 +105,6 @@
       }
       return Expectation.pass;
     }
-    if (displayName.contains("negative_test")) {
-      return Expectation.fail;
-    }
     if (configuration.compiler == Compiler.dart2analyzer && hasStaticWarning) {
       return Expectation.staticWarning;
     }
diff --git a/pkg/test_runner/lib/src/test_configurations.dart b/pkg/test_runner/lib/src/test_configurations.dart
index be93c90..5b957cd 100644
--- a/pkg/test_runner/lib/src/test_configurations.dart
+++ b/pkg/test_runner/lib/src/test_configurations.dart
@@ -34,10 +34,14 @@
   Path('tests/compiler/dart2js_extra'),
   Path('tests/compiler/dart2js_native'),
   Path('tests/compiler/dartdevc_native'),
+  Path('tests/corelib'),
   Path('tests/corelib_2'),
   Path('tests/kernel'),
+  Path('tests/language'),
   Path('tests/language_2'),
+  Path('tests/lib'),
   Path('tests/lib_2'),
+  Path('tests/standalone'),
   Path('tests/standalone_2'),
   Path('tests/ffi'),
   Path('utils/tests/peg'),
@@ -125,7 +129,7 @@
       }
 
       for (var key in configuration.selectors.keys) {
-        if (key == 'co19_2') {
+        if (key == 'co19_2' || key == 'co19') {
           testSuites.add(Co19TestSuite(configuration, key));
         } else if ((configuration.compiler == Compiler.none ||
                 configuration.compiler == Compiler.dartk ||
diff --git a/pkg/test_runner/lib/src/test_progress.dart b/pkg/test_runner/lib/src/test_progress.dart
index 6461397..c2b3d5e 100644
--- a/pkg/test_runner/lib/src/test_progress.dart
+++ b/pkg/test_runner/lib/src/test_progress.dart
@@ -255,7 +255,6 @@
 
 class StatusFileUpdatePrinter extends EventListener {
   final Map<String, List<String>> statusToConfigs = {};
-  final List<String> _failureSummary = [];
 
   void done(TestCase test) {
     if (test.unexpectedOutput) {
@@ -391,7 +390,6 @@
 
 class PassingStdoutPrinter extends EventListener {
   final Formatter _formatter;
-  final _failureSummary = <String>[];
 
   PassingStdoutPrinter([this._formatter = Formatter.normal]);
 
diff --git a/pkg/test_runner/lib/src/test_suite.dart b/pkg/test_runner/lib/src/test_suite.dart
index 31b7f32..5f92c54 100644
--- a/pkg/test_runner/lib/src/test_suite.dart
+++ b/pkg/test_runner/lib/src/test_suite.dart
@@ -147,7 +147,8 @@
     // So, for now, until we have figured out how to manage those tests, we
     // implicitly skip any test that does not require NNBD if run in a
     // configuration that enables the NNBD experiment.
-    if (configuration.experiments.contains("non-nullable") &&
+    if (testFile.path.toString().contains("language_2") &&
+        configuration.experiments.contains("non-nullable") &&
         !(testFile.requirements.contains(Feature.nnbd) ||
             testFile.requirements.contains(Feature.nnbdWeak) ||
             testFile.requirements.contains(Feature.nnbdStrong))) {
@@ -165,11 +166,6 @@
       return false;
     }
 
-    if (isNegative(testFile) &&
-        configuration.runtimeConfiguration.shouldSkipNegativeTests) {
-      return false;
-    }
-
     // Handle sharding based on the original test path. All multitests of a
     // given original test belong to the same shard.
     if (configuration.shardCount > 1 &&
@@ -211,10 +207,6 @@
     return false;
   }
 
-  bool isNegative(TestFile testFile) =>
-      testFile.hasCompileError ||
-      testFile.hasRuntimeError && configuration.runtime != Runtime.none;
-
   String createGeneratedTestDirectoryHelper(
       String name, String dirname, Path testPath) {
     Path relative = testPath.relativeTo(Repository.dir);
@@ -879,8 +871,7 @@
     var htmlPathSubtest = _createUrlPathFromFile(Path(htmlPath));
     var fullHtmlPath = _uriForBrowserTest(htmlPathSubtest, subtestName);
 
-    commands.add(BrowserTestCommand(fullHtmlPath, configuration,
-        retry: !isNegative(testFile)));
+    commands.add(BrowserTestCommand(fullHtmlPath, configuration));
 
     var fullName = testName;
     if (subtestName != null) fullName += "/$subtestName";
@@ -970,8 +961,7 @@
       super._enqueueBrowserTest(testFile, expectations, onTest);
     } else {
       var fullPath = _createUrlPathFromFile(customHtmlPath);
-      var command = BrowserTestCommand(fullPath, configuration,
-          retry: !isNegative(testFile));
+      var command = BrowserTestCommand(fullPath, configuration);
       _addTestCase(testFile, testFile.name, [command],
           expectations[testFile.name], onTest);
     }
diff --git a/pkg/test_runner/tool/update_static_error_tests.dart b/pkg/test_runner/tool/update_static_error_tests.dart
index d763c9f..4547df3 100644
--- a/pkg/test_runner/tool/update_static_error_tests.dart
+++ b/pkg/test_runner/tool/update_static_error_tests.dart
@@ -142,7 +142,7 @@
     bool insertCfe}) async {
   stdout.write("${file.path}...");
   var source = file.readAsStringSync();
-  var testFile = TestFile.parse(Path("."), file.path, source);
+  var testFile = TestFile.parse(Path("."), file.absolute.path, source);
 
   var options = testFile.sharedOptions.toList();
   if (testFile.experiments.isNotEmpty) {
@@ -152,14 +152,14 @@
   var errors = <StaticError>[];
   if (insertAnalyzer) {
     stdout.write("\r${file.path} (Running analyzer...)");
-    errors.addAll(await _runAnalyzer(file.path, options));
+    errors.addAll(await _runAnalyzer(file.absolute.path, options));
   }
 
   if (insertCfe) {
     // Clear the previous line.
     stdout.write("\r${file.path}                      ");
     stdout.write("\r${file.path} (Running CFE...)");
-    errors.addAll(await _runCfe(file.path, options));
+    errors.addAll(await _runCfe(file.absolute.path, options));
   }
 
   errors = StaticError.simplify(errors);
@@ -182,11 +182,15 @@
   // TODO(rnystrom): Running the analyzer command line each time is very slow.
   // Either import the analyzer as a library, or at least invoke it in a batch
   // mode.
-  var result = await Process.run("sdk/bin/dartanalyzer$shellScriptExtension", [
-    ...options,
-    "--format=machine",
-    path,
-  ]);
+  var result = await Process.run(
+      Platform.isWindows
+          ? "sdk\\bin\\dartanalyzer.bat"
+          : "sdk/bin/dartanalyzer",
+      [
+        ...options,
+        "--format=machine",
+        path,
+      ]);
   var errors = <StaticError>[];
   AnalysisCommandOutput.parseErrors(result.stderr as String, errors);
   return errors;
@@ -197,19 +201,17 @@
   // TODO(rnystrom): Running the CFE command line each time is slow and wastes
   // time generating code, which we don't care about. Import it as a library or
   // at least run it in batch mode.
-  var result = await Process.run("sdk/bin/dart", [
+  var result = await Process.run(
+      Platform.isWindows ? "sdk\\bin\\dart.bat" : "sdk/bin/dart", [
     "pkg/front_end/tool/_fasta/compile.dart",
     ...options,
     "--verify",
+    "-o",
+    "dev:null", // Output is only created for file URIs.
     path,
   ]);
 
   var errors = <StaticError>[];
   FastaCommandOutput.parseErrors(result.stdout as String, errors);
-
-  // Running the above command generates a dill file next to the test, which we
-  // don't want, so delete it.
-  await File("$path.dill").delete();
-
   return errors;
 }
diff --git a/pkg/vm/bin/kernel_service.dart b/pkg/vm/bin/kernel_service.dart
index 00de5c9..99141fa 100644
--- a/pkg/vm/bin/kernel_service.dart
+++ b/pkg/vm/bin/kernel_service.dart
@@ -35,13 +35,14 @@
 import 'package:kernel/binary/ast_to_binary.dart';
 import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
 import 'package:kernel/core_types.dart' show CoreTypes;
-import 'package:kernel/kernel.dart' show Component, Procedure;
+import 'package:kernel/kernel.dart' show Component, Library, Procedure;
 import 'package:kernel/target/targets.dart' show TargetFlags;
 import 'package:vm/bytecode/gen_bytecode.dart'
     show createFreshComponentWithBytecode, generateBytecode;
 import 'package:vm/bytecode/options.dart' show BytecodeOptions;
 import 'package:vm/incremental_compiler.dart';
-import 'package:vm/kernel_front_end.dart' show runWithFrontEndCompilerContext;
+import 'package:vm/kernel_front_end.dart'
+    show createLoadedLibrariesSet, runWithFrontEndCompilerContext;
 import 'package:vm/http_filesystem.dart';
 import 'package:vm/target/vm.dart' show VmTarget;
 import 'package:front_end/src/api_prototype/compiler_options.dart'
@@ -157,7 +158,7 @@
       };
   }
 
-  Future<Component> compile(Uri script) {
+  Future<CompilerResult> compile(Uri script) {
     return runWithPrintToStderr(() async {
       CompilerResult compilerResult = await compileInternal(script);
       Component component = compilerResult.component;
@@ -169,11 +170,19 @@
       }
 
       if (options.bytecode && errors.isEmpty) {
+        final List<Library> libraries = new List<Library>();
+        final Set<Library> loadedLibraries = compilerResult.loadedLibraries;
+        for (Library library in component.libraries) {
+          if (loadedLibraries.contains(library)) continue;
+          libraries.add(library);
+        }
+
         await runWithFrontEndCompilerContext(script, options, component, () {
           // TODO(alexmarkov): disable local variables info,
           //  debugger stops and source files in VM PRODUCT mode.
           // TODO(rmacnak): disable annotations if mirrors are not enabled.
           generateBytecode(component,
+              libraries: libraries,
               coreTypes: compilerResult.coreTypes,
               hierarchy: compilerResult.classHierarchy,
               options: new BytecodeOptions(
@@ -195,11 +204,17 @@
                 keepUnreachableCode: supportCodeCoverage,
                 avoidClosureCallInstructions: supportCodeCoverage,
               ));
-          component = createFreshComponentWithBytecode(component);
+          Component freshComponent =
+              createFreshComponentWithBytecode(component);
+          compilerResult = new CompilerResult(
+              freshComponent,
+              compilerResult.loadedLibraries,
+              compilerResult.classHierarchy,
+              compilerResult.coreTypes);
         });
       }
 
-      return component;
+      return compilerResult;
     });
   }
 
@@ -208,11 +223,17 @@
 
 class CompilerResult {
   final Component component;
+
+  /// Set of libraries loaded from .dill, with or without the SDK depending on
+  /// the compilation settings.
+  final Set<Library> loadedLibraries;
   final ClassHierarchy classHierarchy;
   final CoreTypes coreTypes;
 
-  CompilerResult(this.component, this.classHierarchy, this.coreTypes)
+  CompilerResult(
+      this.component, this.loadedLibraries, this.classHierarchy, this.coreTypes)
       : assert(component != null),
+        assert(loadedLibraries != null),
         assert(classHierarchy != null),
         assert(coreTypes != null);
 }
@@ -279,8 +300,8 @@
     }
     errors.clear();
     final component = await generator.compile(entryPoint: script);
-    return new CompilerResult(
-        component, generator.getClassHierarchy(), generator.getCoreTypes());
+    return new CompilerResult(component, const {},
+        generator.getClassHierarchy(), generator.getCoreTypes());
   }
 
   void accept() => generator.accept();
@@ -336,7 +357,12 @@
     fe.CompilerResult compilerResult = requireMain
         ? await kernelForProgram(script, options)
         : await kernelForModule([script], options);
-    return new CompilerResult(compilerResult.component,
+
+    Set<Library> loadedLibraries = createLoadedLibrariesSet(
+        compilerResult?.loadedComponents, compilerResult?.sdkComponent,
+        includePlatform: !options.omitPlatform);
+
+    return new CompilerResult(compilerResult.component, loadedLibraries,
         compilerResult.classHierarchy, compilerResult.coreTypes);
   }
 }
@@ -678,14 +704,15 @@
       print("DFE: scriptUri: ${script}");
     }
 
-    Component component = await compiler.compile(script);
+    CompilerResult compilerResult = await compiler.compile(script);
+    Set<Library> loadedLibraries = compilerResult.loadedLibraries;
 
     if (compiler.errors.isNotEmpty) {
-      if (component != null) {
+      if (compilerResult.component != null) {
         result = new CompilationResult.errors(
             compiler.errors,
-            // ignore: DEPRECATED_MEMBER_USE
-            serializeComponent(component, filter: (lib) => !lib.isExternal));
+            serializeComponent(compilerResult.component,
+                filter: (lib) => !loadedLibraries.contains(lib)));
       } else {
         result = new CompilationResult.errors(compiler.errors, null);
       }
@@ -694,9 +721,9 @@
       // these sources built-in. Everything loaded as a summary in
       // [kernelForProgram] is marked `external`, so we can use that bit to
       // decide what to exclude.
-      result = new CompilationResult.ok(
-          // ignore: DEPRECATED_MEMBER_USE
-          serializeComponent(component, filter: (lib) => !lib.isExternal));
+      result = new CompilationResult.ok(serializeComponent(
+          compilerResult.component,
+          filter: (lib) => !loadedLibraries.contains(lib)));
     }
   } catch (error, stack) {
     result = new CompilationResult.crash(error, stack);
diff --git a/pkg/vm/lib/bytecode/assembler.dart b/pkg/vm/lib/bytecode/assembler.dart
index 10dd830..be95068 100644
--- a/pkg/vm/lib/bytecode/assembler.dart
+++ b/pkg/vm/lib/bytecode/assembler.dart
@@ -107,9 +107,9 @@
     }
   }
 
-  void emitYieldPointSourcePosition() {
+  void emitYieldPointSourcePosition(int yieldSourcePosition) {
     if (!isUnreachable) {
-      sourcePositions.addYieldPoint(offset, currentSourcePosition);
+      sourcePositions.addYieldPoint(offset, yieldSourcePosition);
     }
   }
 
@@ -746,4 +746,14 @@
     emitSourcePosition();
     _emitInstructionD(Opcode.kInitLateField, rd);
   }
+
+  @pragma('vm:prefer-inline')
+  void emitPushUninitializedSentinel() {
+    _emitInstruction0(Opcode.kPushUninitializedSentinel);
+  }
+
+  @pragma('vm:prefer-inline')
+  void emitJumpIfInitialized(Label label) {
+    _emitJumpInstruction(Opcode.kJumpIfInitialized, label);
+  }
 }
diff --git a/pkg/vm/lib/bytecode/dbc.dart b/pkg/vm/lib/bytecode/dbc.dart
index a860cd6..bc1e22b 100644
--- a/pkg/vm/lib/bytecode/dbc.dart
+++ b/pkg/vm/lib/bytecode/dbc.dart
@@ -10,7 +10,7 @@
 /// Before bumping current bytecode version format, make sure that
 /// all users have switched to a VM which is able to consume new
 /// version of bytecode.
-const int currentBytecodeFormatVersion = 26;
+const int currentBytecodeFormatVersion = 27;
 
 enum Opcode {
   kUnusedOpcode000,
@@ -95,9 +95,11 @@
   kUnusedOpcode079,
   kUnusedOpcode080,
   kUnusedOpcode081,
-  kUnusedOpcode082,
-  kUnusedOpcode083,
-  kUnusedOpcode084,
+
+  // Late variables.
+  kJumpIfInitialized,
+  kJumpIfInitialized_Wide,
+  kPushUninitializedSentinel,
 
   kTrap,
 
@@ -181,7 +183,7 @@
   kStoreIndexedTOS,
   kUnused20,
 
-  // Late fields and variables.
+  // Late fields.
   kInitLateField,
   kInitLateField_Wide,
 
@@ -416,6 +418,10 @@
       Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
   Opcode.kInitLateField: const Format(
       Encoding.kD, const [Operand.lit, Operand.none, Operand.none]),
+  Opcode.kPushUninitializedSentinel: const Format(
+      Encoding.k0, const [Operand.none, Operand.none, Operand.none]),
+  Opcode.kJumpIfInitialized: const Format(
+      Encoding.kT, const [Operand.tgt, Operand.none, Operand.none]),
   Opcode.kLoadStatic: const Format(
       Encoding.kD, const [Operand.lit, Operand.none, Operand.none]),
   Opcode.kStoreStaticTOS: const Format(
@@ -642,6 +648,7 @@
     case Opcode.kPushTrue:
     case Opcode.kPushFalse:
     case Opcode.kPushInt:
+    case Opcode.kPushUninitializedSentinel:
       return true;
     default:
       return false;
diff --git a/pkg/vm/lib/bytecode/declarations.dart b/pkg/vm/lib/bytecode/declarations.dart
index 704bef6..273e443 100644
--- a/pkg/vm/lib/bytecode/declarations.dart
+++ b/pkg/vm/lib/bytecode/declarations.dart
@@ -5,6 +5,7 @@
 library vm.bytecode.declarations;
 
 import 'package:kernel/ast.dart' show TreeNode, listHashCode, listEquals;
+import 'package:kernel/core_types.dart' show CoreTypes;
 import 'bytecode_serialization.dart'
     show
         BufferedWriter,
@@ -1253,9 +1254,9 @@
   Set<String> protectedNames;
   ObjectHandle mainLibrary;
 
-  Component(this.version)
+  Component(this.version, CoreTypes coreTypes)
       : stringTable = new StringTable(),
-        objectTable = new ObjectTable();
+        objectTable = new ObjectTable(coreTypes);
 
   void write(BufferedWriter writer) {
     objectTable.allocateIndexTable();
diff --git a/pkg/vm/lib/bytecode/gen_bytecode.dart b/pkg/vm/lib/bytecode/gen_bytecode.dart
index 6e97d4a..dce21ec 100644
--- a/pkg/vm/lib/bytecode/gen_bytecode.dart
+++ b/pkg/vm/lib/bytecode/gen_bytecode.dart
@@ -24,7 +24,7 @@
 import 'package:kernel/type_algebra.dart'
     show Substitution, containsTypeVariable;
 import 'package:kernel/type_environment.dart'
-    show SubtypeCheckMode, TypeEnvironment;
+    show StatefulStaticTypeContext, SubtypeCheckMode, TypeEnvironment;
 import 'assembler.dart';
 import 'bytecode_serialization.dart' show StringTable;
 import 'constant_pool.dart';
@@ -122,6 +122,7 @@
   final CoreTypes coreTypes;
   final ClassHierarchy hierarchy;
   final TypeEnvironment typeEnvironment;
+  final StatefulStaticTypeContext staticTypeContext;
   final BytecodeOptions options;
   final BytecodeMetadataRepository metadata = new BytecodeMetadataRepository();
   final RecognizedMethods recognizedMethods;
@@ -167,20 +168,33 @@
   List<int> savedMaxSourcePositions;
   int maxSourcePosition;
 
-  BytecodeGenerator(ast.Component component, this.coreTypes, this.hierarchy,
-      this.typeEnvironment, this.options)
-      : recognizedMethods = new RecognizedMethods(typeEnvironment),
+  BytecodeGenerator(
+      ast.Component component,
+      CoreTypes coreTypes,
+      ClassHierarchy hierarchy,
+      TypeEnvironment typeEnvironment,
+      BytecodeOptions options)
+      : this._internal(component, coreTypes, hierarchy, typeEnvironment,
+            options, new StatefulStaticTypeContext.flat(typeEnvironment));
+
+  BytecodeGenerator._internal(
+      ast.Component component,
+      this.coreTypes,
+      this.hierarchy,
+      this.typeEnvironment,
+      this.options,
+      this.staticTypeContext)
+      : recognizedMethods = new RecognizedMethods(staticTypeContext),
         formatVersion = currentBytecodeFormatVersion,
         astUriToSource = component.uriToSource {
     nullabilityDetector = new NullabilityDetector(recognizedMethods);
     component.addMetadataRepository(metadata);
 
-    bytecodeComponent = new Component(formatVersion);
+    bytecodeComponent = new Component(formatVersion, coreTypes);
     metadata.mapping[component] = new BytecodeMetadata(bytecodeComponent);
 
     stringTable = bytecodeComponent.stringTable;
     objectTable = bytecodeComponent.objectTable;
-    objectTable.coreTypes = coreTypes;
 
     if (component.mainMethod != null) {
       bytecodeComponent.mainLibrary =
@@ -207,10 +221,7 @@
 
   @override
   visitLibrary(Library node) {
-    // ignore: DEPRECATED_MEMBER_USE
-    if (node.isExternal) {
-      return;
-    }
+    staticTypeContext.enterLibrary(node);
 
     startMembers();
     visitList(node.procedures, this);
@@ -226,6 +237,7 @@
     bytecodeComponent.libraries
         .add(getLibraryDeclaration(node, classDeclarations));
     classDeclarations = null;
+    staticTypeContext.leaveLibrary(node);
   }
 
   @override
@@ -570,12 +582,10 @@
   FieldDeclaration getFieldDeclaration(Field field, Code initializer) {
     int flags = 0;
     Constant value;
-    if (_hasTrivialInitializer(field)) {
-      if (field.initializer != null) {
-        value = _getConstant(field.initializer);
-      }
-    } else {
+    if (_hasNonTrivialInitializer(field)) {
       flags |= FieldDeclaration.hasNontrivialInitializerFlag;
+    } else if (field.initializer != null) {
+      value = _getConstant(field.initializer);
     }
     if (initializer != null) {
       flags |= FieldDeclaration.hasInitializerCodeFlag;
@@ -956,7 +966,7 @@
       (field.isStatic ||
           field.isLate ||
           options.emitInstanceFieldInitializers) &&
-      !_hasTrivialInitializer(field);
+      _hasNonTrivialInitializer(field);
 
   bool _needsGetter(Field field) {
     // All instance fields need a getter.
@@ -964,7 +974,7 @@
 
     // Static fields also need a getter if they have a non-trivial initializer,
     // because it needs to be initialized lazily.
-    if (!_hasTrivialInitializer(field)) return true;
+    if (_hasNonTrivialInitializer(field)) return true;
 
     // Static late fields with no initializer also need a getter, to check if
     // it's been initialized.
@@ -972,11 +982,14 @@
   }
 
   bool _needsSetter(Field field) {
-    // Static fields never need a setter.
-    if (field.isStatic) return false;
+    // Late fields always need a setter, unless they're static and non-final.
+    if (field.isLate) {
+      if (field.isStatic && !field.isFinal) return false;
+      return true;
+    }
 
-    // Late instance fields always need a setter.
-    if (field.isLate) return true;
+    // Non-late static fields never need a setter.
+    if (field.isStatic) return false;
 
     // Otherwise, the field only needs a setter if it isn't final.
     return !field.isFinal;
@@ -1074,6 +1087,11 @@
   Procedure get futureValue =>
       _futureValue ??= libraryIndex.getMember('dart:async', 'Future', 'value');
 
+  Procedure _throwNewLateInitializationError;
+  Procedure get throwNewLateInitializationError =>
+      _throwNewLateInitializationError ??= libraryIndex.getMember(
+          'dart:core', '_LateInitializationError', '_throwNew');
+
   Procedure _throwNewAssertionError;
   Procedure get throwNewAssertionError => _throwNewAssertionError ??=
       libraryIndex.getMember('dart:core', '_AssertionError', '_throwNew');
@@ -1203,7 +1221,7 @@
   void _genLateFieldInitializer(Field field) {
     assert(!field.isStatic);
 
-    if (field.initializer != null && _hasTrivialInitializer(field)) {
+    if (_isTrivialInitializer(field.initializer)) {
       _genFieldInitializer(field, field.initializer);
       return;
     }
@@ -1277,7 +1295,7 @@
     }
   }
 
-  void _genReturnTOS() {
+  void _genReturnTOS([int yieldSourcePosition = null]) {
     if (options.causalAsyncStacks &&
         parentFunction != null &&
         (parentFunction.dartAsyncMarker == AsyncMarker.Async ||
@@ -1290,6 +1308,9 @@
       asm.currentSourcePosition = savedSourcePosition;
     }
 
+    if (yieldSourcePosition != null && options.emitSourcePositions) {
+      asm.emitYieldPointSourcePosition(yieldSourcePosition);
+    }
     asm.emitReturnTOS();
   }
 
@@ -1653,9 +1674,7 @@
     parentFunction = null;
     isClosure = false;
     hasErrors = false;
-    if ((node is Procedure && !node.isStatic) || node is Constructor) {
-      typeEnvironment.thisType = enclosingClass.thisType;
-    }
+    staticTypeContext.enterMember(node);
     final isFactory = node is Procedure && node.isFactory;
     if (node.isInstanceMember || node is Constructor || isFactory) {
       if (enclosingClass.typeParameters.isNotEmpty) {
@@ -1726,8 +1745,8 @@
     savedMaxSourcePositions = <int>[];
     maxSourcePosition = node.fileOffset;
 
-    locals =
-        new LocalVariables(node, options, typeEnvironment, directCallMetadata);
+    locals = new LocalVariables(
+        node, options, staticTypeContext, directCallMetadata);
     locals.enterScope(node);
     assert(!locals.isSyncYieldingFrame);
 
@@ -1847,7 +1866,7 @@
       }
     }
 
-    typeEnvironment.thisType = null;
+    staticTypeContext.leaveMember(node);
     enclosingClass = null;
     enclosingMember = null;
     enclosingFunction = null;
@@ -3237,7 +3256,7 @@
 
   bool _isUncheckedCall(
           Node node, Member interfaceTarget, Expression receiver) =>
-      isUncheckedCall(interfaceTarget, receiver, typeEnvironment) ||
+      isUncheckedCall(interfaceTarget, receiver, staticTypeContext) ||
       (inferredTypeMetadata != null &&
           inferredTypeMetadata[node]?.skipCheck == true);
 
@@ -3258,7 +3277,7 @@
     }
 
     if (invocationKind != InvocationKind.getter && !isDynamic && !isUnchecked) {
-      final staticReceiverType = getStaticType(receiver, typeEnvironment);
+      final staticReceiverType = getStaticType(receiver, staticTypeContext);
       if (isInstantiatedInterfaceCall(interfaceTarget, staticReceiverType)) {
         final callCpIndex = cp.addInstantiatedInterfaceCall(
             invocationKind, interfaceTarget, argDesc, staticReceiverType);
@@ -3349,7 +3368,7 @@
     }
     // Front-end guarantees that all calls with known function type
     // do not need any argument type checks.
-    if (isUncheckedClosureCall(node, typeEnvironment, options)) {
+    if (isUncheckedClosureCall(node, staticTypeContext, options)) {
       final int receiverTemp = locals.tempIndexInFrame(node);
       _genArguments(node.receiver, args, storeReceiverToLocal: receiverTemp);
       // Duplicate receiver (closure) for UncheckedClosureCall.
@@ -3569,10 +3588,14 @@
     _genRethrow(tryCatch);
   }
 
-  bool _hasTrivialInitializer(Field field) {
-    final initializer = field.initializer;
-    if (initializer == null ||
-        initializer is StringLiteral ||
+  bool _hasNonTrivialInitializer(Field field) {
+    if (field.initializer == null) return false;
+    return !_isTrivialInitializer(field.initializer);
+  }
+
+  bool _isTrivialInitializer(Expression initializer) {
+    if (initializer == null) return false;
+    if (initializer is StringLiteral ||
         initializer is BoolLiteral ||
         initializer is IntLiteral ||
         initializer is DoubleLiteral ||
@@ -3670,7 +3693,7 @@
     }
 
     final target = node.target;
-    if (target is Field) {
+    if (target is Field && !_needsSetter(target)) {
       if (options.emitDebuggerStops &&
           _variableSetNeedsDebugCheck(node.value)) {
         asm.emitDebugCheck();
@@ -3751,6 +3774,34 @@
     final v = node.variable;
     if (v.isConst) {
       _genPushConstExpr(v.initializer);
+    } else if (v.isLate) {
+      _genLoadVar(v);
+
+      final Label done = new Label();
+      asm.emitJumpIfInitialized(done);
+
+      if (v.initializer != null) {
+        final init = v.initializer;
+        _genPushContextIfCaptured(v);
+        // Late local variable initializers are transformed to wrap the
+        // initializer in a closure (see late_var_init_transformer.dart). The
+        // closure call needs one temporary, so withTemp lets us use this
+        // VariableGet's temporary when visiting the initializer.
+        assert(init is MethodInvocation &&
+            init.name.name == "call" &&
+            init.arguments.positional.length == 0);
+        locals.withTemp(
+            init, locals.tempIndexInFrame(node), () => _generateNode(init));
+        _genStoreVar(v);
+      } else {
+        asm.emitPushConstant(cp.addName(v.name));
+        _genDirectCall(throwNewLateInitializationError,
+            objectTable.getArgDescHandle(1), 1);
+        asm.emitDrop1();
+      }
+
+      asm.bind(done);
+      _genLoadVar(v);
     } else {
       _genLoadVar(v);
     }
@@ -3760,8 +3811,11 @@
   visitVariableSet(VariableSet node) {
     final v = node.variable;
     final bool hasResult = !isExpressionWithoutResult(node);
+    final bool isLateFinal = v.isLate && v.isFinal;
 
-    _genPushContextIfCaptured(v);
+    if (!isLateFinal) {
+      _genPushContextIfCaptured(v);
+    }
 
     _generateNode(node.value);
 
@@ -3769,7 +3823,32 @@
       asm.emitDebugCheck();
     }
 
-    if (locals.isCaptured(v)) {
+    if (isLateFinal) {
+      final int temp = locals.tempIndexInFrame(node);
+      asm.emitPopLocal(temp);
+
+      final Label error = new Label();
+      final Label done = new Label();
+      _genLoadVar(v);
+      asm.emitJumpIfInitialized(error);
+
+      _genPushContextIfCaptured(v);
+      asm.emitPush(temp);
+      _genStoreVar(v);
+      asm.emitJump(done);
+
+      asm.bind(error);
+      asm.emitPushConstant(cp.addName(v.name));
+      _genDirectCall(
+          throwNewLateInitializationError, objectTable.getArgDescHandle(1), 1);
+      asm.emitDrop1();
+
+      asm.bind(done);
+
+      if (hasResult) {
+        asm.emitPush(temp);
+      }
+    } else if (locals.isCaptured(v)) {
       final int temp = locals.tempIndexInFrame(node);
       if (hasResult) {
         asm.emitStoreLocal(temp);
@@ -4415,19 +4494,37 @@
     finallyBlocks.remove(node);
   }
 
+  bool _skipVariableInitialization(VariableDeclaration v, bool isCaptured) {
+    // We can skip variable initialization if the variable is supposed to be
+    // initialized to null and it's captured. This is because all the slots in
+    // the capture context are implicitly initialized to null.
+
+    // Check if the variable is supposed to be initialized to null.
+    if (!(v.initializer == null || v.initializer is NullLiteral)) {
+      return false;
+    }
+
+    // Late variables need to be initialized to a sentinel, not null.
+    if (v.isLate) return false;
+
+    // Non-captured variables go in stack slots that aren't implicitly nulled.
+    return isCaptured;
+  }
+
   @override
   visitVariableDeclaration(VariableDeclaration node) {
     if (!node.isConst) {
       final bool isCaptured = locals.isCaptured(node);
       final initializer = node.initializer;
-      final bool emitStore =
-          !(isCaptured && (initializer == null || initializer is NullLiteral));
+      final bool emitStore = !_skipVariableInitialization(node, isCaptured);
       int maxInitializerPosition = node.fileOffset;
       if (emitStore) {
         if (isCaptured) {
           _genPushContextForVariable(node);
         }
-        if (initializer != null) {
+        if (node.isLate && !_isTrivialInitializer(initializer)) {
+          asm.emitPushUninitializedSentinel();
+        } else if (initializer != null) {
           _startRecordingMaxPosition(node.fileOffset);
           _generateNode(initializer);
           maxInitializerPosition = _endRecordingMaxPosition();
@@ -4490,10 +4587,6 @@
       return;
     }
 
-    if (options.emitSourcePositions) {
-      asm.emitYieldPointSourcePosition();
-    }
-
     // 0 is reserved for normal entry, yield points are counted from 1.
     final int yieldIndex = yieldPoints.length + 1;
     final Label continuationLabel = new Label(allowsBackwardJumps: true);
@@ -4514,7 +4607,7 @@
     // return <expression>
     // Note: finally blocks are *not* executed on the way out.
     _generateNode(node.expression);
-    _genReturnTOS();
+    _genReturnTOS(node.fileOffset);
 
     asm.bind(continuationLabel);
 
diff --git a/pkg/vm/lib/bytecode/generics.dart b/pkg/vm/lib/bytecode/generics.dart
index 4fe55e8..88b551c 100644
--- a/pkg/vm/lib/bytecode/generics.dart
+++ b/pkg/vm/lib/bytecode/generics.dart
@@ -9,7 +9,7 @@
 import 'package:kernel/ast.dart' hide MapEntry;
 import 'package:kernel/core_types.dart' show CoreTypes;
 import 'package:kernel/type_algebra.dart' show Substitution;
-import 'package:kernel/type_environment.dart' show TypeEnvironment;
+import 'package:kernel/type_environment.dart' show StaticTypeContext;
 
 import 'options.dart' show BytecodeOptions;
 
@@ -153,6 +153,9 @@
   bool visitBottomType(BottomType node) => false;
 
   @override
+  bool visitNeverType(NeverType node) => false;
+
+  @override
   bool visitTypeParameterType(TypeParameterType node) =>
       _declaredTypeParameters == null ||
       !_declaredTypeParameters.contains(node.parameter);
@@ -185,15 +188,8 @@
 }
 
 /// Returns static type of [expr].
-DartType getStaticType(Expression expr, TypeEnvironment typeEnvironment) {
-  // TODO(dartbug.com/34496): Remove this try/catch once
-  // getStaticType() is reliable.
-  try {
-    return expr.getStaticType(typeEnvironment);
-  } catch (e) {
-    return const DynamicType();
-  }
-}
+DartType getStaticType(Expression expr, StaticTypeContext staticTypeContext) =>
+    expr.getStaticType(staticTypeContext);
 
 /// Returns `true` if [type] cannot be extended in user code.
 bool isSealedType(DartType type, CoreTypes coreTypes) {
@@ -212,7 +208,7 @@
 /// [receiver] can omit argument type checks needed due to generic-covariant
 /// parameters.
 bool isUncheckedCall(Member interfaceTarget, Expression receiver,
-    TypeEnvironment typeEnvironment) {
+    StaticTypeContext staticTypeContext) {
   if (interfaceTarget == null) {
     // Dynamic call cannot be unchecked.
     return false;
@@ -228,14 +224,14 @@
     return true;
   }
 
-  DartType receiverStaticType = getStaticType(receiver, typeEnvironment);
+  DartType receiverStaticType = getStaticType(receiver, staticTypeContext);
   if (receiverStaticType is InterfaceType) {
     if (receiverStaticType.typeArguments.isEmpty) {
       return true;
     }
 
-    if (receiverStaticType.typeArguments
-        .every((t) => isSealedType(t, typeEnvironment.coreTypes))) {
+    if (receiverStaticType.typeArguments.every(
+        (t) => isSealedType(t, staticTypeContext.typeEnvironment.coreTypes))) {
       return true;
     }
   }
@@ -282,9 +278,9 @@
 /// Returns true if invocation [node] is a closure call with statically known
 /// function type. Such invocations can omit argument type checks.
 bool isUncheckedClosureCall(MethodInvocation node,
-        TypeEnvironment typeEnvironment, BytecodeOptions options) =>
+        StaticTypeContext staticTypeContext, BytecodeOptions options) =>
     node.name.name == 'call' &&
-    getStaticType(node.receiver, typeEnvironment) is FunctionType &&
+    getStaticType(node.receiver, staticTypeContext) is FunctionType &&
     !options.avoidClosureCallInstructions;
 
 /// Returns true if [MethodInvocation] node with given [interfaceTarget] is
diff --git a/pkg/vm/lib/bytecode/local_vars.dart b/pkg/vm/lib/bytecode/local_vars.dart
index 88812ec..304fd0e 100644
--- a/pkg/vm/lib/bytecode/local_vars.dart
+++ b/pkg/vm/lib/bytecode/local_vars.dart
@@ -25,7 +25,7 @@
   Map<TreeNode, VariableDeclaration> _capturedStackTraceVars;
   Map<ForInStatement, VariableDeclaration> _capturedIteratorVars;
   final BytecodeOptions options;
-  final TypeEnvironment typeEnvironment;
+  final StaticTypeContext staticTypeContext;
   final Map<TreeNode, DirectCallMetadata> directCallMetadata;
 
   Scope _currentScope;
@@ -190,7 +190,7 @@
   List<VariableDeclaration> get sortedNamedParameters =>
       _currentFrame.sortedNamedParameters;
 
-  LocalVariables(Member node, this.options, this.typeEnvironment,
+  LocalVariables(Member node, this.options, this.staticTypeContext,
       this.directCallMetadata) {
     final scopeBuilder = new _ScopeBuilder(this);
     node.accept(scopeBuilder);
@@ -208,6 +208,14 @@
     _currentScope = _currentScope.parent;
     _currentFrame = _currentScope?.frame;
   }
+
+  void withTemp(TreeNode node, int temp, void action()) {
+    final old = _temps[node];
+    assert(old == null || old.length == 1);
+    _temps[node] = [temp];
+    action();
+    _temps[node] = old;
+  }
 }
 
 class VarDesc {
@@ -595,6 +603,9 @@
   @override
   visitVariableGet(VariableGet node) {
     _useVariable(node.variable);
+    if (node.variable.isLate && node.variable.initializer != null) {
+      node.variable.initializer.accept(this);
+    }
   }
 
   @override
@@ -1225,7 +1236,8 @@
   @override
   visitMethodInvocation(MethodInvocation node) {
     int numTemps = 0;
-    if (isUncheckedClosureCall(node, locals.typeEnvironment, locals.options)) {
+    if (isUncheckedClosureCall(
+        node, locals.staticTypeContext, locals.options)) {
       numTemps = 1;
     } else if (isCallThroughGetter(node.interfaceTarget)) {
       final args = node.arguments;
@@ -1282,8 +1294,15 @@
   }
 
   @override
+  visitVariableGet(VariableGet node) {
+    _visit(node, temps: node.variable.isLate ? 1 : 0);
+  }
+
+  @override
   visitVariableSet(VariableSet node) {
-    _visit(node, temps: locals.isCaptured(node.variable) ? 1 : 0);
+    final v = node.variable;
+    final bool needsTemp = locals.isCaptured(v) || v.isLate && v.isFinal;
+    _visit(node, temps: needsTemp ? 1 : 0);
   }
 
   @override
diff --git a/pkg/vm/lib/bytecode/object_table.dart b/pkg/vm/lib/bytecode/object_table.dart
index 1d8e290..7ef26b2 100644
--- a/pkg/vm/lib/bytecode/object_table.dart
+++ b/pkg/vm/lib/bytecode/object_table.dart
@@ -1745,14 +1745,13 @@
   _TypeHandle _dynamicType;
   _TypeHandle _voidType;
   _TypeHandle _neverType;
-  CoreTypes coreTypes;
   _NodeVisitor _nodeVisitor;
 
-  ObjectTable() {
+  ObjectTable(CoreTypes coreTypes) {
     _dynamicType = getOrAddObject(new _DynamicTypeHandle());
     _voidType = getOrAddObject(new _VoidTypeHandle());
     _neverType = getOrAddObject(new _NeverTypeHandle());
-    _nodeVisitor = new _NodeVisitor(this);
+    _nodeVisitor = new _NodeVisitor(this, coreTypes);
   }
 
   ObjectHandle getHandle(Node node) {
@@ -2093,11 +2092,13 @@
 
 class _NodeVisitor extends Visitor<ObjectHandle> {
   final ObjectTable objectTable;
+  final CoreTypes coreTypes;
   final _typeParameters = <TypeParameter, ObjectHandle>{};
   final Map<DartType, int> _recursiveTypeIds = <DartType, int>{};
-  final recursiveTypesValidator = new RecursiveTypesValidator();
+  final recursiveTypesValidator;
 
-  _NodeVisitor(this.objectTable);
+  _NodeVisitor(this.objectTable, this.coreTypes)
+      : recursiveTypesValidator = new RecursiveTypesValidator(coreTypes);
 
   @override
   ObjectHandle defaultNode(Node node) =>
@@ -2132,7 +2133,7 @@
 
   @override
   ObjectHandle visitBottomType(BottomType node) =>
-      objectTable.getHandle(objectTable.coreTypes.nullType);
+      objectTable.getHandle(coreTypes.nullType);
 
   @override
   ObjectHandle visitInterfaceType(InterfaceType node) {
diff --git a/pkg/vm/lib/bytecode/recognized_methods.dart b/pkg/vm/lib/bytecode/recognized_methods.dart
index 73033b6..a237c1f 100644
--- a/pkg/vm/lib/bytecode/recognized_methods.dart
+++ b/pkg/vm/lib/bytecode/recognized_methods.dart
@@ -5,7 +5,7 @@
 library vm.bytecode.recognized_methods;
 
 import 'package:kernel/ast.dart';
-import 'package:kernel/type_environment.dart' show TypeEnvironment;
+import 'package:kernel/type_environment.dart' show StaticTypeContext;
 
 import 'dbc.dart';
 import 'generics.dart' show getStaticType;
@@ -41,15 +41,18 @@
     '<=': Opcode.kCompareDoubleLe,
   };
 
-  final TypeEnvironment typeEnv;
+  final StaticTypeContext staticTypeContext;
 
-  RecognizedMethods(this.typeEnv);
+  RecognizedMethods(this.staticTypeContext);
 
-  DartType staticType(Expression expr) => getStaticType(expr, typeEnv);
+  DartType staticType(Expression expr) =>
+      getStaticType(expr, staticTypeContext);
 
-  bool isInt(DartType type) => type == typeEnv.coreTypes.intLegacyRawType;
+  bool isInt(DartType type) =>
+      type == staticTypeContext.typeEnvironment.coreTypes.intLegacyRawType;
 
-  bool isDouble(DartType type) => type == typeEnv.coreTypes.doubleLegacyRawType;
+  bool isDouble(DartType type) =>
+      type == staticTypeContext.typeEnvironment.coreTypes.doubleLegacyRawType;
 
   Opcode specializedBytecodeFor(MethodInvocation node) {
     final args = node.arguments;
diff --git a/pkg/vm/lib/bytecode/recursive_types_validator.dart b/pkg/vm/lib/bytecode/recursive_types_validator.dart
index acaa020..d88d291 100644
--- a/pkg/vm/lib/bytecode/recursive_types_validator.dart
+++ b/pkg/vm/lib/bytecode/recursive_types_validator.dart
@@ -5,6 +5,7 @@
 library vm.bytecode.recursive_types_validator;
 
 import 'package:kernel/ast.dart' hide MapEntry;
+import 'package:kernel/core_types.dart' show CoreTypes;
 import 'package:kernel/type_algebra.dart' show Substitution;
 
 import 'generics.dart'
@@ -13,10 +14,13 @@
 /// Detect recursive types and validates that finalized (flattened)
 /// representation of generic types is valid (finite).
 class RecursiveTypesValidator {
+  final CoreTypes coreTypes;
   final Set<DartType> _validatedTypes = <DartType>{};
   final Set<DartType> _recursiveTypes = <DartType>{};
   final Set<Class> _validatedClases = <Class>{};
 
+  RecursiveTypesValidator(this.coreTypes);
+
   /// Validates [type].
   void validateType(DartType type) {
     if (!isValidated(type)) {
@@ -39,7 +43,8 @@
   void validateClass(Class cls) {
     if (_validatedClases.add(cls)) {
       try {
-        validateType(cls.thisType);
+        validateType(
+            cls.getThisType(coreTypes, cls.enclosingLibrary.nonNullable));
       } on IllegalRecursiveTypeException catch (e) {
         _validatedClases.remove(cls);
         throw e;
@@ -103,6 +108,9 @@
   void visitBottomType(BottomType node) {}
 
   @override
+  void visitNeverType(NeverType node) {}
+
+  @override
   void visitTypeParameterType(TypeParameterType node) {}
 
   @override
diff --git a/pkg/vm/lib/kernel_front_end.dart b/pkg/vm/lib/kernel_front_end.dart
index e35422e..733b3b5 100644
--- a/pkg/vm/lib/kernel_front_end.dart
+++ b/pkg/vm/lib/kernel_front_end.dart
@@ -230,6 +230,7 @@
     ..embedSourceText = embedSources;
 
   final results = await compileToKernel(mainUri, compilerOptions,
+      includePlatform: linkedDependencies.isNotEmpty,
       aot: aot,
       useGlobalTypeFlowAnalysis: tfa,
       environmentDefines: environmentDefines,
@@ -267,9 +268,7 @@
     await writeOutputSplitByPackages(
       mainUri,
       compilerOptions,
-      results.component,
-      results.coreTypes,
-      results.classHierarchy,
+      results,
       outputFileName,
       genBytecode: genBytecode,
       bytecodeOptions: bytecodeOptions,
@@ -284,12 +283,16 @@
 /// collection of compiled sources.
 class KernelCompilationResults {
   final Component component;
+
+  /// Set of libraries loaded from .dill, with or without the SDK depending on
+  /// the compilation settings.
+  final Set<Library> loadedLibraries;
   final ClassHierarchy classHierarchy;
   final CoreTypes coreTypes;
   final Iterable<Uri> compiledSources;
 
-  KernelCompilationResults(this.component, this.classHierarchy, this.coreTypes,
-      this.compiledSources);
+  KernelCompilationResults(this.component, this.loadedLibraries,
+      this.classHierarchy, this.coreTypes, this.compiledSources);
 }
 
 /// Generates a kernel representation of the program whose main library is in
@@ -299,7 +302,8 @@
 ///
 Future<KernelCompilationResults> compileToKernel(
     Uri source, CompilerOptions options,
-    {bool aot: false,
+    {bool includePlatform: false,
+    bool aot: false,
     bool useGlobalTypeFlowAnalysis: false,
     Map<String, String> environmentDefines,
     bool enableAsserts: true,
@@ -314,10 +318,13 @@
 
   setVMEnvironmentDefines(environmentDefines, options);
   CompilerResult compilerResult = await kernelForProgram(source, options);
-
   Component component = compilerResult?.component;
   final compiledSources = component?.uriToSource?.keys;
 
+  Set<Library> loadedLibraries = createLoadedLibrariesSet(
+      compilerResult?.loadedComponents, compilerResult?.sdkComponent,
+      includePlatform: includePlatform);
+
   // Run global transformations only if component is correct.
   if (aot && component != null) {
     await runGlobalTransformations(
@@ -330,8 +337,15 @@
   }
 
   if (genBytecode && !errorDetector.hasCompilationErrors && component != null) {
+    List<Library> libraries = new List<Library>();
+    for (Library library in component.libraries) {
+      if (loadedLibraries.contains(library)) continue;
+      libraries.add(library);
+    }
+
     await runWithFrontEndCompilerContext(source, options, component, () {
       generateBytecode(component,
+          libraries: libraries,
           hierarchy: compilerResult.classHierarchy,
           coreTypes: compilerResult.coreTypes,
           options: bytecodeOptions);
@@ -345,8 +359,37 @@
   // Restore error handler (in case 'options' are reused).
   options.onDiagnostic = errorDetector.previousErrorHandler;
 
-  return new KernelCompilationResults(component, compilerResult?.classHierarchy,
-      compilerResult?.coreTypes, compiledSources);
+  return new KernelCompilationResults(
+      component,
+      loadedLibraries,
+      compilerResult?.classHierarchy,
+      compilerResult?.coreTypes,
+      compiledSources);
+}
+
+Set<Library> createLoadedLibrariesSet(
+    List<Component> loadedComponents, Component sdkComponent,
+    {bool includePlatform: false}) {
+  final Set<Library> loadedLibraries = {};
+  if (loadedComponents != null) {
+    for (Component c in loadedComponents) {
+      for (Library lib in c.libraries) {
+        loadedLibraries.add(lib);
+      }
+    }
+  }
+  if (sdkComponent != null) {
+    if (includePlatform) {
+      for (Library lib in sdkComponent.libraries) {
+        loadedLibraries.remove(lib);
+      }
+    } else {
+      for (Library lib in sdkComponent.libraries) {
+        loadedLibraries.add(lib);
+      }
+    }
+  }
+  return loadedLibraries;
 }
 
 void setVMEnvironmentDefines(
@@ -618,9 +661,7 @@
 Future writeOutputSplitByPackages(
   Uri source,
   CompilerOptions compilerOptions,
-  Component component,
-  CoreTypes coreTypes,
-  ClassHierarchy hierarchy,
+  KernelCompilationResults compilationResults,
   String outputFileName, {
   bool genBytecode: false,
   BytecodeOptions bytecodeOptions,
@@ -631,31 +672,34 @@
   }
 
   final packages = new List<String>();
-  await runWithFrontEndCompilerContext(source, compilerOptions, component,
-      () async {
+  await runWithFrontEndCompilerContext(
+      source, compilerOptions, compilationResults.component, () async {
     // When loading a kernel file list, flutter_runner and dart_runner expect
     // 'main' to be last.
-    await forEachPackage(component,
+    await forEachPackage(compilationResults,
         (String package, List<Library> libraries) async {
       packages.add(package);
       final String filename = '$outputFileName-$package.dilp';
       final IOSink sink = new File(filename).openWrite();
 
-      Component partComponent = component;
+      Component partComponent = compilationResults.component;
       if (genBytecode) {
         generateBytecode(partComponent,
             options: bytecodeOptions,
             libraries: libraries,
-            hierarchy: hierarchy,
-            coreTypes: coreTypes);
+            hierarchy: compilationResults.classHierarchy,
+            coreTypes: compilationResults.coreTypes);
 
         if (dropAST) {
           partComponent = createFreshComponentWithBytecode(partComponent);
         }
       }
 
-      final BinaryPrinter printer = new LimitedBinaryPrinter(sink,
-          (lib) => packageFor(lib) == package, false /* excludeUriToSource */);
+      final BinaryPrinter printer = new LimitedBinaryPrinter(
+          sink,
+          (lib) =>
+              packageFor(lib, compilationResults.loadedLibraries) == package,
+          false /* excludeUriToSource */);
       printer.writeComponentFile(partComponent);
 
       await sink.close();
@@ -673,10 +717,9 @@
   await packagesList.close();
 }
 
-String packageFor(Library lib) {
+String packageFor(Library lib, Set<Library> loadedLibraries) {
   // Core libraries are not written into any package kernel binaries.
-  // ignore: DEPRECATED_MEMBER_USE
-  if (lib.isExternal) return null;
+  if (loadedLibraries.contains(lib)) return null;
 
   // Packages are written into their own kernel binaries.
   Uri uri = lib.importUri;
@@ -702,15 +745,20 @@
   }
 }
 
-Future<Null> forEachPackage<T>(
-    Component component, T action(String package, List<Library> libraries),
+Future<Null> forEachPackage<T>(KernelCompilationResults results,
+    T action(String package, List<Library> libraries),
     {bool mainFirst}) async {
+  final Component component = results.component;
+  final Set<Library> loadedLibraries = results.loadedLibraries;
   sortComponent(component);
 
   final packages = new Map<String, List<Library>>();
   packages['main'] = new List<Library>(); // Always create 'main'.
   for (Library lib in component.libraries) {
-    packages.putIfAbsent(packageFor(lib), () => new List<Library>()).add(lib);
+    packages
+        .putIfAbsent(
+            packageFor(lib, loadedLibraries), () => new List<Library>())
+        .add(lib);
   }
   packages.remove(null); // Ignore external libraries.
 
diff --git a/pkg/vm/lib/target/vm.dart b/pkg/vm/lib/target/vm.dart
index a647eb8..bd70be0 100644
--- a/pkg/vm/lib/target/vm.dart
+++ b/pkg/vm/lib/target/vm.dart
@@ -14,11 +14,14 @@
     as transformMixins show transformLibraries;
 import 'package:kernel/transformations/continuation.dart' as transformAsync
     show transformLibraries, transformProcedure;
+import 'package:kernel/type_environment.dart';
 import 'package:kernel/vm/constants_native_effects.dart'
     show VmConstantsBackend;
 
 import '../metadata/binary_cache.dart' show BinaryCacheMetadataRepository;
 import '../transformations/call_site_annotator.dart' as callSiteAnnotator;
+import '../transformations/late_var_init_transformer.dart'
+    as lateVarInitTransformer;
 import '../transformations/list_factory_specializer.dart'
     as listFactorySpecializer;
 import '../transformations/ffi.dart' as transformFfi show ReplacedMembers;
@@ -48,6 +51,9 @@
   bool get supportsSetLiterals => false;
 
   @override
+  bool get supportsLateFields => !flags.forceLateLoweringForTesting;
+
+  @override
   String get name => 'vm';
 
   // This is the order that bootstrap libraries are loaded according to
@@ -145,13 +151,17 @@
 
     // TODO(kmillikin): Make this run on a per-method basis.
     bool productMode = environmentDefines["dart.vm.product"] == "true";
-    transformAsync.transformLibraries(coreTypes, libraries,
+    transformAsync.transformLibraries(
+        new TypeEnvironment(coreTypes, hierarchy), libraries,
         productMode: productMode);
     logger?.call("Transformed async methods");
 
     listFactorySpecializer.transformLibraries(libraries, coreTypes);
     logger?.call("Specialized list factories");
 
+    lateVarInitTransformer.transformLibraries(libraries);
+    logger?.call("Transformed late variable initializers");
+
     callSiteAnnotator.transformLibraries(
         component, libraries, coreTypes, hierarchy);
     logger?.call("Annotated call sites");
@@ -161,7 +171,8 @@
   void performTransformationsOnProcedure(
       CoreTypes coreTypes, ClassHierarchy hierarchy, Procedure procedure,
       {void logger(String msg)}) {
-    transformAsync.transformProcedure(coreTypes, procedure);
+    transformAsync.transformProcedure(
+        new TypeEnvironment(coreTypes, hierarchy), procedure);
     logger?.call("Transformed async functions");
   }
 
@@ -348,7 +359,7 @@
           new ListLiteral(elements, typeArgument: typeArgument)
             ..fileOffset = offset
         ], types: [
-          new DynamicType()
+          typeArgument,
         ]));
   }
 
diff --git a/pkg/vm/lib/transformations/call_site_annotator.dart b/pkg/vm/lib/transformations/call_site_annotator.dart
index 7b6b620..b93b258 100644
--- a/pkg/vm/lib/transformations/call_site_annotator.dart
+++ b/pkg/vm/lib/transformations/call_site_annotator.dart
@@ -12,7 +12,8 @@
 import 'package:kernel/ast.dart';
 import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
 import 'package:kernel/core_types.dart' show CoreTypes;
-import 'package:kernel/type_environment.dart' show TypeEnvironment;
+import 'package:kernel/type_environment.dart'
+    show StaticTypeContext, TypeEnvironment;
 
 import '../metadata/call_site_attributes.dart';
 
@@ -32,6 +33,7 @@
 class AnnotateWithStaticTypes extends RecursiveVisitor<Null> {
   final CallSiteAttributesMetadataRepository _metadata;
   final TypeEnvironment env;
+  StaticTypeContext _staticTypeContext;
 
   AnnotateWithStaticTypes(
       Component component, CoreTypes coreTypes, ClassHierarchy hierarchy)
@@ -39,30 +41,15 @@
         env = new TypeEnvironment(coreTypes, hierarchy);
 
   @override
-  visitProcedure(Procedure proc) {
-    if (!proc.isStatic) {
-      env.thisType = proc.enclosingClass?.thisType;
-    }
-    super.visitProcedure(proc);
-    env.thisType = null;
-  }
-
-  @override
-  visitConstructor(Constructor proc) {
-    env.thisType = proc.enclosingClass?.thisType;
-    super.visitConstructor(proc);
-    env.thisType = null;
+  defaultMember(Member node) {
+    _staticTypeContext = new StaticTypeContext(node, env);
+    super.defaultMember(node);
+    _staticTypeContext = null;
   }
 
   void annotateWithType(TreeNode node, Expression receiver) {
-    try {
-      _metadata.mapping[node] = new CallSiteAttributesMetadata(
-          receiverType: receiver.getStaticType(env));
-    } catch (e) {
-      // TODO(dartbug.com/34496) Currently getStaticType is unreliable due to
-      // various issues with AST welltypedness. As a workaround we just
-      // swallow the exception.
-    }
+    _metadata.mapping[node] = new CallSiteAttributesMetadata(
+        receiverType: receiver.getStaticType(_staticTypeContext));
   }
 
   @override
diff --git a/pkg/vm/lib/transformations/devirtualization.dart b/pkg/vm/lib/transformations/devirtualization.dart
index ff8e4ca..838fe66 100644
--- a/pkg/vm/lib/transformations/devirtualization.dart
+++ b/pkg/vm/lib/transformations/devirtualization.dart
@@ -91,9 +91,7 @@
   @override
   visitLibrary(Library node) {
     if (_trace) {
-      // ignore: DEPRECATED_MEMBER_USE
-      String external = node.isExternal ? " (external)" : "";
-      print("[devirt] Processing library ${node.name}${external}");
+      print("[devirt] Processing library ${node.name}");
     }
     super.visitLibrary(node);
   }
diff --git a/pkg/vm/lib/transformations/ffi.dart b/pkg/vm/lib/transformations/ffi.dart
index 4837963..76e6f9c 100644
--- a/pkg/vm/lib/transformations/ffi.dart
+++ b/pkg/vm/lib/transformations/ffi.dart
@@ -181,6 +181,7 @@
 
   final Class intClass;
   final Class doubleClass;
+  final Class listClass;
   final Class pragmaClass;
   final Field pragmaName;
   final Field pragmaOptions;
@@ -216,6 +217,7 @@
       : env = new TypeEnvironment(coreTypes, hierarchy),
         intClass = coreTypes.intClass,
         doubleClass = coreTypes.doubleClass,
+        listClass = coreTypes.listClass,
         pragmaClass = coreTypes.pragmaClass,
         pragmaName = coreTypes.pragmaName,
         pragmaOptions = coreTypes.pragmaOptions,
diff --git a/pkg/vm/lib/transformations/ffi_definitions.dart b/pkg/vm/lib/transformations/ffi_definitions.dart
index 249a45a..9861852 100644
--- a/pkg/vm/lib/transformations/ffi_definitions.dart
+++ b/pkg/vm/lib/transformations/ffi_definitions.dart
@@ -274,7 +274,8 @@
               IntConstant(values[Abi.wordSize32Align32]),
               IntConstant(values[Abi.wordSize32Align64])
             ]),
-            InterfaceType(intClass, Nullability.legacy)),
+            InterfaceType(listClass, Nullability.legacy,
+                [InterfaceType(intClass, Nullability.legacy)])),
         Name("[]"),
         Arguments([StaticInvocation(abiMethod, Arguments([]))]),
         listElementAt);
@@ -332,7 +333,8 @@
                 loadMethod,
                 Arguments([
                   PropertyGet(ThisExpression(), pointerName, pointerGetter),
-                  ConstantExpression(IntConstant(0))
+                  ConstantExpression(IntConstant(0),
+                      InterfaceType(intClass, Nullability.legacy))
                 ], types: typeArguments))),
             returnType: field.type),
         fileUri: field.fileUri)
@@ -353,7 +355,8 @@
                   storeMethod,
                   Arguments([
                     PropertyGet(ThisExpression(), pointerName, pointerGetter),
-                    ConstantExpression(IntConstant(0)),
+                    ConstantExpression(IntConstant(0),
+                        InterfaceType(intClass, Nullability.legacy)),
                     VariableGet(argument)
                   ], types: typeArguments))),
               returnType: VoidType(),
diff --git a/pkg/vm/lib/transformations/ffi_use_sites.dart b/pkg/vm/lib/transformations/ffi_use_sites.dart
index e8562ab..9e3ba3ed 100644
--- a/pkg/vm/lib/transformations/ffi_use_sites.dart
+++ b/pkg/vm/lib/transformations/ffi_use_sites.dart
@@ -53,6 +53,7 @@
 class _FfiUseSiteTransformer extends FfiTransformer {
   final Map<Field, Procedure> replacedGetters;
   final Map<Field, Procedure> replacedSetters;
+  StaticTypeContext _staticTypeContext;
 
   Library currentLibrary;
   bool get isFfiLibrary => currentLibrary == ffiLibrary;
@@ -79,7 +80,6 @@
 
   @override
   visitClass(Class node) {
-    env.thisType = InterfaceType(node, Nullability.legacy);
     try {
       _ensureNotExtendsOrImplementsSealedClass(node);
       return super.visitClass(node);
@@ -88,12 +88,34 @@
       // cause compilation to fail. By continuing, we can report more
       // diagnostics before compilation ends.
       return super.visitClass(node);
-    } finally {
-      env.thisType = null;
     }
   }
 
   @override
+  visitField(Field node) {
+    _staticTypeContext = new StaticTypeContext(node, env);
+    var result = super.visitField(node);
+    _staticTypeContext = null;
+    return result;
+  }
+
+  @override
+  visitConstructor(Constructor node) {
+    _staticTypeContext = new StaticTypeContext(node, env);
+    var result = super.visitConstructor(node);
+    _staticTypeContext = null;
+    return result;
+  }
+
+  @override
+  visitProcedure(Procedure node) {
+    _staticTypeContext = new StaticTypeContext(node, env);
+    var result = super.visitProcedure(node);
+    _staticTypeContext = null;
+    return result;
+  }
+
+  @override
   visitPropertyGet(PropertyGet node) {
     super.visitPropertyGet(node);
 
@@ -128,7 +150,7 @@
         final DartType nativeType = InterfaceType(
             nativeFunctionClass, Nullability.legacy, [node.arguments.types[0]]);
         final Expression func = node.arguments.positional[0];
-        final DartType dartType = func.getStaticType(env);
+        final DartType dartType = func.getStaticType(_staticTypeContext);
 
         _ensureIsStaticFunction(func);
 
@@ -189,7 +211,8 @@
             return node;
           }
 
-          final DartType returnType = exceptionalReturn.getStaticType(env);
+          final DartType returnType =
+              exceptionalReturn.getStaticType(_staticTypeContext);
 
           if (!env.isSubtypeOf(returnType, funcType.returnType,
               SubtypeCheckMode.ignoringNullabilities)) {
@@ -299,7 +322,8 @@
         return _replaceLookupFunction(node);
       } else if (target == asFunctionMethod) {
         final DartType dartType = node.arguments.types[0];
-        final DartType pointerType = node.receiver.getStaticType(env);
+        final DartType pointerType =
+            node.receiver.getStaticType(_staticTypeContext);
         final DartType nativeType = _pointerTypeGetTypeArg(pointerType);
 
         _ensureNativeTypeValid(pointerType, node);
@@ -313,7 +337,8 @@
       } else if (target == elementAtMethod) {
         // TODO(37773): When moving to extension methods we can get rid of
         // this rewiring.
-        final DartType pointerType = node.receiver.getStaticType(env);
+        final DartType pointerType =
+            node.receiver.getStaticType(_staticTypeContext);
         final DartType nativeType = _pointerTypeGetTypeArg(pointerType);
         if (nativeType is TypeParameterType) {
           // Do not rewire generic invocations.
diff --git a/pkg/vm/lib/transformations/late_var_init_transformer.dart b/pkg/vm/lib/transformations/late_var_init_transformer.dart
new file mode 100644
index 0000000..2e916d0
--- /dev/null
+++ b/pkg/vm/lib/transformations/late_var_init_transformer.dart
@@ -0,0 +1,85 @@
+// Copyright (c) 2019, 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:kernel/ast.dart';
+
+/// Wraps the initializers of late local variables in closures.
+void transformLibraries(List<Library> libraries) {
+  const transformer = _LateVarInitTransformer();
+  libraries.forEach(transformer.visitLibrary);
+}
+
+class _LateVarInitTransformer extends Transformer {
+  const _LateVarInitTransformer();
+
+  bool _shouldApplyTransform(VariableDeclaration v) {
+    // This transform only applies to late variables.
+    if (!v.isLate) return false;
+
+    // Const variables are ignored.
+    if (v.isConst) return false;
+
+    // Variables with no initializer or a trivial initializer are ignored.
+    if (v.initializer == null) return false;
+    final Expression init = v.initializer;
+    if (init is StringLiteral) return false;
+    if (init is BoolLiteral) return false;
+    if (init is IntLiteral) return false;
+    if (init is DoubleLiteral) return false;
+    if (init is NullLiteral) return false;
+    if (init is ConstantExpression && init.constant is PrimitiveConstant) {
+      return false;
+    }
+
+    return true;
+  }
+
+  List<Statement> _transformVariableDeclaration(
+      TreeNode parent, VariableDeclaration node) {
+    super.visitVariableDeclaration(node);
+
+    final fnNode =
+        FunctionNode(ReturnStatement(node.initializer), returnType: node.type);
+    final fn = FunctionDeclaration(
+        VariableDeclaration("#${node.name}#initializer",
+            type: fnNode.thisFunctionType),
+        fnNode)
+      ..parent = parent;
+    node.initializer =
+        MethodInvocation(VariableGet(fn.variable), Name("call"), Arguments([]))
+          ..parent = node;
+
+    return [fn, node];
+  }
+
+  void _transformStatements(TreeNode parent, List<Statement> statements) {
+    List<Statement> oldStatements = statements;
+    for (var i = 0; i < oldStatements.length; ++i) {
+      Statement s = oldStatements[i];
+      if (s is VariableDeclaration && _shouldApplyTransform(s)) {
+        if (oldStatements == statements) {
+          oldStatements = List<Statement>.of(statements);
+          statements.clear();
+        }
+        statements.addAll(_transformVariableDeclaration(parent, s));
+      } else if (oldStatements != statements) {
+        statements.add(s.accept<TreeNode>(this)..parent = parent);
+      } else {
+        statements[i] = s.accept<TreeNode>(this)..parent = parent;
+      }
+    }
+  }
+
+  @override
+  visitBlock(Block node) {
+    _transformStatements(node, node.statements);
+    return node;
+  }
+
+  @override
+  visitAssertBlock(AssertBlock node) {
+    _transformStatements(node, node.statements);
+    return node;
+  }
+}
diff --git a/pkg/vm/lib/transformations/mixin_deduplication.dart b/pkg/vm/lib/transformations/mixin_deduplication.dart
index 610a20d..fcf8224 100644
--- a/pkg/vm/lib/transformations/mixin_deduplication.dart
+++ b/pkg/vm/lib/transformations/mixin_deduplication.dart
@@ -9,7 +9,28 @@
 /// De-duplication of identical mixin applications.
 void transformComponent(Component component) {
   final deduplicateMixins = new DeduplicateMixinsTransformer();
+  final interfaceTargetResolver = InterfaceTargetResolver(deduplicateMixins);
+
+  // Deduplicate mixins and re-resolve super initializers.
+  // (this is a shallow transformation)
   component.libraries.forEach(deduplicateMixins.visitLibrary);
+
+  // Do a deep transformation to re-resolve all interface targets that point to
+  // members of removed mixin application classes.
+
+  // This is necessary iff the component was assembled from individual modular
+  // kernel compilations:
+  //
+  //   * if the CFE reads in the entire program as source, interface targets
+  //     will point to the original mixin class
+  //
+  //   * if the CFE reads in dependencies as kernel, interface targets will
+  //     point to the already existing mixin application classes.
+  //
+  // TODO(dartbug.com/39375): Remove this extra O(N) pass over the AST if the
+  // CFE decides to consistently let the interface target point to the mixin
+  // class (instead of mixin application).
+  component.libraries.forEach(interfaceTargetResolver.visitLibrary);
 }
 
 class _DeduplicateMixinKey {
@@ -59,20 +80,12 @@
 
   @override
   TreeNode visitLibrary(Library node) {
-    // ignore: DEPRECATED_MEMBER_USE
-    if (!node.isExternal) {
-      transformList(node.classes, this, node);
-    }
+    transformList(node.classes, this, node);
     return node;
   }
 
   @override
   TreeNode visitClass(Class c) {
-    // ignore: DEPRECATED_MEMBER_USE
-    if (c.enclosingLibrary.isExternal) {
-      return c;
-    }
-
     if (_duplicatedMixins.containsKey(c)) {
       return null; // Class was de-duplicated already, just remove it.
     }
@@ -96,7 +109,6 @@
     if (canonical != c) {
       c.canonicalName?.unbind();
       _duplicatedMixins[c] = canonical;
-      // print('Replacing $c with $canonical');
       return null; // Remove class.
     }
 
@@ -128,6 +140,73 @@
       throw 'Unexpected node ${node.runtimeType}: $node';
 }
 
+/// Rewrites interface targets to point to the deduplicated mixin application
+/// class.
+class InterfaceTargetResolver extends RecursiveVisitor<TreeNode> {
+  final DeduplicateMixinsTransformer transformer;
+
+  InterfaceTargetResolver(this.transformer);
+
+  defaultTreeNode(TreeNode node) {
+    node.visitChildren(this);
+    return node;
+  }
+
+  visitPropertyGet(PropertyGet node) {
+    node.interfaceTarget = _resolveNewInterfaceTarget(node.interfaceTarget);
+    return super.visitPropertyGet(node);
+  }
+
+  visitPropertySet(PropertySet node) {
+    node.interfaceTarget = _resolveNewInterfaceTarget(node.interfaceTarget);
+    return super.visitPropertySet(node);
+  }
+
+  visitMethodInvocation(MethodInvocation node) {
+    node.interfaceTarget = _resolveNewInterfaceTarget(node.interfaceTarget);
+    return super.visitMethodInvocation(node);
+  }
+
+  visitSuperPropertyGet(SuperPropertyGet node) {
+    node.interfaceTarget = _resolveNewInterfaceTarget(node.interfaceTarget);
+    return super.visitSuperPropertyGet(node);
+  }
+
+  visitSuperPropertySet(SuperPropertySet node) {
+    node.interfaceTarget = _resolveNewInterfaceTarget(node.interfaceTarget);
+    return super.visitSuperPropertySet(node);
+  }
+
+  visitSuperMethodInvocation(SuperMethodInvocation node) {
+    node.interfaceTarget = _resolveNewInterfaceTarget(node.interfaceTarget);
+    return super.visitSuperMethodInvocation(node);
+  }
+
+  Member _resolveNewInterfaceTarget(Member m) {
+    final Class c = m?.enclosingClass;
+    if (c != null && c.isAnonymousMixin) {
+      final Class replacement = transformer._duplicatedMixins[c];
+      if (replacement != null) {
+        // The class got removed, so we need to re-resolve the interface target.
+        return _findMember(replacement, m);
+      }
+    }
+    return m;
+  }
+
+  Member _findMember(Class klass, Member m) {
+    if (m is Field) {
+      return klass.members.where((other) => other.name == m.name).single;
+    } else if (m is Procedure) {
+      return klass.procedures
+          .where((other) => other.kind == m.kind && other.name == m.name)
+          .single;
+    } else {
+      throw 'Hit unexpected interface target which is not a Field/Procedure';
+    }
+  }
+}
+
 /// Corrects forwarding constructors inserted by mixin resolution after
 /// replacing superclass.
 void _correctForwardingConstructors(Class c, Class oldSuper, Class newSuper) {
diff --git a/pkg/vm/lib/transformations/type_flow/analysis.dart b/pkg/vm/lib/transformations/type_flow/analysis.dart
index 259d06e..b03f943 100644
--- a/pkg/vm/lib/transformations/type_flow/analysis.dart
+++ b/pkg/vm/lib/transformations/type_flow/analysis.dart
@@ -133,8 +133,8 @@
 
     final nsmArgs = new Args<Type>([
       receiver,
-      new Type.cone(
-          typeFlowAnalysis.environment.coreTypes.invocationLegacyRawType)
+      typeFlowAnalysis.hierarchyCache.fromStaticType(
+          typeFlowAnalysis.environment.coreTypes.invocationLegacyRawType, false)
     ]);
 
     final nsmInvocation =
@@ -346,7 +346,7 @@
 
     // Calculate result as a union of results of direct invocations
     // corresponding to each target.
-    Type result = new Type.empty();
+    Type result = const EmptyType();
 
     if (targets.isEmpty) {
       tracePrint("No targets...");
@@ -438,9 +438,8 @@
     }
 
     if (selector is InterfaceSelector) {
-      final staticReceiverType = new Type.fromStatic(typeFlowAnalysis
-          .environment.coreTypes
-          .legacyRawType(selector.member.enclosingClass));
+      final staticReceiverType = new ConeType(typeFlowAnalysis.hierarchyCache
+          .getTFClass(selector.member.enclosingClass));
       receiver = receiver.intersection(
           staticReceiverType, typeFlowAnalysis.hierarchyCache);
       assertx(receiver is! NullableType);
@@ -455,7 +454,7 @@
       // invocation to the receiver class. A new allocated class discovered
       // in the receiver cone will invalidate this invocation.
       receiver = typeFlowAnalysis.hierarchyCache
-          .specializeTypeCone((receiver as ConeType).dartType);
+          .specializeTypeCone((receiver as ConeType).cls);
     }
 
     assertx(targets.isEmpty);
@@ -497,10 +496,11 @@
       ConcreteType receiver,
       Map<Member, _ReceiverTypeBuilder> targets,
       TypeFlowAnalysis typeFlowAnalysis) {
-    Class class_ = receiver.classNode;
+    final TFClass cls = receiver.cls;
 
-    Member target = typeFlowAnalysis.hierarchyCache.hierarchy
-        .getDispatchTarget(class_, selector.name, setter: selector.isSetter);
+    Member target = typeFlowAnalysis.hierarchyCache.hierarchy.getDispatchTarget(
+        cls.classNode, selector.name,
+        setter: selector.isSetter);
 
     if (target != null) {
       if (kPrintTrace) {
@@ -508,7 +508,7 @@
       }
       _getReceiverTypeBuilder(targets, target).addConcreteType(receiver);
     } else {
-      if (typeFlowAnalysis.hierarchyCache.hasNonTrivialNoSuchMethod(class_)) {
+      if (typeFlowAnalysis.hierarchyCache.hasNonTrivialNoSuchMethod(cls)) {
         if (kPrintTrace) {
           tracePrint("Found non-trivial noSuchMethod for receiver $receiver");
         }
@@ -652,7 +652,7 @@
       _type = null;
     }
 
-    assertx(_list.last.classId.compareTo(type.classId) < 0);
+    assertx(_list.last.cls.id < type.cls.id);
     _list.add(type);
   }
 
@@ -762,8 +762,8 @@
   /// Flag indicating if field initializer was executed.
   bool isInitialized = false;
 
-  _FieldValue(this.field, this.typeGuardSummary)
-      : staticType = new Type.fromStatic(field.type) {
+  _FieldValue(this.field, this.typeGuardSummary, TypesBuilder typesBuilder)
+      : staticType = typesBuilder.fromStaticType(field.type, true) {
     if (field.initializer == null && _isDefaultValueOfFieldObservable()) {
       value = new Type.nullable(const EmptyType());
     } else {
@@ -872,24 +872,24 @@
   _DynamicTargetSet(this.selector, this.isObjectMember);
 }
 
-class _ClassData extends _DependencyTracker implements ClassId<_ClassData> {
-  final int _id;
-  final Class class_;
-  final Set<_ClassData> supertypes; // List of super-types including this.
-  final Set<_ClassData> _allocatedSubtypes = new Set<_ClassData>();
+class _TFClassImpl extends TFClass {
+  final Set<_TFClassImpl> supertypes; // List of super-types including this.
+  final Set<_TFClassImpl> _allocatedSubtypes = new Set<_TFClassImpl>();
+  final _DependencyTracker dependencyTracker = new _DependencyTracker();
 
   /// Flag indicating if this class has a noSuchMethod() method not inherited
   /// from Object.
   /// Lazy initialized by ClassHierarchyCache.hasNonTrivialNoSuchMethod().
   bool hasNonTrivialNoSuchMethod;
 
-  _ClassData(this._id, this.class_, this.supertypes) {
+  _TFClassImpl(int id, Class classNode, this.supertypes)
+      : super(id, classNode) {
     supertypes.add(this);
   }
 
   ConcreteType _concreteType;
   ConcreteType get concreteType =>
-      _concreteType ??= new ConcreteType(this, class_, null);
+      _concreteType ??= new ConcreteType(this, null);
 
   Type _specializedConeType;
   Type get specializedConeType =>
@@ -898,7 +898,7 @@
   Type _calculateConeTypeSpecialization() {
     final int numSubTypes = _allocatedSubtypes.length;
     if (numSubTypes == 0) {
-      return new Type.empty();
+      return const EmptyType();
     } else if (numSubTypes == 1) {
       return _allocatedSubtypes.single.concreteType;
     } else {
@@ -913,25 +913,11 @@
     }
   }
 
-  void addAllocatedSubtype(_ClassData subType) {
+  void addAllocatedSubtype(_TFClassImpl subType) {
     _allocatedSubtypes.add(subType);
     _specializedConeType = null; // Reset cached specialization.
   }
 
-  @override
-  int get hashCode => _id;
-
-  @override
-  bool operator ==(other) =>
-      identical(this, other) ||
-      (other is _ClassData) && (this._id == other._id);
-
-  @override
-  int compareTo(_ClassData other) => this._id.compareTo(other._id);
-
-  @override
-  String toString() => "_C $class_";
-
   String dump() => "$this {supers: $supertypes}";
 }
 
@@ -1000,12 +986,13 @@
   }
 }
 
-class _ClassHierarchyCache implements TypeHierarchy {
+// TODO(alexmarkov): Rename to _TypeHierarchyImpl.
+class _ClassHierarchyCache extends TypeHierarchy {
   final TypeFlowAnalysis _typeFlowAnalysis;
   final ClosedWorldClassHierarchy hierarchy;
   final TypeEnvironment environment;
   final Set<Class> allocatedClasses = new Set<Class>();
-  final Map<Class, _ClassData> classes = <Class, _ClassData>{};
+  final Map<Class, _TFClassImpl> classes = <Class, _TFClassImpl>{};
   final GenericInterfacesInfo genericInterfacesInfo;
 
   /// Object.noSuchMethod().
@@ -1027,35 +1014,39 @@
   _ClassHierarchyCache(this._typeFlowAnalysis, this.hierarchy,
       this.genericInterfacesInfo, this.environment)
       : objectNoSuchMethod = hierarchy.getDispatchTarget(
-            environment.coreTypes.objectClass, noSuchMethodName) {
+            environment.coreTypes.objectClass, noSuchMethodName),
+        super(environment.coreTypes) {
     assertx(objectNoSuchMethod != null);
   }
 
-  _ClassData getClassData(Class c) {
-    return classes[c] ??= _createClassData(c);
+  @override
+  _TFClassImpl getTFClass(Class c) {
+    return classes[c] ??= _createTFClass(c);
   }
 
-  _ClassData _createClassData(Class c) {
-    final supertypes = new Set<_ClassData>();
+  _TFClassImpl _createTFClass(Class c) {
+    final supertypes = new Set<_TFClassImpl>();
     for (var sup in c.supers) {
-      supertypes.addAll(getClassData(sup.classNode).supertypes);
+      supertypes.addAll(getTFClass(sup.classNode).supertypes);
     }
-    return new _ClassData(++_classIdCounter, c, supertypes);
+    return new _TFClassImpl(++_classIdCounter, c, supertypes);
   }
 
   ConcreteType addAllocatedClass(Class cl) {
     assertx(!cl.isAbstract);
     assertx(!_sealed);
 
-    final _ClassData classData = getClassData(cl);
+    final _TFClassImpl classImpl = getTFClass(cl);
 
     if (allocatedClasses.add(cl)) {
-      classData.addAllocatedSubtype(classData);
-      classData.invalidateDependentInvocations(_typeFlowAnalysis.workList);
+      classImpl.addAllocatedSubtype(classImpl);
+      classImpl.dependencyTracker
+          .invalidateDependentInvocations(_typeFlowAnalysis.workList);
 
-      for (var supertype in classData.supertypes) {
-        supertype.addAllocatedSubtype(classData);
-        supertype.invalidateDependentInvocations(_typeFlowAnalysis.workList);
+      for (var supertype in classImpl.supertypes) {
+        supertype.addAllocatedSubtype(classImpl);
+        supertype.dependencyTracker
+            .invalidateDependentInvocations(_typeFlowAnalysis.workList);
       }
 
       for (var targetSet in _dynamicTargets.values) {
@@ -1063,7 +1054,7 @@
       }
     }
 
-    return classData.concreteType;
+    return classImpl.concreteType;
   }
 
   void seal() {
@@ -1071,112 +1062,58 @@
   }
 
   @override
-  bool isSubtype(DartType subType, DartType superType) {
+  bool isSubtype(Class sub, Class sup) {
     if (kPrintTrace) {
-      tracePrint("isSubtype for sub = $subType (${subType.runtimeType}),"
-          " sup = $superType (${superType.runtimeType})");
+      tracePrint("isSubtype for sub = $sub, sup = $sup");
     }
-    if (subType == superType) {
+    if (identical(sub, sup)) {
       return true;
     }
 
-    if (superType is DynamicType ||
-        superType is VoidType ||
-        subType is BottomType) {
-      return true;
-    }
-    if (subType is DynamicType ||
-        subType is VoidType ||
-        superType is BottomType) {
-      return false;
-    }
-
-    // TODO(alexmarkov): handle function types properly
-    if (subType is FunctionType) {
-      subType = _typeFlowAnalysis.environment.functionLegacyRawType;
-    }
-    if (superType is FunctionType) {
-      superType = _typeFlowAnalysis.environment.functionLegacyRawType;
-    }
-    // TODO(alexmarkov): handle generic types properly.
-    assertx(subType is! TypeParameterType);
-    assertx(superType is! TypeParameterType);
-
-    assertx(subType is InterfaceType, details: subType); // TODO(alexmarkov)
-    assertx(superType is InterfaceType, details: superType); // TODO(alexmarkov)
-
-    // InterfaceTypes should be raw, since we don't handle type arguments
-    // (although frankly we can't distinguish between raw C and C<dynamic).
-    assertx((subType as InterfaceType)
-        .typeArguments
-        .every((t) => t == const DynamicType()));
-    assertx((superType as InterfaceType)
-        .typeArguments
-        .every((t) => t == const DynamicType()));
-
-    Class subClass = (subType as InterfaceType).classNode;
-    Class superClass = (superType as InterfaceType).classNode;
-    if (subClass == superClass) {
+    // TODO(alexmarkov): handle FutureOr more precisely.
+    if (sup == coreTypes.futureOrClass) {
       return true;
     }
 
-    // TODO(alexmarkov): handle FutureOr more precisely (requires generics).
-    if (superClass == _typeFlowAnalysis.environment.futureOrClass) {
-      return true;
-    }
-
-    _ClassData subClassData = getClassData(subClass);
-    _ClassData superClassData = getClassData(superClass);
+    _TFClassImpl subClassData = getTFClass(sub);
+    _TFClassImpl superClassData = getTFClass(sup);
 
     return subClassData.supertypes.contains(superClassData);
   }
 
   @override
-  Type specializeTypeCone(DartType base) {
+  Type specializeTypeCone(TFClass baseClass) {
     if (kPrintTrace) {
-      tracePrint("specializeTypeCone for $base");
+      tracePrint("specializeTypeCone for $baseClass");
     }
     Statistics.typeConeSpecializations++;
 
-    // TODO(alexmarkov): handle function types properly
-    if (base is FunctionType) {
-      base = _typeFlowAnalysis.environment.functionLegacyRawType;
-    }
-
-    if (base is TypeParameterType) {
-      base = (base as TypeParameterType).bound;
-    }
-
-    assertx(base is InterfaceType); // TODO(alexmarkov)
-    final baseClass = (base as InterfaceType).classNode;
-
-    // TODO(alexmarkov): take type arguments into account.
-
     // TODO(alexmarkov): consider approximating type if number of allocated
     // subtypes is too large
 
-    if (base == const DynamicType() ||
-        base == _typeFlowAnalysis.environment.coreTypes.objectLegacyRawType ||
-        // TODO(alexmarkov): handle FutureOr more precisely (requires generics).
-        baseClass == _typeFlowAnalysis.environment.futureOrClass) {
+    // TODO(alexmarkov): handle FutureOr more precisely.
+
+    if (baseClass.classNode == coreTypes.objectClass ||
+        baseClass.classNode == coreTypes.futureOrClass) {
       return const AnyType();
     }
 
-    _ClassData classData = getClassData(baseClass);
+    final _TFClassImpl cls = baseClass as _TFClassImpl;
 
     if (!_sealed) {
-      classData.addDependentInvocation(_typeFlowAnalysis.currentInvocation);
+      cls.dependencyTracker
+          .addDependentInvocation(_typeFlowAnalysis.currentInvocation);
     }
 
-    return classData.specializedConeType;
+    return cls.specializedConeType;
   }
 
-  bool hasNonTrivialNoSuchMethod(Class c) {
-    final classData = getClassData(c);
-    classData.hasNonTrivialNoSuchMethod ??=
-        (hierarchy.getDispatchTarget(c, noSuchMethodName) !=
+  bool hasNonTrivialNoSuchMethod(TFClass c) {
+    final classImpl = c as _TFClassImpl;
+    classImpl.hasNonTrivialNoSuchMethod ??=
+        (hierarchy.getDispatchTarget(c.classNode, noSuchMethodName) !=
             objectNoSuchMethod);
-    return classData.hasNonTrivialNoSuchMethod;
+    return classImpl.hasNonTrivialNoSuchMethod;
   }
 
   _DynamicTargetSet getDynamicTargetSet(DynamicSelector selector) {
@@ -1236,11 +1173,6 @@
     buf.write("}\n");
     return buf.toString();
   }
-
-  Class get futureOrClass => environment.coreTypes.futureOrClass;
-  Class get futureClass => environment.coreTypes.futureClass;
-  Class get functionClass => environment.coreTypes.functionClass;
-  CoreTypes get coreTypes => environment.coreTypes;
 }
 
 class _WorkList {
@@ -1353,8 +1285,8 @@
       }
       // Fall back to static type.
       Statistics.recursiveInvocationsApproximated++;
-      final staticType =
-          new Type.fromStatic(invocation.selector.staticReturnType);
+      final staticType = _typeFlowAnalysis.hierarchyCache
+          .fromStaticType(invocation.selector.staticReturnType, true);
       if (kPrintTrace) {
         tracePrint(
             "Approximated recursive invocation with static type $staticType");
@@ -1398,8 +1330,8 @@
     nativeCodeOracle = new NativeCodeOracle(libraryIndex, annotationMatcher);
     hierarchyCache = new _ClassHierarchyCache(
         this, hierarchy, _genericInterfacesInfo, environment);
-    summaryCollector = new SummaryCollector(
-        target, environment, hierarchy, this, nativeCodeOracle, hierarchyCache);
+    summaryCollector = new SummaryCollector(target, environment, hierarchy,
+        this, hierarchyCache, nativeCodeOracle, hierarchyCache);
     _invocationsCache = new _InvocationsCache(this);
     workList = new _WorkList(this);
 
@@ -1419,7 +1351,8 @@
       setterSummary = summaryCollector.createSummary(field,
           fieldSummaryType: FieldSummaryType.kFieldGuard);
     }
-    return _fieldValues[field] ??= new _FieldValue(field, setterSummary);
+    return _fieldValues[field] ??=
+        new _FieldValue(field, setterSummary, hierarchyCache);
   }
 
   void process() {
@@ -1528,8 +1461,7 @@
     if (field.isStatic) {
       fieldValue.setValue(value, this, /*receiver_type=*/ null);
     } else {
-      final receiver =
-          new Type.cone(new InterfaceType(field.parent, Nullability.legacy));
+      final receiver = new ConeType(hierarchyCache.getTFClass(field.parent));
       fieldValue.setValue(value, this, receiver);
     }
   }
diff --git a/pkg/vm/lib/transformations/type_flow/native_code.dart b/pkg/vm/lib/transformations/type_flow/native_code.dart
index 3f06a5d..c9093dd 100644
--- a/pkg/vm/lib/transformations/type_flow/native_code.dart
+++ b/pkg/vm/lib/transformations/type_flow/native_code.dart
@@ -191,8 +191,8 @@
 
   /// Simulate the execution of a native method by adding its entry points
   /// using [entryPointsListener]. Returns result type of the native method.
-  Type handleNativeProcedure(
-      Member member, EntryPointsListener entryPointsListener) {
+  Type handleNativeProcedure(Member member,
+      EntryPointsListener entryPointsListener, TypesBuilder typesBuilder) {
     Type returnType = null;
     bool nullable = null;
 
@@ -243,8 +243,8 @@
     if (returnType != null) {
       return returnType;
     } else {
-      final coneType = new Type.cone(member.function.returnType);
-      return nullable == false ? coneType : new Type.nullable(coneType);
+      return typesBuilder.fromStaticType(
+          member.function.returnType, nullable ?? true);
     }
   }
 }
diff --git a/pkg/vm/lib/transformations/type_flow/summary.dart b/pkg/vm/lib/transformations/type_flow/summary.dart
index efcf37f..9589729 100644
--- a/pkg/vm/lib/transformations/type_flow/summary.dart
+++ b/pkg/vm/lib/transformations/type_flow/summary.dart
@@ -317,7 +317,7 @@
         extractedType = const AnyType();
       } else {
         final interfaceOffset = typeHierarchy.genericInterfaceOffsetFor(
-            c.classNode, referenceClass);
+            c.cls.classNode, referenceClass);
         final extract = c.typeArgs[interfaceOffset + paramIndex];
         assertx(extract is AnyType || extract is RuntimeType);
         if (extractedType == null || extract == extractedType) {
@@ -345,10 +345,10 @@
 // The type arguments are factored against the generic interfaces; for more
 // details see 'ClassHierarchyCache.factoredGenericInterfacesOf'.
 class CreateConcreteType extends Statement {
-  final ConcreteType type;
+  final TFClass cls;
   final List<TypeExpr> flattenedTypeArgs;
 
-  CreateConcreteType(this.type, this.flattenedTypeArgs);
+  CreateConcreteType(this.cls, this.flattenedTypeArgs);
 
   @override
   void accept(StatementVisitor visitor) =>
@@ -356,8 +356,8 @@
 
   @override
   String dump() {
-    int numImmediateTypeArgs = type.classNode.typeParameters.length;
-    return "$label = _CreateConcreteType (${type.classNode} @ "
+    int numImmediateTypeArgs = cls.classNode.typeParameters.length;
+    return "$label = _CreateConcreteType ($cls @ "
         "${flattenedTypeArgs.take(numImmediateTypeArgs)})";
   }
 
@@ -372,8 +372,7 @@
       if (computed is RuntimeType) hasRuntimeType = true;
       types[i] = computed;
     }
-    return new ConcreteType(
-        type.classId, type.classNode, hasRuntimeType ? types : null);
+    return new ConcreteType(cls, hasRuntimeType ? types : null);
   }
 }
 
@@ -465,7 +464,8 @@
     } else if (checkType is RuntimeType) {
       canSkip = argType.isSubtypeOfRuntimeType(typeHierarchy, checkType);
       argType = argType.intersection(
-          Type.fromStatic(checkType.representedTypeRaw), typeHierarchy);
+          typeHierarchy.fromStaticType(checkType.representedTypeRaw, true),
+          typeHierarchy);
     } else {
       assertx(false, details: "Cannot see $checkType on RHS of TypeCheck.");
     }
diff --git a/pkg/vm/lib/transformations/type_flow/summary_collector.dart b/pkg/vm/lib/transformations/type_flow/summary_collector.dart
index 23902dc..3385c08 100644
--- a/pkg/vm/lib/transformations/type_flow/summary_collector.dart
+++ b/pkg/vm/lib/transformations/type_flow/summary_collector.dart
@@ -11,7 +11,8 @@
 import 'package:kernel/ast.dart' hide Statement, StatementVisitor;
 import 'package:kernel/ast.dart' as ast show Statement, StatementVisitor;
 import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
-import 'package:kernel/type_environment.dart' show TypeEnvironment;
+import 'package:kernel/type_environment.dart'
+    show StaticTypeContext, TypeEnvironment;
 import 'package:kernel/type_algebra.dart' show Substitution;
 
 import 'calls.dart';
@@ -32,11 +33,12 @@
 /// * Eliminates joins with a single input.
 class _SummaryNormalizer extends StatementVisitor {
   final Summary _summary;
+  final TypesBuilder _typesBuilder;
   Set<Statement> _processed = new Set<Statement>();
   Set<Statement> _pending = new Set<Statement>();
   bool _inLoop = false;
 
-  _SummaryNormalizer(this._summary);
+  _SummaryNormalizer(this._summary, this._typesBuilder);
 
   void normalize() {
     final List<Statement> statements = _summary.statements;
@@ -132,7 +134,7 @@
       _inLoop = false;
       debugPrint("Approximated ${st} with ${st.staticType}");
       Statistics.joinsApproximatedToBreakLoops++;
-      return new Type.fromStatic(st.staticType);
+      return _typesBuilder.fromStaticType(st.staticType, true);
     } else {
       // Step back until Join is found.
       _inLoop = true;
@@ -295,6 +297,7 @@
   final TypeEnvironment _environment;
   final ClassHierarchy _hierarchy;
   final EntryPointsListener _entryPointsListener;
+  final TypesBuilder _typesBuilder;
   final NativeCodeOracle _nativeCodeOracle;
   final GenericInterfacesInfo _genericInterfacesInfo;
 
@@ -310,6 +313,7 @@
   Parameter _receiver;
   ConstantAllocationCollector constantAllocationCollector;
   RuntimeTypeTranslator _translator;
+  StaticTypeContext _staticTypeContext;
 
   // Currently only used for factory constructors.
   Map<TypeParameter, TypeExpr> _fnTypeVariables;
@@ -319,6 +323,7 @@
       this._environment,
       this._hierarchy,
       this._entryPointsListener,
+      this._typesBuilder,
       this._nativeCodeOracle,
       this._genericInterfacesInfo) {
     assertx(_genericInterfacesInfo != null);
@@ -330,6 +335,7 @@
     debugPrint("===== ${member} =====");
     assertx(!member.isAbstract);
 
+    _staticTypeContext = new StaticTypeContext(member, _environment);
     _variableJoins = <VariableDeclaration, Join>{};
     _variables = <VariableDeclaration, TypeExpr>{};
     _returnValue = null;
@@ -347,7 +353,6 @@
         _receiver = _declareParameter("this",
             _environment.coreTypes.legacyRawType(member.enclosingClass), null,
             isReceiver: true);
-        _environment.thisType = member.enclosingClass?.thisType;
       } else {
         _summary = new Summary();
       }
@@ -361,8 +366,8 @@
       } else {
         Parameter valueParam = _declareParameter("value", member.type, null);
         TypeExpr runtimeType = _translator.translate(member.type);
-        final check = new TypeCheck(
-            valueParam, runtimeType, member, Type.fromStatic(member.type));
+        final check = new TypeCheck(valueParam, runtimeType, member,
+            _typesBuilder.fromStaticType(member.type, true));
         _summary.add(check);
         _summary.result = check;
       }
@@ -394,7 +399,6 @@
         _receiver = _declareParameter("this",
             _environment.coreTypes.legacyRawType(member.enclosingClass), null,
             isReceiver: true);
-        _environment.thisType = member.enclosingClass?.thisType;
       }
 
       _translator = new RuntimeTypeTranslator(
@@ -468,7 +472,7 @@
 
       if (function.body == null) {
         Type type = _nativeCodeOracle.handleNativeProcedure(
-            member, _entryPointsListener);
+            member, _entryPointsListener, _typesBuilder);
         if (type is! ConcreteType) {
           // Runtime type could be more precise than static type, so
           // calculate intersection.
@@ -488,14 +492,15 @@
       }
 
       _summary.result = _returnValue;
-      _environment.thisType = null;
     }
 
+    _staticTypeContext = null;
+
     debugPrint("------------ SUMMARY ------------");
     debugPrint(_summary);
     debugPrint("---------------------------------");
 
-    new _SummaryNormalizer(_summary).normalize();
+    new _SummaryNormalizer(_summary, _typesBuilder).normalize();
 
     debugPrint("---------- NORM SUMMARY ---------");
     debugPrint(_summary);
@@ -524,8 +529,8 @@
 
     if (hasReceiverArg(member)) {
       assertx(member.enclosingClass != null);
-      Type receiver = new Type.cone(
-          _environment.coreTypes.legacyRawType(member.enclosingClass));
+      final receiver =
+          new ConeType(_typesBuilder.getTFClass(member.enclosingClass));
       args.add(receiver);
     }
 
@@ -605,7 +610,7 @@
       {bool isReceiver: false}) {
     Type staticType;
     if (type != null) {
-      staticType = isReceiver ? new ConeType(type) : new Type.fromStatic(type);
+      staticType = _typesBuilder.fromStaticType(type, !isReceiver);
     }
     final param = new Parameter(name, staticType);
     _summary.add(param);
@@ -639,8 +644,8 @@
     TypeExpr variable = join;
     if (useTypeCheck) {
       TypeExpr runtimeType = _translator.translate(type);
-      variable = new TypeCheck(
-          variable, runtimeType, decl, Type.fromStatic(decl.type));
+      variable = new TypeCheck(variable, runtimeType, decl,
+          _typesBuilder.fromStaticType(decl.type, true));
       _summary.add(variable);
     }
 
@@ -659,7 +664,7 @@
   // TODO(alexmarkov): Avoid declaring variables with static types.
   void _declareVariableWithStaticType(VariableDeclaration decl) {
     Join v = _declareVariable(decl);
-    v.values.add(new Type.fromStatic(v.staticType));
+    v.values.add(_typesBuilder.fromStaticType(v.staticType, true));
   }
 
   Call _makeCall(TreeNode node, Selector selector, Args<TypeExpr> args) {
@@ -696,43 +701,41 @@
     }
   }
 
-  DartType _staticDartType(Expression node) {
-    // TODO(dartbug.com/34496): Remove this try/catch once
-    // getStaticType() is reliable.
-    try {
-      return node.getStaticType(_environment);
-    } catch (e) {
-      return const DynamicType();
-    }
-  }
+  DartType _staticDartType(Expression node) =>
+      node.getStaticType(_staticTypeContext);
 
   Type _staticType(Expression node) =>
-      new Type.fromStatic(_staticDartType(node));
+      _typesBuilder.fromStaticType(_staticDartType(node), true);
 
   Type _cachedBoolType;
   Type get _boolType => _cachedBoolType ??=
-      new Type.cone(_environment.coreTypes.boolLegacyRawType);
+      new ConeType(_typesBuilder.getTFClass(_environment.coreTypes.boolClass));
 
   Type _cachedDoubleType;
-  Type get _doubleType => _cachedDoubleType ??=
-      new Type.cone(_environment.coreTypes.doubleLegacyRawType);
+  Type get _doubleType => _cachedDoubleType ??= new ConeType(
+      _typesBuilder.getTFClass(_environment.coreTypes.doubleClass));
 
   Type _cachedIntType;
-  Type get _intType =>
-      _cachedIntType ??= new Type.cone(_environment.coreTypes.intLegacyRawType);
+  Type get _intType => _cachedIntType ??=
+      new ConeType(_typesBuilder.getTFClass(_environment.coreTypes.intClass));
 
   Type _cachedStringType;
-  Type get _stringType => _cachedStringType ??=
-      new Type.cone(_environment.coreTypes.stringLegacyRawType);
+  Type get _stringType => _cachedStringType ??= new ConeType(
+      _typesBuilder.getTFClass(_environment.coreTypes.stringClass));
 
   Type _cachedSymbolType;
-  Type get _symbolType => _cachedSymbolType ??=
-      new Type.cone(_environment.coreTypes.symbolLegacyRawType);
+  Type get _symbolType => _cachedSymbolType ??= new ConeType(
+      _typesBuilder.getTFClass(_environment.coreTypes.symbolClass));
+
+  Type _cachedTypeType;
+  Type get _typeType => _cachedTypeType ??=
+      new ConeType(_typesBuilder.getTFClass(_environment.coreTypes.typeClass));
 
   Type _cachedNullType;
-  Type get _nullType => _cachedNullType ??= new Type.nullable(new Type.empty());
+  Type get _nullType =>
+      _cachedNullType ??= new Type.nullable(const EmptyType());
 
-  Class get _superclass => _environment.thisType.classNode.superclass;
+  Class get _superclass => _staticTypeContext.thisType.classNode.superclass;
 
   Type _intLiteralType(int value) {
     Class concreteClass =
@@ -779,7 +782,7 @@
   @override
   TypeExpr visitAsExpression(AsExpression node) {
     TypeExpr operand = _visit(node.operand);
-    Type type = new Type.fromStatic(node.type);
+    Type type = _typesBuilder.fromStaticType(node.type, true);
     TypeExpr runtimeType = _translator.translate(node.type);
     TypeExpr result = new TypeCheck(operand, runtimeType, node, type);
     explicitCasts[node] = result;
@@ -888,7 +891,7 @@
 
   @override
   TypeExpr visitInvalidExpression(InvalidExpression node) {
-    return new Type.empty();
+    return const EmptyType();
   }
 
   @override
@@ -1009,7 +1012,7 @@
     }
     switch (elementTypes.length) {
       case 0:
-        return new Type.empty();
+        return const EmptyType();
       case 1:
         return elementTypes.single;
       default:
@@ -1066,7 +1069,7 @@
     // Re-resolve target due to partial mixin resolution.
     final target = _hierarchy.getDispatchTarget(_superclass, node.name);
     if (target == null) {
-      return new Type.empty();
+      return const EmptyType();
     } else {
       if ((target is Field) || ((target is Procedure) && target.isGetter)) {
         // Call via field/getter.
@@ -1094,7 +1097,7 @@
     // Re-resolve target due to partial mixin resolution.
     final target = _hierarchy.getDispatchTarget(_superclass, node.name);
     if (target == null) {
-      return new Type.empty();
+      return const EmptyType();
     } else {
       return _makeCall(node,
           new DirectSelector(target, callKind: CallKind.PropertyGet), args);
@@ -1132,7 +1135,7 @@
 
   @override
   TypeExpr visitRethrow(Rethrow node) {
-    return new Type.empty();
+    return const EmptyType();
   }
 
   @override
@@ -1188,12 +1191,12 @@
   @override
   TypeExpr visitThrow(Throw node) {
     _visit(node.expression);
-    return new Type.empty();
+    return const EmptyType();
   }
 
   @override
   TypeExpr visitTypeLiteral(TypeLiteral node) {
-    return new Type.cone(_environment.coreTypes.typeLegacyRawType);
+    return _typeType;
   }
 
   @override
@@ -1205,7 +1208,8 @@
 
     if ((node.promotedType != null) &&
         (node.promotedType != const DynamicType())) {
-      return _makeNarrow(v, new Type.cone(node.promotedType));
+      return _makeNarrow(
+          v, _typesBuilder.fromStaticType(node.promotedType, false));
     }
 
     return v;
@@ -1303,7 +1307,7 @@
     Join v = _declareVariable(node.variable);
     // TODO(alexmarkov): support function types.
     // v.values.add(_concreteType(node.function.functionType));
-    v.values.add(new Type.fromStatic(v.staticType));
+    v.values.add(_typesBuilder.fromStaticType(v.staticType, true));
     _handleNestedFunctionNode(node.function);
     return null;
   }
@@ -1472,7 +1476,7 @@
 
     // This function is very similar to 'visitInterfaceType', but with
     // many small differences.
-    final klass = type.classNode;
+    final klass = type.cls.classNode;
     final substitution = Substitution.fromPairs(klass.typeParameters, typeArgs);
     final flattenedTypeArgs =
         genericInterfacesInfo.flattenedTypeArgumentsFor(klass);
@@ -1491,10 +1495,10 @@
     if (allAnyType) return type;
 
     if (createConcreteType) {
-      return new ConcreteType(type.classId, type.classNode,
-          new List<Type>.from(flattenedTypeExprs));
+      return new ConcreteType(
+          type.cls, new List<Type>.from(flattenedTypeExprs));
     } else {
-      final instantiate = new CreateConcreteType(type, flattenedTypeExprs);
+      final instantiate = new CreateConcreteType(type.cls, flattenedTypeExprs);
       summary.add(instantiate);
       return instantiate;
     }
@@ -1532,6 +1536,8 @@
   TypeExpr visitVoidType(VoidType type) => new RuntimeType(type, null);
   @override
   TypeExpr visitBottomType(BottomType type) => new RuntimeType(type, null);
+  @override
+  TypeExpr visitNeverType(NeverType type) => new RuntimeType(type, null);
 
   @override
   visitTypedefType(TypedefType node) => translate(node.unalias);
@@ -1583,50 +1589,6 @@
   }
 }
 
-class EmptyEntryPointsListener implements EntryPointsListener {
-  final Map<Class, IntClassId> _classIds = <Class, IntClassId>{};
-  int _classIdCounter = 0;
-
-  @override
-  void addRawCall(Selector selector) {}
-
-  @override
-  void addDirectFieldAccess(Field field, Type value) {}
-
-  @override
-  ConcreteType addAllocatedClass(Class c) {
-    final classId = (_classIds[c] ??= new IntClassId(++_classIdCounter));
-    return new ConcreteType(classId, c, null);
-  }
-
-  @override
-  void recordMemberCalledViaInterfaceSelector(Member target) {}
-
-  @override
-  void recordMemberCalledViaThis(Member target) {}
-}
-
-class CreateAllSummariesVisitor extends RecursiveVisitor<Null> {
-  final SummaryCollector _summaryCollector;
-
-  CreateAllSummariesVisitor(Target target, TypeEnvironment environment,
-      ClassHierarchy hierarchy, GenericInterfacesInfo genericInterfacesInfo)
-      : _summaryCollector = new SummaryCollector(
-            target,
-            environment,
-            hierarchy,
-            new EmptyEntryPointsListener(),
-            new NativeCodeOracle(null, null),
-            genericInterfacesInfo);
-
-  @override
-  defaultMember(Member m) {
-    if (!m.isAbstract && !(m is Field && m.initializer == null)) {
-      _summaryCollector.createSummary(m);
-    }
-  }
-}
-
 class ConstantAllocationCollector extends ConstantVisitor<Type> {
   final SummaryCollector summaryCollector;
 
@@ -1640,6 +1602,10 @@
     return constants.putIfAbsent(constant, () => constant.accept(this));
   }
 
+  Type _getStaticType(Constant constant) =>
+      summaryCollector._typesBuilder.fromStaticType(
+          constant.getType(summaryCollector._staticTypeContext), false);
+
   @override
   defaultConstant(Constant constant) {
     throw 'There is no support for constant "$constant" in TFA yet!';
@@ -1689,7 +1655,7 @@
         .concreteConstListLiteralClass(summaryCollector._environment.coreTypes);
     return concreteClass != null
         ? summaryCollector._entryPointsListener.addAllocatedClass(concreteClass)
-        : new Type.cone(constant.getType(summaryCollector._environment));
+        : _getStaticType(constant);
   }
 
   @override
@@ -1708,18 +1674,18 @@
     final Procedure procedure = constant.procedure;
     summaryCollector._entryPointsListener
         .addRawCall(new DirectSelector(procedure));
-    return new Type.cone(constant.getType(summaryCollector._environment));
+    return _getStaticType(constant);
   }
 
   @override
   Type visitPartialInstantiationConstant(
       PartialInstantiationConstant constant) {
     constant.tearOffConstant.accept(this);
-    return new Type.cone(constant.getType(summaryCollector._environment));
+    return _getStaticType(constant);
   }
 
   @override
   Type visitTypeLiteralConstant(TypeLiteralConstant constant) {
-    return new Type.cone(constant.getType(summaryCollector._environment));
+    return summaryCollector._typeType;
   }
 }
diff --git a/pkg/vm/lib/transformations/type_flow/transformer.dart b/pkg/vm/lib/transformations/type_flow/transformer.dart
index bde9684..a6289ea 100644
--- a/pkg/vm/lib/transformations/type_flow/transformer.dart
+++ b/pkg/vm/lib/transformations/type_flow/transformer.dart
@@ -17,7 +17,6 @@
 import 'analysis.dart';
 import 'calls.dart';
 import 'summary.dart';
-import 'summary_collector.dart';
 import 'types.dart';
 import 'utils.dart';
 import '../pragma.dart';
@@ -27,8 +26,6 @@
 import '../../metadata/procedure_attributes.dart';
 import '../../metadata/unreachable.dart';
 
-const bool kDumpAllSummaries =
-    const bool.fromEnvironment('global.type.flow.dump.all.summaries');
 const bool kDumpClassHierarchy =
     const bool.fromEnvironment('global.type.flow.dump.class.hierarchy');
 
@@ -44,14 +41,6 @@
   final libraryIndex = new LibraryIndex.all(component);
   final genericInterfacesInfo = new GenericInterfacesInfoImpl(hierarchy);
 
-  if (kDumpAllSummaries) {
-    Statistics.reset();
-    new CreateAllSummariesVisitor(
-            target, types, hierarchy, genericInterfacesInfo)
-        .visitComponent(component);
-    Statistics.print("All summaries statistics");
-  }
-
   Statistics.reset();
   final analysisStopWatch = new Stopwatch()..start();
 
@@ -123,14 +112,14 @@
   final InferredTypeMetadataRepository _inferredTypeMetadata;
   final UnreachableNodeMetadataRepository _unreachableNodeMetadata;
   final ProcedureAttributesMetadataRepository _procedureAttributesMetadata;
-  final DartType _intType;
+  final Class _intClass;
 
   AnnotateKernel(Component component, this._typeFlowAnalysis)
       : _inferredTypeMetadata = new InferredTypeMetadataRepository(),
         _unreachableNodeMetadata = new UnreachableNodeMetadataRepository(),
         _procedureAttributesMetadata =
             new ProcedureAttributesMetadataRepository(),
-        _intType = _typeFlowAnalysis.environment.coreTypes.intLegacyRawType {
+        _intClass = _typeFlowAnalysis.environment.coreTypes.intClass {
     component.addMetadataRepository(_inferredTypeMetadata);
     component.addMetadataRepository(_unreachableNodeMetadata);
     component.addMetadataRepository(_procedureAttributesMetadata);
@@ -153,7 +142,7 @@
       concreteClass = type.getConcreteClass(_typeFlowAnalysis.hierarchyCache);
 
       if (concreteClass == null) {
-        isInt = type.isSubtypeOf(_typeFlowAnalysis.hierarchyCache, _intType);
+        isInt = type.isSubtypeOf(_typeFlowAnalysis.hierarchyCache, _intClass);
       }
     }
 
@@ -653,7 +642,7 @@
         if (shaker.isFieldInitializerReachable(node)) {
           node.transformChildren(this);
         } else {
-          node.initializer = _makeUnreachableCall([]);
+          node.initializer = _makeUnreachableCall([])..parent = node;
         }
       }
     } else if (shaker.isMemberReferencedFromNativeCode(node)) {
diff --git a/pkg/vm/lib/transformations/type_flow/types.dart b/pkg/vm/lib/transformations/type_flow/types.dart
index 4f5bf7b..35ec3c5 100644
--- a/pkg/vm/lib/transformations/type_flow/types.dart
+++ b/pkg/vm/lib/transformations/type_flow/types.dart
@@ -13,6 +13,28 @@
 
 import 'utils.dart';
 
+/// Dart class representation used in type flow analysis.
+/// For each Dart class there is a unique instance of [TFClass].
+/// Each [TFClass] has unique id which could be used to sort classes.
+class TFClass {
+  final int id;
+  final Class classNode;
+
+  /// TFClass should not be instantiated directly.
+  /// Instead, [TypeHierarchy.getTFClass] should be used to obtain [TFClass]
+  /// instances specific to given [TypeHierarchy].
+  TFClass(this.id, this.classNode);
+
+  @override
+  int get hashCode => id;
+
+  @override
+  bool operator ==(other) => identical(this, other);
+
+  @override
+  String toString() => classNode.toString();
+}
+
 abstract class GenericInterfacesInfo {
   // Return a type arguments vector which contains the immediate type parameters
   // to 'klass' as well as the type arguments to all generic supertypes of
@@ -36,47 +58,61 @@
   List<Type> flattenedTypeArgumentsForNonGeneric(Class klass);
 }
 
+abstract class TypesBuilder {
+  final CoreTypes coreTypes;
+
+  TypesBuilder(this.coreTypes);
+
+  /// Return [TFClass] corresponding to the given [classNode].
+  TFClass getTFClass(Class classNode);
+
+  /// Create a Type which corresponds to a set of instances constrained by
+  /// Dart type annotation [dartType].
+  Type fromStaticType(DartType type, bool isNullable) {
+    Type result;
+    if (type is InterfaceType) {
+      final cls = type.classNode;
+      result = (cls == coreTypes.nullClass)
+          ? const EmptyType()
+          : new ConeType(getTFClass(cls));
+    } else if (type == const DynamicType() || type == const VoidType()) {
+      result = const AnyType();
+    } else if (type == const BottomType() || type is NeverType) {
+      result = const EmptyType();
+    } else if (type is FunctionType) {
+      // TODO(alexmarkov): support function types
+      result = const AnyType();
+    } else if (type is TypeParameterType) {
+      final bound = type.bound;
+      // Protect against infinite recursion in case of cyclic type parameters
+      // like 'T extends T'. As of today, front-end doesn't report errors in such
+      // cases yet.
+      if (bound is TypeParameterType) {
+        result = const AnyType();
+      } else {
+        return fromStaticType(bound, isNullable);
+      }
+    } else {
+      throw 'Unexpected type ${type.runtimeType} $type';
+    }
+    if (isNullable) {
+      result = new Type.nullable(result);
+    }
+    return result;
+  }
+}
+
 /// Abstract interface to type hierarchy information used by types.
-abstract class TypeHierarchy implements GenericInterfacesInfo {
-  /// Test if [subType] is a subtype of [superType].
-  bool isSubtype(DartType subType, DartType superType);
+abstract class TypeHierarchy extends TypesBuilder
+    implements GenericInterfacesInfo {
+  TypeHierarchy(CoreTypes coreTypes) : super(coreTypes);
+
+  /// Test if [sub] is a subtype of [sup].
+  bool isSubtype(Class sub, Class sup);
 
   /// Return a more specific type for the type cone with [base] root.
   /// May return EmptyType, AnyType, ConcreteType or a SetType.
-  Type specializeTypeCone(DartType base);
-
-  Class get futureOrClass;
-  Class get futureClass;
-  Class get functionClass;
-  CoreTypes get coreTypes;
-}
-
-/// Basic normalization of Dart types.
-/// Currently used to approximate generic and function types.
-DartType _normalizeDartType(DartType type) {
-  if (type is InterfaceType) {
-    // TODO(alexmarkov): take generic type arguments into account
-    // TODO(alexmarkov): cache the created raw type or use a CoreTypes object
-    return new InterfaceType(
-        type.classNode,
-        Nullability.legacy,
-        new List<DartType>.filled(
-            type.classNode.typeParameters.length, const DynamicType()));
-  } else if (type is FunctionType) {
-    // TODO(alexmarkov): support function types
-    return const DynamicType();
-  } else if (type is TypeParameterType) {
-    // TODO(alexmarkov): instantiate type parameters if possible
-    final bound = type.bound;
-    // Protect against infinite recursion in case of cyclic type parameters
-    // like 'T extends T'. As of today, front-end doesn't report errors in such
-    // cases yet.
-    if (bound is TypeParameterType) {
-      return const DynamicType();
-    }
-    return _normalizeDartType(bound);
-  }
-  return type;
+  Type specializeTypeCone(TFClass base);
 }
 
 /// Base class for type expressions.
@@ -96,54 +132,15 @@
 abstract class Type extends TypeExpr {
   const Type();
 
-  /// Create an empty type.
-  factory Type.empty() => const EmptyType();
-
-  /// Create a non-nullable type representing a subtype cone. It contains
-  /// instances of all Dart types which extend, mix-in or implement [dartType].
-  factory Type.cone(DartType dartType) {
-    dartType = _normalizeDartType(dartType);
-    if ((dartType == const DynamicType()) || (dartType == const VoidType())) {
-      return const AnyType();
-    } else if (dartType == const BottomType()) {
-      return new Type.empty();
-    } else {
-      return new ConeType(dartType);
-    }
-  }
-
   /// Create a nullable type - union of [t] and the `null` object.
   factory Type.nullable(Type t) => new NullableType(t);
 
   /// Create a type representing arbitrary nullable object (`dynamic`).
   factory Type.nullableAny() => new NullableType(const AnyType());
 
-  /// Create a Type which corresponds to a set of instances constrained by
-  /// Dart type annotation [dartType].
-  factory Type.fromStatic(DartType dartType) {
-    dartType = _normalizeDartType(dartType);
-    if ((dartType == const DynamicType()) || (dartType == const VoidType())) {
-      return new Type.nullableAny();
-    } else if (dartType == const BottomType()) {
-      return new Type.nullable(new Type.empty());
-    } else if (
-        // Recognize Null type and use a more precise representation which
-        // doesn't need type specialization.
-        // TODO(alexmarkov): figure out where exactly approximation happens if
-        // Null is represented as Nullable(Cone(Null)) instead of
-        // Nullable(Empty).
-        dartType is InterfaceType &&
-            dartType.classNode.name == 'Null' &&
-            dartType.classNode.enclosingLibrary.importUri.scheme == 'dart' &&
-            dartType.classNode.enclosingLibrary.importUri.path == 'core') {
-      return new Type.nullable(new Type.empty());
-    }
-    return new Type.nullable(new ConeType(dartType));
-  }
-
   Class getConcreteClass(TypeHierarchy typeHierarchy) => null;
 
-  bool isSubtypeOf(TypeHierarchy typeHierarchy, DartType dartType) => false;
+  bool isSubtypeOf(TypeHierarchy typeHierarchy, Class cls) => false;
 
   // Returns 'true' if this type will definitely pass a runtime type-check
   // against 'runtimeType'. Returns 'false' if the test might fail (e.g. due to
@@ -230,8 +227,8 @@
   String toString() => "${baseType}?";
 
   @override
-  bool isSubtypeOf(TypeHierarchy typeHierarchy, DartType dartType) =>
-      baseType.isSubtypeOf(typeHierarchy, dartType);
+  bool isSubtypeOf(TypeHierarchy typeHierarchy, Class cls) =>
+      baseType.isSubtypeOf(typeHierarchy, cls);
 
   bool isSubtypeOfRuntimeType(TypeHierarchy typeHierarchy, RuntimeType other) =>
       baseType.isSubtypeOfRuntimeType(typeHierarchy, other);
@@ -308,7 +305,11 @@
   }
 
   bool isSubtypeOfRuntimeType(TypeHierarchy typeHierarchy, RuntimeType other) {
-    return typeHierarchy.isSubtype(const DynamicType(), other._type);
+    final rhs = other._type;
+    return (rhs is DynamicType) ||
+        (rhs is VoidType) ||
+        (rhs is InterfaceType &&
+            rhs.classNode == typeHierarchy.coreTypes.objectClass);
   }
 }
 
@@ -354,8 +355,8 @@
   String toString() => "_T ${types}";
 
   @override
-  bool isSubtypeOf(TypeHierarchy typeHierarchy, DartType dartType) =>
-      types.every((ConcreteType t) => t.isSubtypeOf(typeHierarchy, dartType));
+  bool isSubtypeOf(TypeHierarchy typeHierarchy, Class cls) =>
+      types.every((ConcreteType t) => t.isSubtypeOf(typeHierarchy, cls));
 
   bool isSubtypeOfRuntimeType(TypeHierarchy typeHierarchy, RuntimeType other) =>
       types.every((t) => t.isSubtypeOfRuntimeType(typeHierarchy, other));
@@ -371,11 +372,12 @@
     while ((i1 < types1.length) && (i2 < types2.length)) {
       final t1 = types1[i1];
       final t2 = types2[i2];
-      final relation = t1.classId.compareTo(t2.classId);
-      if (relation < 0) {
+      final id1 = t1.cls.id;
+      final id2 = t2.cls.id;
+      if (id1 < id2) {
         types.add(t1);
         ++i1;
-      } else if (relation > 0) {
+      } else if (id1 > id2) {
         types.add(t2);
         ++i2;
       } else {
@@ -406,10 +408,11 @@
     while ((i1 < types1.length) && (i2 < types2.length)) {
       final t1 = types1[i1];
       final t2 = types2[i2];
-      final relation = t1.classId.compareTo(t2.classId);
-      if (relation < 0) {
+      final id1 = t1.cls.id;
+      final id2 = t2.cls.id;
+      if (id1 < id2) {
         ++i1;
-      } else if (relation > 0) {
+      } else if (id1 > id2) {
         ++i2;
       } else {
         if (t1.typeArgs == null && t2.typeArgs == null) {
@@ -440,7 +443,7 @@
           : new SetType(_unionLists(types, <ConcreteType>[other]));
     } else if (other is ConeType) {
       return typeHierarchy
-          .specializeTypeCone(other.dartType)
+          .specializeTypeCone(other.cls)
           .union(this, typeHierarchy);
     } else {
       throw 'Unexpected type $other';
@@ -465,14 +468,14 @@
     } else if (other is ConcreteType) {
       for (var type in types) {
         if (type == other) return other;
-        if (type.classId == other.classId) {
+        if (identical(type.cls, other.cls)) {
           return type.intersection(other, typeHierarchy);
         }
       }
       return EmptyType();
     } else if (other is ConeType) {
       return typeHierarchy
-          .specializeTypeCone(other.dartType)
+          .specializeTypeCone(other.cls)
           .intersection(this, typeHierarchy);
     } else {
       throw 'Unexpected type $other';
@@ -481,42 +484,41 @@
 }
 
 /// Type representing a subtype cone. It contains instances of all
-/// Dart types which extend, mix-in or implement [dartType].
+/// Dart types which extend, mix-in or implement certain class.
 /// TODO(alexmarkov): Introduce cones of types which extend but not implement.
 class ConeType extends Type {
-  final DartType dartType;
+  final TFClass cls;
 
-  ConeType(this.dartType) {
-    assertx(dartType != null);
-  }
+  ConeType(this.cls);
 
   @override
-  Class getConcreteClass(TypeHierarchy typeHierarchy) => typeHierarchy
-      .specializeTypeCone(dartType)
-      .getConcreteClass(typeHierarchy);
+  Class getConcreteClass(TypeHierarchy typeHierarchy) =>
+      typeHierarchy.specializeTypeCone(cls).getConcreteClass(typeHierarchy);
 
   @override
-  bool isSubtypeOf(TypeHierarchy typeHierarchy, DartType dartType) =>
-      typeHierarchy.isSubtype(this.dartType, dartType);
+  bool isSubtypeOf(TypeHierarchy typeHierarchy, Class cls) =>
+      typeHierarchy.isSubtype(this.cls.classNode, cls);
 
   bool isSubtypeOfRuntimeType(TypeHierarchy typeHierarchy, RuntimeType other) {
-    if (!typeHierarchy.isSubtype(dartType, other._type)) return false;
-    if (dartType is InterfaceType) {
-      return (dartType as InterfaceType).classNode.typeParameters.isEmpty;
+    final rhs = other._type;
+    if (rhs is DynamicType || rhs is VoidType) return true;
+    if (rhs is InterfaceType) {
+      return cls.classNode.typeParameters.isEmpty &&
+          typeHierarchy.isSubtype(cls.classNode, rhs.classNode);
     }
-    return true;
+    return false;
   }
 
   @override
-  int get hashCode => (dartType.hashCode + 37) & kHashMask;
+  int get hashCode => (cls.id + 37) & kHashMask;
 
   @override
   bool operator ==(other) =>
       identical(this, other) ||
-      (other is ConeType) && (this.dartType == other.dartType);
+      (other is ConeType) && identical(this.cls, other.cls);
 
   @override
-  String toString() => "_T (${dartType})+";
+  String toString() => "_T ($cls)+";
 
   @override
   int get order => TypeOrder.Cone.index;
@@ -526,7 +528,7 @@
 
   @override
   Type specialize(TypeHierarchy typeHierarchy) =>
-      typeHierarchy.specializeTypeCone(dartType);
+      typeHierarchy.specializeTypeCone(cls);
 
   @override
   Type union(Type other, TypeHierarchy typeHierarchy) {
@@ -537,22 +539,18 @@
       if (this == other) {
         return this;
       }
-      if (typeHierarchy.isSubtype(other.dartType, this.dartType)) {
+      if (typeHierarchy.isSubtype(other.cls.classNode, this.cls.classNode)) {
         return this;
       }
-      if (typeHierarchy.isSubtype(this.dartType, other.dartType)) {
+      if (typeHierarchy.isSubtype(this.cls.classNode, other.cls.classNode)) {
         return other;
       }
     } else if (other is ConcreteType) {
-      if (typeHierarchy.isSubtype(
-          typeHierarchy.coreTypes.legacyRawType(other.classNode),
-          this.dartType)) {
+      if (typeHierarchy.isSubtype(other.cls.classNode, this.cls.classNode)) {
         return this;
       }
     }
-    return typeHierarchy
-        .specializeTypeCone(dartType)
-        .union(other, typeHierarchy);
+    return typeHierarchy.specializeTypeCone(cls).union(other, typeHierarchy);
   }
 
   @override
@@ -564,48 +562,29 @@
       if (this == other) {
         return this;
       }
-      if (typeHierarchy.isSubtype(other.dartType, this.dartType)) {
+      if (typeHierarchy.isSubtype(other.cls.classNode, this.cls.classNode)) {
         return other;
       }
-      if (typeHierarchy.isSubtype(this.dartType, other.dartType)) {
+      if (typeHierarchy.isSubtype(this.cls.classNode, other.cls.classNode)) {
         return this;
       }
     } else if (other is ConcreteType) {
-      if (typeHierarchy.isSubtype(
-          typeHierarchy.coreTypes.legacyRawType(other.classNode),
-          this.dartType)) {
+      if (typeHierarchy.isSubtype(other.cls.classNode, this.cls.classNode)) {
         return other;
       } else {
         return const EmptyType();
       }
     }
     return typeHierarchy
-        .specializeTypeCone(dartType)
+        .specializeTypeCone(cls)
         .intersection(other, typeHierarchy);
   }
 }
 
-/// Abstract unique identifier of a Dart class.
-/// Identifiers are comparable and used to provide ordering on classes.
-abstract class ClassId<E extends ClassId<E>> implements Comparable<E> {
-  const ClassId();
-}
-
-/// Simple implementation of [ClassId] based on int.
-class IntClassId extends ClassId<IntClassId> {
-  final int id;
-
-  const IntClassId(this.id);
-
-  @override
-  int compareTo(IntClassId other) => id.compareTo(other.id);
-}
-
 /// Type representing a set of instances of a specific Dart class (no subtypes
 /// or `null` object).
 class ConcreteType extends Type implements Comparable<ConcreteType> {
-  final ClassId classId;
-  final Class classNode;
+  final TFClass cls;
   int _hashCode;
 
   // May be null if there are no type arguments constraints. The type arguments
@@ -621,52 +600,46 @@
   final int numImmediateTypeArgs;
   final List<Type> typeArgs;
 
-  ConcreteType(this.classId, this.classNode, [List<Type> typeArgs_])
+  ConcreteType(this.cls, [List<Type> typeArgs_])
       : typeArgs = typeArgs_,
         numImmediateTypeArgs =
-            typeArgs_ != null ? classNode.typeParameters.length : 0 {
+            typeArgs_ != null ? cls.classNode.typeParameters.length : 0 {
     // TODO(alexmarkov): support closures
-    assertx(!classNode.isAbstract);
-    assertx(typeArgs == null || classNode.typeParameters.isNotEmpty);
+    assertx(!cls.classNode.isAbstract);
+    assertx(typeArgs == null || cls.classNode.typeParameters.isNotEmpty);
     assertx(typeArgs == null || typeArgs.any((t) => t is RuntimeType));
   }
 
-  ConcreteType get raw => new ConcreteType(classId, classNode, null);
+  ConcreteType get raw => new ConcreteType(cls, null);
 
   @override
-  Class getConcreteClass(TypeHierarchy typeHierarchy) => classNode;
+  Class getConcreteClass(TypeHierarchy typeHierarchy) => cls.classNode;
 
   @override
-  bool isSubtypeOf(TypeHierarchy typeHierarchy, DartType dartType) =>
-      typeHierarchy.isSubtype(
-          typeHierarchy.coreTypes.legacyRawType(classNode), dartType);
+  bool isSubtypeOf(TypeHierarchy typeHierarchy, Class other) =>
+      typeHierarchy.isSubtype(cls.classNode, other);
 
   bool isSubtypeOfRuntimeType(
       TypeHierarchy typeHierarchy, RuntimeType runtimeType) {
-    if (runtimeType._type is InterfaceType &&
-        (runtimeType._type as InterfaceType).classNode ==
-            typeHierarchy.functionClass) {
-      // TODO(35573): "implements/extends Function" is not handled correctly by
-      // the CFE. By returning "false" we force an approximation -- that a type
-      // check against "Function" might fail, whatever the LHS is.
-      return false;
-    }
+    final rhs = runtimeType._type;
+    if (rhs is DynamicType || rhs is VoidType) return true;
+    if (rhs is InterfaceType) {
+      if (rhs.classNode == typeHierarchy.coreTypes.functionClass) {
+        // TODO(35573): "implements/extends Function" is not handled correctly by
+        // the CFE. By returning "false" we force an approximation -- that a type
+        // check against "Function" might fail, whatever the LHS is.
+        return false;
+      }
 
-    if (!typeHierarchy.isSubtype(
-        typeHierarchy.coreTypes.legacyRawType(this.classNode),
-        runtimeType._type)) {
-      return false;
-    }
+      if (!typeHierarchy.isSubtype(this.cls.classNode, rhs.classNode)) {
+        return false;
+      }
 
-    InterfaceType runtimeDartType;
-    if (runtimeType._type is InterfaceType) {
-      runtimeDartType = runtimeType._type;
-      if (runtimeDartType.typeArguments.isEmpty) return true;
-      if (runtimeDartType.classNode == typeHierarchy.futureOrClass) {
+      if (rhs.typeArguments.isEmpty) return true;
+      if (rhs.classNode == typeHierarchy.coreTypes.futureOrClass) {
         if (typeHierarchy.isSubtype(
-                typeHierarchy.coreTypes.legacyRawType(classNode),
-                typeHierarchy.coreTypes.futureLegacyRawType) ||
-            classNode == typeHierarchy.futureOrClass) {
+                cls.classNode, typeHierarchy.coreTypes.futureClass) ||
+            cls.classNode == typeHierarchy.coreTypes.futureOrClass) {
           final RuntimeType lhs =
               typeArgs == null ? RuntimeType(DynamicType(), null) : typeArgs[0];
           return lhs.isSubtypeOfRuntimeType(
@@ -675,44 +648,42 @@
           return isSubtypeOfRuntimeType(typeHierarchy, runtimeType.typeArgs[0]);
         }
       }
-    } else {
-      // The TypeHierarchy result may be inaccurate only if there are type
-      // arguments which it doesn't examine.
+
+      List<Type> usableTypeArgs = typeArgs;
+      if (usableTypeArgs == null) {
+        if (cls.classNode.typeParameters.isEmpty) {
+          usableTypeArgs =
+              typeHierarchy.flattenedTypeArgumentsForNonGeneric(cls.classNode);
+        } else {
+          return false;
+        }
+      }
+
+      final interfaceOffset =
+          typeHierarchy.genericInterfaceOffsetFor(cls.classNode, rhs.classNode);
+
+      assertx(usableTypeArgs.length - interfaceOffset >=
+          runtimeType.numImmediateTypeArgs);
+
+      for (int i = 0; i < runtimeType.numImmediateTypeArgs; ++i) {
+        if (usableTypeArgs[i + interfaceOffset] == const AnyType())
+          return false;
+        assertx(usableTypeArgs[i + interfaceOffset] is RuntimeType);
+        if (!usableTypeArgs[i + interfaceOffset]
+            .isSubtypeOfRuntimeType(typeHierarchy, runtimeType.typeArgs[i])) {
+          return false;
+        }
+      }
       return true;
     }
-
-    List<Type> usableTypeArgs = typeArgs;
-    if (usableTypeArgs == null) {
-      if (classNode.typeParameters.isEmpty) {
-        usableTypeArgs =
-            typeHierarchy.flattenedTypeArgumentsForNonGeneric(classNode);
-      } else {
-        return false;
-      }
-    }
-
-    final interfaceOffset = typeHierarchy.genericInterfaceOffsetFor(
-        classNode, runtimeDartType.classNode);
-
-    assertx(usableTypeArgs.length - interfaceOffset >=
-        runtimeType.numImmediateTypeArgs);
-
-    for (int i = 0; i < runtimeType.numImmediateTypeArgs; ++i) {
-      if (usableTypeArgs[i + interfaceOffset] == const AnyType()) return false;
-      assertx(usableTypeArgs[i + interfaceOffset] is RuntimeType);
-      if (!usableTypeArgs[i + interfaceOffset]
-          .isSubtypeOfRuntimeType(typeHierarchy, runtimeType.typeArgs[i])) {
-        return false;
-      }
-    }
-    return true;
+    return false;
   }
 
   @override
   int get hashCode => _hashCode ??= _computeHashCode();
 
   int _computeHashCode() {
-    int hash = classId.hashCode ^ 0x1234 & kHashMask;
+    int hash = cls.hashCode ^ 0x1234 & kHashMask;
     // We only need to hash the first type arguments vector, since the type
     // arguments of the implemented interfaces are implied by it.
     for (int i = 0; i < numImmediateTypeArgs; ++i) {
@@ -725,7 +696,7 @@
   bool operator ==(other) {
     if (identical(this, other)) return true;
     if (other is ConcreteType) {
-      if (this.classId != other.classId ||
+      if (!identical(this.cls, other.cls) ||
           this.numImmediateTypeArgs != other.numImmediateTypeArgs) {
         return false;
       }
@@ -745,12 +716,12 @@
   // Note that this may return 0 for concrete types which are not equal if the
   // difference is only in type arguments.
   @override
-  int compareTo(ConcreteType other) => classId.compareTo(other.classId);
+  int compareTo(ConcreteType other) => cls.id.compareTo(other.cls.id);
 
   @override
   String toString() => typeArgs == null
-      ? "_T (${classNode})"
-      : "_T (${classNode}<${typeArgs.take(numImmediateTypeArgs).join(', ')}>)";
+      ? "_T (${cls})"
+      : "_T (${cls}<${typeArgs.take(numImmediateTypeArgs).join(', ')}>)";
 
   @override
   int get order => TypeOrder.Concrete.index;
@@ -763,8 +734,8 @@
     if (other is ConcreteType) {
       if (this == other) {
         return this;
-      } else if (this.classId != other.classId) {
-        final types = (this.classId.compareTo(other.classId) < 0)
+      } else if (!identical(this.cls, other.cls)) {
+        final types = (this.cls.id < other.cls.id)
             ? <ConcreteType>[this, other]
             : <ConcreteType>[other, this];
         return new SetType(types);
@@ -786,7 +757,7 @@
       if (this == other) {
         return this;
       }
-      if (this.classId != other.classId) {
+      if (!identical(this.cls, other.cls)) {
         return EmptyType();
       }
       assertx(typeArgs != null || other.typeArgs != null);
@@ -809,7 +780,7 @@
         mergedTypeArgs[i] = merged;
       }
       if (!hasRuntimeType) return raw;
-      return new ConcreteType(classId, classNode, mergedTypeArgs);
+      return new ConcreteType(cls, mergedTypeArgs);
     } else {
       throw 'Unexpected type $other';
     }
@@ -915,7 +886,7 @@
       throw "ERROR: RuntimeType does not support isSpecialized.";
 
   @override
-  bool isSubtypeOf(TypeHierarchy typeHierarchy, DartType dartType) =>
+  bool isSubtypeOf(TypeHierarchy typeHierarchy, Class cls) =>
       throw "ERROR: RuntimeType does not support isSubtypeOf.";
 
   @override
@@ -944,20 +915,33 @@
 
   bool isSubtypeOfRuntimeType(
       TypeHierarchy typeHierarchy, RuntimeType runtimeType) {
-    if (!typeHierarchy.isSubtype(this._type, runtimeType._type)) return false;
-
-    // The typeHierarchy result maybe be inaccurate only if there are type
-    // arguments which need to be examined.
-    if (_type is! InterfaceType || runtimeType.numImmediateTypeArgs == 0) {
+    final rhs = runtimeType._type;
+    if (rhs is DynamicType ||
+        rhs is VoidType ||
+        _type is BottomType ||
+        _type is NeverType) {
       return true;
     }
+    if (rhs is BottomType || rhs is NeverType) return false;
+    if (_type is DynamicType || _type is VoidType) {
+      return (rhs is InterfaceType &&
+          rhs.classNode == typeHierarchy.coreTypes.objectClass);
+    }
 
     final thisClass = (_type as InterfaceType).classNode;
-    final otherClass = (runtimeType._type as InterfaceType).classNode;
+    final otherClass = (rhs as InterfaceType).classNode;
 
-    if (otherClass == typeHierarchy.futureOrClass) {
-      if (thisClass == typeHierarchy.futureClass ||
-          thisClass == typeHierarchy.futureOrClass) {
+    if (!typeHierarchy.isSubtype(thisClass, otherClass)) return false;
+
+    // The typeHierarchy result maybe be inaccurate only if there are type
+    // arguments which need to be examined.
+    if (runtimeType.numImmediateTypeArgs == 0) {
+      return true;
+    }
+
+    if (otherClass == typeHierarchy.coreTypes.futureOrClass) {
+      if (thisClass == typeHierarchy.coreTypes.futureClass ||
+          thisClass == typeHierarchy.coreTypes.futureOrClass) {
         return typeArgs[0]
             .isSubtypeOfRuntimeType(typeHierarchy, runtimeType.typeArgs[0]);
       } else {
diff --git a/pkg/vm/test/bytecode/object_table_test.dart b/pkg/vm/test/bytecode/object_table_test.dart
index 98923e8..84f1001 100644
--- a/pkg/vm/test/bytecode/object_table_test.dart
+++ b/pkg/vm/test/bytecode/object_table_test.dart
@@ -40,7 +40,7 @@
     lib2.parent = component;
     component.libraries.add(lib2);
 
-    objectTable = new ObjectTable();
+    objectTable = new ObjectTable(coreTypes);
   });
 
   tearDown(() {});
diff --git a/pkg/vm/test/bytecode/recursive_types_validator_test.dart b/pkg/vm/test/bytecode/recursive_types_validator_test.dart
index 6e27e46..6927492 100644
--- a/pkg/vm/test/bytecode/recursive_types_validator_test.dart
+++ b/pkg/vm/test/bytecode/recursive_types_validator_test.dart
@@ -10,6 +10,7 @@
 import 'package:vm/bytecode/recursive_types_validator.dart';
 
 main() {
+  CoreTypes coreTypes;
   Library lib;
   Supertype objectSuper;
   DartType intType;
@@ -27,7 +28,7 @@
   setUp(() {
     // Start with mock SDK libraries.
     Component component = createMockSdkComponent();
-    CoreTypes coreTypes = new CoreTypes(component);
+    coreTypes = new CoreTypes(component);
     objectSuper = coreTypes.objectClass.asThisSupertype;
     intType = new InterfaceType(coreTypes.intClass, Nullability.legacy);
     doubleType = new InterfaceType(coreTypes.doubleClass, Nullability.legacy);
@@ -40,7 +41,7 @@
     // class Base<T>
     base = addClass('Base', [new TypeParameter('T')]);
 
-    validator = new RecursiveTypesValidator();
+    validator = new RecursiveTypesValidator(coreTypes);
   });
 
   tearDown(() {});
@@ -165,9 +166,10 @@
         new InterfaceType(e, Nullability.legacy, [intType, doubleType]);
 
     validator.validateType(eOfIntDouble);
-    validator.validateType(e.thisType);
+    validator.validateType(e.getThisType(coreTypes, lib.nonNullable));
 
     Expect.isFalse(validator.isRecursive(eOfIntDouble));
-    Expect.isFalse(validator.isRecursive(e.thisType));
+    Expect.isFalse(
+        validator.isRecursive(e.getThisType(coreTypes, lib.nonNullable)));
   });
 }
diff --git a/pkg/vm/test/modular_kernel_plus_aot_test.dart b/pkg/vm/test/modular_kernel_plus_aot_test.dart
new file mode 100644
index 0000000..d382501
--- /dev/null
+++ b/pkg/vm/test/modular_kernel_plus_aot_test.dart
@@ -0,0 +1,163 @@
+// Copyright (c) 2019, 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:async';
+import 'dart:io';
+import 'dart:typed_data';
+
+import 'package:front_end/src/api_unstable/bazel_worker.dart' as fe;
+import 'package:front_end/src/api_prototype/standard_file_system.dart';
+import 'package:kernel/target/targets.dart';
+import 'package:kernel/kernel.dart';
+import 'package:kernel/verifier.dart';
+import 'package:vm/target/vm.dart';
+import 'package:vm/kernel_front_end.dart';
+
+main() async {
+  Uri sdkSummary =
+      sdkRootFile(Platform.executable).resolve('vm_platform_strong.dill');
+  if (!await File.fromUri(sdkSummary).exists()) {
+    // If we run from the <build-dir>/dart-sdk/bin folder, we need to navigate two
+    // levels up.
+    sdkSummary = sdkRootFile(Platform.executable)
+        .resolve('../../vm_platform_strong.dill');
+  }
+
+  // Tests are run in the root directory of the sdk checkout.
+  final Uri packagesFile = sdkRootFile('.packages');
+  final Uri librariesFile = sdkRootFile('sdk/lib/libraries.json');
+
+  final vmTarget = VmTarget(TargetFlags());
+
+  await withTempDirectory((Uri uri) async {
+    final mixinFilename = uri.resolve('mixin.dart');
+    final mixinDillFilename = uri.resolve('mixin.dart.dill');
+    await File.fromUri(mixinFilename).writeAsStringSync(mixinFile);
+
+    await compileToKernel(vmTarget, librariesFile, sdkSummary, packagesFile,
+        mixinDillFilename, <Uri>[mixinFilename], <Uri>[], <Uri>[]);
+
+    final mainFilename = uri.resolve('main.dart');
+    final mainDillFilename = uri.resolve('main.dart.dill');
+    await File.fromUri(mainFilename).writeAsStringSync(mainFile);
+
+    await compileToKernel(
+        vmTarget,
+        librariesFile,
+        sdkSummary,
+        packagesFile,
+        mainDillFilename,
+        <Uri>[mainFilename],
+        <Uri>[mixinDillFilename],
+        <Uri>[]);
+
+    final bytes = concat(
+        await File.fromUri(sdkSummary).readAsBytes(),
+        concat(await File.fromUri(mixinDillFilename).readAsBytes(),
+            await File.fromUri(mainDillFilename).readAsBytes()));
+    final component = loadComponentFromBytes(bytes);
+
+    // Verify before running global transformations.
+    verifyComponent(component, isOutline: false, afterConst: true);
+
+    const useGlobalTypeFlowAnalysis = true;
+    const enableAsserts = false;
+    const useProtobufTreeShaker = false;
+    await runGlobalTransformations(
+        vmTarget,
+        component,
+        useGlobalTypeFlowAnalysis,
+        enableAsserts,
+        useProtobufTreeShaker,
+        ErrorDetector());
+
+    // Verify after running global transformations.
+    verifyComponent(component, isOutline: false, afterConst: true);
+  });
+}
+
+Future compileToKernel(
+    Target target,
+    Uri librariesFile,
+    Uri sdkSummary,
+    Uri packagesFile,
+    Uri outputFile,
+    List<Uri> sources,
+    List<Uri> linkedInputs,
+    List<Uri> summaryInputs) async {
+  final state = await fe.initializeCompiler(
+      null,
+      sdkSummary,
+      librariesFile,
+      packagesFile,
+      summaryInputs,
+      linkedInputs,
+      target,
+      StandardFileSystem.instance, const <String>[], const <String, String>{});
+
+  void onDiagnostic(fe.DiagnosticMessage message) {
+    print(message);
+  }
+
+  final Component component =
+      await fe.compileComponent(state, sources, onDiagnostic);
+  final Uint8List kernel = fe.serializeComponent(component,
+      filter: (library) => sources.contains(library.importUri));
+  await File(outputFile.toFilePath()).writeAsBytes(kernel);
+}
+
+Future withTempDirectory(Future func(Uri dirUri)) async {
+  final dir = await Directory.systemTemp.createTemp('modular-compile-test');
+  try {
+    await func(dir.uri);
+  } finally {
+    await dir.delete(recursive: true);
+  }
+}
+
+Uint8List concat(List<int> a, List<int> b) {
+  final bytes = Uint8List(a.length + b.length);
+  bytes.setRange(0, a.length, a);
+  bytes.setRange(a.length, bytes.length, b);
+  return bytes;
+}
+
+Uri sdkRootFile(name) => Directory.current.uri.resolveUri(Uri.file(name));
+
+const String mainFile = r'''
+import 'mixin.dart';
+class R extends A2 {
+  void bar() {
+    mixinProperty = '';
+    mixinProperty .foo();
+    mixinMethod('').foo();
+    super.mixinProperty= '';
+    super.mixinProperty.foo();
+    super.mixinMethod('').foo();
+  }
+}
+
+main() {
+  A1();
+  final a2 = A2();
+  // The mixin deduplication will remove the anonymous mixin application class
+  // from `A2 & Mixin` and instead use the one from `A1 & Mixin`.
+  a2.mixinProperty= '';
+  a2.mixinProperty.foo();
+  a2.mixinMethod('').foo();
+}
+''';
+
+const String mixinFile = r'''
+class Foo {
+  foo() {}
+}
+class Mixin {
+  void set mixinProperty(v) {}
+  Foo get mixinProperty{}
+  Foo mixinMethod(v) {}
+}
+class A1 extends Object with Mixin { }
+class A2 extends Object with Mixin { }
+''';
diff --git a/pkg/vm/test/transformations/type_flow/summary_collector_test.dart b/pkg/vm/test/transformations/type_flow/summary_collector_test.dart
index 4ab863b..2bb4e8b 100644
--- a/pkg/vm/test/transformations/type_flow/summary_collector_test.dart
+++ b/pkg/vm/test/transformations/type_flow/summary_collector_test.dart
@@ -7,33 +7,72 @@
 import 'package:kernel/ast.dart';
 import 'package:kernel/class_hierarchy.dart';
 import 'package:kernel/core_types.dart';
+import 'package:kernel/target/targets.dart';
 import 'package:kernel/type_environment.dart';
 import 'package:test/test.dart';
 import 'package:vm/transformations/pragma.dart'
     show ConstantPragmaAnnotationParser;
+import 'package:vm/transformations/type_flow/analysis.dart';
+import 'package:vm/transformations/type_flow/calls.dart';
 import 'package:vm/transformations/type_flow/native_code.dart';
 import 'package:vm/transformations/type_flow/summary_collector.dart';
-import 'package:vm/transformations/type_flow/analysis.dart';
-import 'package:kernel/target/targets.dart';
+import 'package:vm/transformations/type_flow/types.dart';
 
 import '../../common_test_utils.dart';
 
 final String pkgVmDir = Platform.script.resolve('../../..').toFilePath();
 
+class FakeTypesBuilder extends TypesBuilder {
+  final Map<Class, TFClass> _classes = <Class, TFClass>{};
+  int _classIdCounter = 0;
+
+  FakeTypesBuilder(CoreTypes coreTypes) : super(coreTypes);
+
+  @override
+  TFClass getTFClass(Class c) =>
+      _classes[c] ??= new TFClass(++_classIdCounter, c);
+}
+
+class FakeEntryPointsListener implements EntryPointsListener {
+  final FakeTypesBuilder _typesBuilder;
+
+  FakeEntryPointsListener(this._typesBuilder);
+
+  @override
+  void addRawCall(Selector selector) {}
+
+  @override
+  void addDirectFieldAccess(Field field, Type value) {}
+
+  @override
+  ConcreteType addAllocatedClass(Class c) {
+    return new ConcreteType(_typesBuilder.getTFClass(c), null);
+  }
+
+  @override
+  void recordMemberCalledViaInterfaceSelector(Member target) {}
+
+  @override
+  void recordMemberCalledViaThis(Member target) {}
+}
+
 class PrintSummaries extends RecursiveVisitor<Null> {
-  final SummaryCollector _summaryCollector;
+  SummaryCollector _summaryCollector;
   final StringBuffer _buf = new StringBuffer();
 
   PrintSummaries(Target target, TypeEnvironment environment,
-      CoreTypes coreTypes, ClassHierarchy hierarchy)
-      : _summaryCollector = new SummaryCollector(
-            target,
-            environment,
-            hierarchy,
-            new EmptyEntryPointsListener(),
-            new NativeCodeOracle(
-                null, new ConstantPragmaAnnotationParser(coreTypes)),
-            new GenericInterfacesInfoImpl(hierarchy));
+      CoreTypes coreTypes, ClassHierarchy hierarchy) {
+    final typesBuilder = new FakeTypesBuilder(coreTypes);
+    _summaryCollector = new SummaryCollector(
+        target,
+        environment,
+        hierarchy,
+        new FakeEntryPointsListener(typesBuilder),
+        typesBuilder,
+        new NativeCodeOracle(
+            null, new ConstantPragmaAnnotationParser(coreTypes)),
+        new GenericInterfacesInfoImpl(hierarchy));
+  }
 
   String print(TreeNode node) {
     visitLibrary(node);
diff --git a/pkg/vm/test/transformations/type_flow/types_test.dart b/pkg/vm/test/transformations/type_flow/types_test.dart
index 1689617..ec6e530 100644
--- a/pkg/vm/test/transformations/type_flow/types_test.dart
+++ b/pkg/vm/test/transformations/type_flow/types_test.dart
@@ -6,105 +6,123 @@
 
 import 'package:kernel/ast.dart';
 import 'package:kernel/core_types.dart';
+import 'package:kernel/testing/mock_sdk_component.dart';
 import 'package:test/test.dart';
 import 'package:vm/transformations/type_flow/types.dart';
 
-class TestTypeHierarchy implements TypeHierarchy {
-  final Map<DartType, List<DartType>> subtypes;
-  final Map<DartType, Type> specializations;
-  final CoreTypes coreTypes = new CoreTypes(new Component());
+class TestTypeHierarchy extends TypeHierarchy {
+  final Map<Class, TFClass> classes = <Class, TFClass>{};
+  final Map<Class, List<Class>> subtypes;
+  final Map<Class, Type> specializations;
+  int classIdCounter = 0;
 
-  TestTypeHierarchy(this.subtypes, this.specializations);
+  TestTypeHierarchy(CoreTypes coreTypes, this.subtypes, this.specializations)
+      : super(coreTypes);
 
   @override
-  bool isSubtype(DartType subType, DartType superType) {
-    return subtypes[superType].contains(subType);
+  bool isSubtype(Class sub, Class sup) {
+    return subtypes[sup].contains(sub);
   }
 
   @override
-  Type specializeTypeCone(DartType base) {
-    Type result = specializations[base];
+  Type specializeTypeCone(TFClass base) {
+    Type result = specializations[base.classNode];
     expect(result, isNotNull,
         reason: "specializeTypeCone($base) is not defined");
     return result;
   }
 
+  @override
+  TFClass getTFClass(Class c) =>
+      classes[c] ??= new TFClass(++classIdCounter, c);
+
+  @override
   List<DartType> flattenedTypeArgumentsFor(Class klass) =>
       throw "flattenedTypeArgumentsFor is not supported in the types test.";
 
+  @override
   int genericInterfaceOffsetFor(Class klass, Class iface) =>
       throw "genericInterfaceOffsetFor is not supported in the types test.";
 
+  @override
   List<Type> flattenedTypeArgumentsForNonGeneric(Class klass) =>
       throw "flattenedTypeArgumentsFor is not supported in the types test.";
-
-  Class get futureOrClass =>
-      throw "futureOrClass not supported in the types test.";
-  Class get futureClass => throw "futureClass not supported in the types test.";
-  Class get functionClass =>
-      throw "functionClass not supported in the types test.";
 }
 
 main() {
-  test('factory-constructors', () {
-    Class c1 = new Class(name: 'C1');
-    Class c2 = new Class(name: 'C2', typeParameters: [new TypeParameter('E')]);
-    InterfaceType t1 = new InterfaceType(c1, Nullability.legacy);
-    InterfaceType t2Raw = new InterfaceType(c2, Nullability.legacy);
-    InterfaceType t2Generic = new InterfaceType(c2, Nullability.legacy, [t1]);
-    FunctionType f1 =
+  final Component component = createMockSdkComponent();
+  final CoreTypes coreTypes = new CoreTypes(component);
+
+  test('types-builder', () {
+    final Class c1 = new Class(name: 'C1');
+    final Class c2 =
+        new Class(name: 'C2', typeParameters: [new TypeParameter('E')]);
+
+    final TypesBuilder tb = new TestTypeHierarchy(coreTypes, {}, {});
+    final tfc1 = tb.getTFClass(c1);
+    final tfc2 = tb.getTFClass(c2);
+
+    final InterfaceType t1 = new InterfaceType(c1, Nullability.legacy);
+    final InterfaceType t2Raw = new InterfaceType(c2, Nullability.legacy);
+    final InterfaceType t2Generic =
+        new InterfaceType(c2, Nullability.legacy, [t1]);
+    final InterfaceType t3 =
+        new InterfaceType(coreTypes.nullClass, Nullability.nullable);
+    final FunctionType f1 =
         new FunctionType([t1], const VoidType(), Nullability.legacy);
 
-    expect(new Type.empty(), equals(const EmptyType()));
+    expect(tb.fromStaticType(const NeverType(Nullability.nonNullable), false),
+        equals(const EmptyType()));
+    expect(tb.fromStaticType(const BottomType(), true),
+        equals(new NullableType(const EmptyType())));
+    expect(tb.fromStaticType(const DynamicType(), true),
+        equals(new NullableType(const AnyType())));
+    expect(tb.fromStaticType(const VoidType(), true),
+        equals(new NullableType(const AnyType())));
 
-    expect(new Type.cone(const DynamicType()), equals(const AnyType()));
-    expect(new Type.cone(t1), equals(new ConeType(t1)));
-    expect(new Type.cone(t2Raw), equals(new ConeType(t2Raw)));
-    expect(new Type.cone(t2Generic), equals(new ConeType(t2Raw)));
-    expect(new Type.cone(f1), equals(const AnyType()));
+    expect(tb.fromStaticType(t1, false), equals(new ConeType(tfc1)));
+    expect(tb.fromStaticType(t2Raw, false), equals(new ConeType(tfc2)));
+    expect(tb.fromStaticType(t2Generic, false), equals(new ConeType(tfc2)));
+    expect(tb.fromStaticType(t3, false), equals(new EmptyType()));
+    expect(tb.fromStaticType(f1, false), equals(const AnyType()));
 
-    expect(new Type.nullable(new Type.empty()),
-        equals(new NullableType(new EmptyType())));
-    expect(new Type.nullable(new Type.cone(t1)),
-        equals(new NullableType(new ConeType(t1))));
+    expect(tb.fromStaticType(t1, true),
+        equals(new NullableType(new ConeType(tfc1))));
+    expect(tb.fromStaticType(t2Raw, true),
+        equals(new NullableType(new ConeType(tfc2))));
+    expect(tb.fromStaticType(t2Generic, true),
+        equals(new NullableType(new ConeType(tfc2))));
+    expect(
+        tb.fromStaticType(t3, true), equals(new NullableType(new EmptyType())));
+    expect(
+        tb.fromStaticType(f1, true), equals(new NullableType(const AnyType())));
 
     expect(new Type.nullableAny(), equals(new NullableType(new AnyType())));
-
-    expect(new Type.fromStatic(const DynamicType()),
-        equals(new NullableType(new AnyType())));
-    expect(new Type.fromStatic(const DynamicType()),
-        equals(new Type.nullableAny()));
-    expect(new Type.fromStatic(const BottomType()),
-        equals(new NullableType(new EmptyType())));
-    expect(new Type.fromStatic(t1), equals(new NullableType(new ConeType(t1))));
-    expect(new Type.fromStatic(t2Raw),
-        equals(new NullableType(new ConeType(t2Raw))));
-    expect(new Type.fromStatic(t2Generic),
-        equals(new NullableType(new ConeType(t2Raw))));
   });
 
   test('union-intersection', () {
     // T1 <: T3, T2 <: T3
 
-    InterfaceType t1 =
-        new InterfaceType(new Class(name: 'T1'), Nullability.legacy);
-    InterfaceType t2 =
-        new InterfaceType(new Class(name: 'T2'), Nullability.legacy);
-    InterfaceType t3 =
-        new InterfaceType(new Class(name: 'T3'), Nullability.legacy);
-    InterfaceType t4 =
-        new InterfaceType(new Class(name: 'T4'), Nullability.legacy);
+    final c1 = new Class(name: 'T1');
+    final c2 = new Class(name: 'T2');
+    final c3 = new Class(name: 'T3');
+    final c4 = new Class(name: 'T4');
+
+    final tfc1 = new TFClass(1, c1);
+    final tfc2 = new TFClass(2, c2);
+    final tfc3 = new TFClass(3, c3);
+    final tfc4 = new TFClass(4, c4);
 
     final empty = new EmptyType();
     final any = new AnyType();
-    final concreteT1 = new ConcreteType(const IntClassId(1), t1.classNode);
-    final concreteT2 = new ConcreteType(const IntClassId(2), t2.classNode);
-    final concreteT3 = new ConcreteType(const IntClassId(3), t3.classNode);
-    final concreteT4 = new ConcreteType(const IntClassId(4), t4.classNode);
-    final coneT1 = new ConeType(t1);
-    final coneT2 = new ConeType(t2);
-    final coneT3 = new ConeType(t3);
-    final coneT4 = new ConeType(t4);
+    final concreteT1 = new ConcreteType(tfc1);
+    final concreteT2 = new ConcreteType(tfc2);
+    final concreteT3 = new ConcreteType(tfc3);
+    final concreteT4 = new ConcreteType(tfc4);
+    final coneT1 = new ConeType(tfc1);
+    final coneT2 = new ConeType(tfc2);
+    final coneT3 = new ConeType(tfc3);
+    final coneT4 = new ConeType(tfc4);
     final setT12 = new SetType([concreteT1, concreteT2]);
     final setT14 = new SetType([concreteT1, concreteT4]);
     final setT23 = new SetType([concreteT2, concreteT3]);
@@ -242,20 +260,20 @@
       [nullableSetT12, nullableSetT34, nullableSetT1234, nullableEmpty],
     ];
 
-    final hierarchy = new TestTypeHierarchy(
+    final hierarchy = new TestTypeHierarchy(coreTypes,
         // subtypes
         {
-          t1: [t1],
-          t2: [t2],
-          t3: [t1, t2, t3],
-          t4: [t4],
+          c1: [c1],
+          c2: [c2],
+          c3: [c1, c2, c3],
+          c4: [c4],
         },
         // specializations
         {
-          t1: concreteT1,
-          t2: concreteT2,
-          t3: setT123,
-          t4: concreteT4
+          c1: concreteT1,
+          c2: concreteT2,
+          c3: setT123,
+          c4: concreteT4
         });
 
     for (List testCase in testCases) {
@@ -280,17 +298,13 @@
     final c2 = new Class(name: 'C2');
     final c3 = new Class(name: 'C3');
 
+    final tfc1 = new TFClass(1, c1);
+    final tfc2 = new TFClass(2, c2);
+    final tfc3 = new TFClass(3, c3);
+
     final t1a = new InterfaceType(c1, Nullability.legacy);
     final t1b = new InterfaceType(c1, Nullability.legacy);
     final t2 = new InterfaceType(c2, Nullability.legacy);
-    final f1a = new FunctionType([t1a], const VoidType(), Nullability.legacy);
-    final f1b = new FunctionType([t1b], const VoidType(), Nullability.legacy);
-    final f2 =
-        new FunctionType([t1a, t1a], const VoidType(), Nullability.legacy);
-
-    final cid1 = const IntClassId(1);
-    final cid2 = const IntClassId(2);
-    final cid3 = const IntClassId(3);
 
     void eq(dynamic a, dynamic b) {
       expect(a == b, isTrue, reason: "Test case: $a == $b");
@@ -308,68 +322,61 @@
 
     eq(t1a, t1b);
     ne(t1a, t2);
-    eq(f1a, f1b);
-    ne(f1a, f2);
-    ne(t1a, f1a);
 
     eq(new EmptyType(), new EmptyType());
     ne(new EmptyType(), new AnyType());
-    ne(new EmptyType(), new ConcreteType(cid1, c1));
-    ne(new EmptyType(), new ConeType(t1a));
+    ne(new EmptyType(), new ConcreteType(tfc1));
+    ne(new EmptyType(), new ConeType(tfc1));
     ne(new EmptyType(),
-        new SetType([new ConcreteType(cid1, c1), new ConcreteType(cid2, c2)]));
+        new SetType([new ConcreteType(tfc1), new ConcreteType(tfc2)]));
     ne(new EmptyType(), new NullableType(new EmptyType()));
 
     eq(new AnyType(), new AnyType());
-    ne(new AnyType(), new ConcreteType(cid1, c1));
-    ne(new AnyType(), new ConeType(t1a));
+    ne(new AnyType(), new ConcreteType(tfc1));
+    ne(new AnyType(), new ConeType(tfc1));
     ne(new AnyType(),
-        new SetType([new ConcreteType(cid1, c1), new ConcreteType(cid2, c2)]));
+        new SetType([new ConcreteType(tfc1), new ConcreteType(tfc2)]));
     ne(new AnyType(), new NullableType(new EmptyType()));
 
-    eq(new ConcreteType(cid1, c1), new ConcreteType(cid1, c1));
-    ne(new ConcreteType(cid1, c1), new ConcreteType(cid2, c2));
-    ne(new ConcreteType(cid1, c1), new ConeType(t1a));
-    ne(new ConcreteType(cid1, c1), new ConeType(t2));
-    ne(new ConcreteType(cid1, c1),
-        new SetType([new ConcreteType(cid1, c1), new ConcreteType(cid2, c2)]));
-    ne(new ConcreteType(cid1, c1),
-        new NullableType(new ConcreteType(cid1, c1)));
+    eq(new ConcreteType(tfc1), new ConcreteType(tfc1));
+    ne(new ConcreteType(tfc1), new ConcreteType(tfc2));
+    ne(new ConcreteType(tfc1), new ConeType(tfc1));
+    ne(new ConcreteType(tfc1), new ConeType(tfc2));
+    ne(new ConcreteType(tfc1),
+        new SetType([new ConcreteType(tfc1), new ConcreteType(tfc2)]));
+    ne(new ConcreteType(tfc1), new NullableType(new ConcreteType(tfc1)));
 
-    eq(new ConeType(t1a), new ConeType(t1b));
-    eq(new ConeType(f1a), new ConeType(f1b));
-    ne(new ConeType(t1a), new ConeType(t2));
-    ne(new ConeType(f1a), new ConeType(f2));
-    ne(new ConeType(t1a), new ConeType(f1a));
-    ne(new ConeType(t1a),
-        new SetType([new ConcreteType(cid1, c1), new ConcreteType(cid2, c2)]));
-    ne(new ConeType(t1a), new NullableType(new ConeType(t1a)));
+    eq(new ConeType(tfc1), new ConeType(tfc1));
+    ne(new ConeType(tfc1), new ConeType(tfc2));
+    ne(new ConeType(tfc1),
+        new SetType([new ConcreteType(tfc1), new ConcreteType(tfc2)]));
+    ne(new ConeType(tfc1), new NullableType(new ConeType(tfc1)));
 
-    eq(new SetType([new ConcreteType(cid1, c1), new ConcreteType(cid2, c2)]),
-        new SetType([new ConcreteType(cid1, c1), new ConcreteType(cid2, c2)]));
+    eq(new SetType([new ConcreteType(tfc1), new ConcreteType(tfc2)]),
+        new SetType([new ConcreteType(tfc1), new ConcreteType(tfc2)]));
     eq(
         new SetType([
-          new ConcreteType(cid1, c1),
-          new ConcreteType(cid2, c2),
-          new ConcreteType(cid3, c3)
+          new ConcreteType(tfc1),
+          new ConcreteType(tfc2),
+          new ConcreteType(tfc3)
         ]),
         new SetType([
-          new ConcreteType(cid1, c1),
-          new ConcreteType(cid2, c2),
-          new ConcreteType(cid3, c3)
+          new ConcreteType(tfc1),
+          new ConcreteType(tfc2),
+          new ConcreteType(tfc3)
         ]));
     ne(
-        new SetType([new ConcreteType(cid1, c1), new ConcreteType(cid2, c2)]),
+        new SetType([new ConcreteType(tfc1), new ConcreteType(tfc2)]),
         new SetType([
-          new ConcreteType(cid1, c1),
-          new ConcreteType(cid2, c2),
-          new ConcreteType(cid3, c3)
+          new ConcreteType(tfc1),
+          new ConcreteType(tfc2),
+          new ConcreteType(tfc3)
         ]));
-    ne(new SetType([new ConcreteType(cid1, c1), new ConcreteType(cid2, c2)]),
-        new SetType([new ConcreteType(cid1, c1), new ConcreteType(cid3, c3)]));
+    ne(new SetType([new ConcreteType(tfc1), new ConcreteType(tfc2)]),
+        new SetType([new ConcreteType(tfc1), new ConcreteType(tfc3)]));
     ne(
-        new SetType([new ConcreteType(cid1, c1), new ConcreteType(cid2, c2)]),
-        new NullableType(new SetType(
-            [new ConcreteType(cid1, c1), new ConcreteType(cid2, c2)])));
+        new SetType([new ConcreteType(tfc1), new ConcreteType(tfc2)]),
+        new NullableType(
+            new SetType([new ConcreteType(tfc1), new ConcreteType(tfc2)])));
   });
 }
diff --git a/pkg/vm/testcases/bytecode/async.dart.expect b/pkg/vm/testcases/bytecode/async.dart.expect
index 224709f..3dc478d 100644
--- a/pkg/vm/testcases/bytecode/async.dart.expect
+++ b/pkg/vm/testcases/bytecode/async.dart.expect
@@ -413,13 +413,13 @@
   StoreLocal           r2
   Push                 r2
   PushNull
-  StoreFieldTOS        CP#18
+  StoreFieldTOS        CP#16
   Push                 r2
   PushNull
-  StoreFieldTOS        CP#20
+  StoreFieldTOS        CP#18
   Push                 r2
   PushConstant         CP#4
-  StoreFieldTOS        CP#22
+  StoreFieldTOS        CP#20
   Push                 r2
   Push                 r0
   StoreFieldTOS        CP#6
@@ -429,22 +429,22 @@
   Push                 r0
   Push                 r0
   LoadContextVar       0, 10
-  DirectCall           CP#24, 1
+  DirectCall           CP#22, 1
   StoreContextVar      0, 4
   Push                 r0
   Push                 r0
   LoadContextVar       0, 10
-  DirectCall           CP#26, 1
+  DirectCall           CP#24, 1
   StoreContextVar      0, 5
   Push                 r0
   LoadContextVar       0, 2
   Push                 r0
   LoadContextVar       0, 10
-  DynamicCall          CP#28, 2
+  DynamicCall          CP#26, 2
   Drop1
   Push                 r0
   LoadContextVar       0, 2
-  InterfaceCall        CP#30, 1
+  InterfaceCall        CP#28, 1
   ReturnTOS
 }
 ConstantPool {
@@ -458,28 +458,26 @@
   [7] = Reserved
   [8] = DirectCall 'dart:async::_awaitHelper', ArgDesc num-args 4, num-type-args 0, names []
   [9] = Reserved
-  [10] = InterfaceCall 'dart:core::num::+', ArgDesc num-args 2, num-type-args 0, names []
+  [10] = DirectCall 'dart:async::_completeOnAsyncReturn', ArgDesc num-args 2, num-type-args 0, names []
   [11] = Reserved
-  [12] = DirectCall 'dart:async::_completeOnAsyncReturn', ArgDesc num-args 2, num-type-args 0, names []
-  [13] = Reserved
-  [14] = Type dynamic
-  [15] = InterfaceCall 'dart:async::Completer::completeError', ArgDesc num-args 3, num-type-args 0, names []
-  [16] = Reserved
-  [17] = EndClosureFunctionScope
-  [18] = InstanceField dart:core::_Closure::_instantiator_type_arguments (field)
+  [12] = Type dynamic
+  [13] = InterfaceCall 'dart:async::Completer::completeError', ArgDesc num-args 3, num-type-args 0, names []
+  [14] = Reserved
+  [15] = EndClosureFunctionScope
+  [16] = InstanceField dart:core::_Closure::_instantiator_type_arguments (field)
+  [17] = Reserved
+  [18] = InstanceField dart:core::_Closure::_function_type_arguments (field)
   [19] = Reserved
-  [20] = InstanceField dart:core::_Closure::_function_type_arguments (field)
+  [20] = InstanceField dart:core::_Closure::_function (field)
   [21] = Reserved
-  [22] = InstanceField dart:core::_Closure::_function (field)
+  [22] = DirectCall 'dart:async::_asyncThenWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
   [23] = Reserved
-  [24] = DirectCall 'dart:async::_asyncThenWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
+  [24] = DirectCall 'dart:async::_asyncErrorWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
   [25] = Reserved
-  [26] = DirectCall 'dart:async::_asyncErrorWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
+  [26] = DynamicCall 'start', ArgDesc num-args 2, num-type-args 0, names []
   [27] = Reserved
-  [28] = DynamicCall 'start', ArgDesc num-args 2, num-type-args 0, names []
+  [28] = InterfaceCall 'dart:async::Completer::get:future', ArgDesc num-args 1, num-type-args 0, names []
   [29] = Reserved
-  [30] = InterfaceCall 'dart:async::Completer::get:future', ArgDesc num-args 1, num-type-args 0, names []
-  [31] = Reserved
 }
 Closure #lib::simpleAsyncAwait::':async_op' ([ dynamic :result, dynamic :exception, dynamic :stack_trace ]) -> dynamic
 ClosureCode {
@@ -558,7 +556,7 @@
   Push                 r4
   LoadContextVar       0, 9
   Push                 r1
-  InterfaceCall        CP#10, 2
+  AddInt
   StoreContextVar      0, 3
   Jump                 L4
 L4:
@@ -566,7 +564,7 @@
   LoadContextVar       0, 2
   Push                 r4
   LoadContextVar       0, 3
-  DirectCall           CP#12, 2
+  DirectCall           CP#10, 2
   Drop1
   PushNull
   ReturnTOS
@@ -589,7 +587,7 @@
   LoadContextVar       0, 2
   Push                 r8
   Push                 r9
-  InterfaceCall        CP#15, 3
+  InterfaceCall        CP#13, 3
   Drop1
   Jump                 L5
 L5:
@@ -637,13 +635,13 @@
   StoreLocal           r2
   Push                 r2
   PushNull
-  StoreFieldTOS        CP#26
+  StoreFieldTOS        CP#24
   Push                 r2
   PushNull
-  StoreFieldTOS        CP#28
+  StoreFieldTOS        CP#26
   Push                 r2
   PushConstant         CP#4
-  StoreFieldTOS        CP#30
+  StoreFieldTOS        CP#28
   Push                 r2
   Push                 r0
   StoreFieldTOS        CP#6
@@ -653,22 +651,22 @@
   Push                 r0
   Push                 r0
   LoadContextVar       0, 10
-  DirectCall           CP#32, 1
+  DirectCall           CP#30, 1
   StoreContextVar      0, 3
   Push                 r0
   Push                 r0
   LoadContextVar       0, 10
-  DirectCall           CP#34, 1
+  DirectCall           CP#32, 1
   StoreContextVar      0, 4
   Push                 r0
   LoadContextVar       0, 1
   Push                 r0
   LoadContextVar       0, 10
-  DynamicCall          CP#36, 2
+  DynamicCall          CP#34, 2
   Drop1
   Push                 r0
   LoadContextVar       0, 1
-  InterfaceCall        CP#38, 1
+  InterfaceCall        CP#36, 1
   ReturnTOS
 }
 ConstantPool {
@@ -690,28 +688,26 @@
   [15] = Reserved
   [16] = DirectCall 'dart:async::_awaitHelper', ArgDesc num-args 4, num-type-args 0, names []
   [17] = Reserved
-  [18] = InterfaceCall 'dart:core::num::+', ArgDesc num-args 2, num-type-args 0, names []
+  [18] = DirectCall 'dart:async::_completeOnAsyncReturn', ArgDesc num-args 2, num-type-args 0, names []
   [19] = Reserved
-  [20] = DirectCall 'dart:async::_completeOnAsyncReturn', ArgDesc num-args 2, num-type-args 0, names []
-  [21] = Reserved
-  [22] = Type dynamic
-  [23] = InterfaceCall 'dart:async::Completer::completeError', ArgDesc num-args 3, num-type-args 0, names []
-  [24] = Reserved
-  [25] = EndClosureFunctionScope
-  [26] = InstanceField dart:core::_Closure::_instantiator_type_arguments (field)
+  [20] = Type dynamic
+  [21] = InterfaceCall 'dart:async::Completer::completeError', ArgDesc num-args 3, num-type-args 0, names []
+  [22] = Reserved
+  [23] = EndClosureFunctionScope
+  [24] = InstanceField dart:core::_Closure::_instantiator_type_arguments (field)
+  [25] = Reserved
+  [26] = InstanceField dart:core::_Closure::_function_type_arguments (field)
   [27] = Reserved
-  [28] = InstanceField dart:core::_Closure::_function_type_arguments (field)
+  [28] = InstanceField dart:core::_Closure::_function (field)
   [29] = Reserved
-  [30] = InstanceField dart:core::_Closure::_function (field)
+  [30] = DirectCall 'dart:async::_asyncThenWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
   [31] = Reserved
-  [32] = DirectCall 'dart:async::_asyncThenWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
+  [32] = DirectCall 'dart:async::_asyncErrorWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
   [33] = Reserved
-  [34] = DirectCall 'dart:async::_asyncErrorWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
+  [34] = DynamicCall 'start', ArgDesc num-args 2, num-type-args 0, names []
   [35] = Reserved
-  [36] = DynamicCall 'start', ArgDesc num-args 2, num-type-args 0, names []
+  [36] = InterfaceCall 'dart:async::Completer::get:future', ArgDesc num-args 1, num-type-args 0, names []
   [37] = Reserved
-  [38] = InterfaceCall 'dart:async::Completer::get:future', ArgDesc num-args 1, num-type-args 0, names []
-  [39] = Reserved
 }
 Closure #lib::loops::':async_op' ([ dynamic :result, dynamic :exception, dynamic :stack_trace ]) -> dynamic
 ClosureCode {
@@ -857,8 +853,8 @@
   LoadContextParent
   LoadContextVar       0, 8
   Push                 r1
-  InterfaceCall        CP#18, 2
-  InterfaceCall        CP#18, 2
+  AddInt
+  AddInt
   StoreContextVar      1, 0
   Push                 r4
   LoadContextParent
@@ -917,7 +913,7 @@
   LoadContextVar       0, 1
   Push                 r4
   LoadContextVar       0, 2
-  DirectCall           CP#20, 2
+  DirectCall           CP#18, 2
   Drop1
   PushNull
   ReturnTOS
@@ -940,7 +936,7 @@
   LoadContextVar       0, 1
   Push                 r8
   Push                 r9
-  InterfaceCall        CP#23, 3
+  InterfaceCall        CP#21, 3
   Drop1
   Jump                 L10
 L10:
@@ -991,13 +987,13 @@
   StoreLocal           r2
   Push                 r2
   PushNull
-  StoreFieldTOS        CP#24
+  StoreFieldTOS        CP#22
   Push                 r2
   PushNull
-  StoreFieldTOS        CP#26
+  StoreFieldTOS        CP#24
   Push                 r2
   PushConstant         CP#4
-  StoreFieldTOS        CP#28
+  StoreFieldTOS        CP#26
   Push                 r2
   Push                 r0
   StoreFieldTOS        CP#6
@@ -1007,22 +1003,22 @@
   Push                 r0
   Push                 r0
   LoadContextVar       0, 17
-  DirectCall           CP#30, 1
+  DirectCall           CP#28, 1
   StoreContextVar      0, 5
   Push                 r0
   Push                 r0
   LoadContextVar       0, 17
-  DirectCall           CP#32, 1
+  DirectCall           CP#30, 1
   StoreContextVar      0, 6
   Push                 r0
   LoadContextVar       0, 3
   Push                 r0
   LoadContextVar       0, 17
-  DynamicCall          CP#34, 2
+  DynamicCall          CP#32, 2
   Drop1
   Push                 r0
   LoadContextVar       0, 3
-  InterfaceCall        CP#36, 1
+  InterfaceCall        CP#34, 1
   ReturnTOS
 }
 ConstantPool {
@@ -1036,34 +1032,32 @@
   [7] = Reserved
   [8] = DirectCall 'dart:async::_awaitHelper', ArgDesc num-args 4, num-type-args 0, names []
   [9] = Reserved
-  [10] = InterfaceCall 'dart:core::num::+', ArgDesc num-args 2, num-type-args 0, names []
-  [11] = Reserved
-  [12] = Type dynamic
-  [13] = Type dart:core::Error
-  [14] = InterfaceCall 'dart:core::Object::_simpleInstanceOf', ArgDesc num-args 2, num-type-args 0, names []
-  [15] = Reserved
-  [16] = ObjectRef 'fin'
-  [17] = DirectCall 'dart:core::print', ArgDesc num-args 1, num-type-args 0, names []
+  [10] = Type dynamic
+  [11] = Type dart:core::Error
+  [12] = InterfaceCall 'dart:core::Object::_simpleInstanceOf', ArgDesc num-args 2, num-type-args 0, names []
+  [13] = Reserved
+  [14] = ObjectRef 'fin'
+  [15] = DirectCall 'dart:core::print', ArgDesc num-args 1, num-type-args 0, names []
+  [16] = Reserved
+  [17] = DirectCall 'dart:async::_completeOnAsyncReturn', ArgDesc num-args 2, num-type-args 0, names []
   [18] = Reserved
-  [19] = DirectCall 'dart:async::_completeOnAsyncReturn', ArgDesc num-args 2, num-type-args 0, names []
+  [19] = InterfaceCall 'dart:async::Completer::completeError', ArgDesc num-args 3, num-type-args 0, names []
   [20] = Reserved
-  [21] = InterfaceCall 'dart:async::Completer::completeError', ArgDesc num-args 3, num-type-args 0, names []
-  [22] = Reserved
-  [23] = EndClosureFunctionScope
-  [24] = InstanceField dart:core::_Closure::_instantiator_type_arguments (field)
+  [21] = EndClosureFunctionScope
+  [22] = InstanceField dart:core::_Closure::_instantiator_type_arguments (field)
+  [23] = Reserved
+  [24] = InstanceField dart:core::_Closure::_function_type_arguments (field)
   [25] = Reserved
-  [26] = InstanceField dart:core::_Closure::_function_type_arguments (field)
+  [26] = InstanceField dart:core::_Closure::_function (field)
   [27] = Reserved
-  [28] = InstanceField dart:core::_Closure::_function (field)
+  [28] = DirectCall 'dart:async::_asyncThenWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
   [29] = Reserved
-  [30] = DirectCall 'dart:async::_asyncThenWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
+  [30] = DirectCall 'dart:async::_asyncErrorWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
   [31] = Reserved
-  [32] = DirectCall 'dart:async::_asyncErrorWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
+  [32] = DynamicCall 'start', ArgDesc num-args 2, num-type-args 0, names []
   [33] = Reserved
-  [34] = DynamicCall 'start', ArgDesc num-args 2, num-type-args 0, names []
+  [34] = InterfaceCall 'dart:async::Completer::get:future', ArgDesc num-args 1, num-type-args 0, names []
   [35] = Reserved
-  [36] = InterfaceCall 'dart:async::Completer::get:future', ArgDesc num-args 1, num-type-args 0, names []
-  [37] = Reserved
 }
 Closure #lib::tryCatchRethrow::':async_op' ([ dynamic :result, dynamic :exception, dynamic :stack_trace ]) -> dynamic
 ClosureCode {
@@ -1145,7 +1139,7 @@
   LoadContextParent
   LoadContextVar       0, 14
   Push                 r1
-  InterfaceCall        CP#10, 2
+  AddInt
   StoreContextVar      1, 0
   Jump                 L3
 Try #2 end:
@@ -1172,8 +1166,8 @@
   StoreContextVar      1, 1
   Push                 r4
   LoadContextVar       1, 1
-  PushConstant         CP#13
-  InterfaceCall        CP#14, 2
+  PushConstant         CP#11
+  InterfaceCall        CP#12, 2
   JumpIfFalse          L4
   Push                 r4
   LoadContextParent
@@ -1222,7 +1216,7 @@
   LoadContextParent
   LoadContextVar       0, 15
   Push                 r1
-  InterfaceCall        CP#10, 2
+  AddInt
   StoreContextVar      1, 0
   Push                 r4
   LoadContextParent
@@ -1252,8 +1246,8 @@
   LoadContextParent
   Push                 r9
   StoreContextVar      0, 13
-  PushConstant         CP#16
-  DirectCall           CP#17, 1
+  PushConstant         CP#14
+  DirectCall           CP#15, 1
   Drop1
   Push                 r4
   LoadContextParent
@@ -1296,7 +1290,7 @@
   LoadContextParent
   LoadContextVar       0, 16
   Push                 r1
-  InterfaceCall        CP#10, 2
+  AddInt
   StoreContextVar      1, 0
   Push                 r4
   LoadContextParent
@@ -1314,8 +1308,8 @@
   Push                 r4
   LoadContextVar       0, 10
   PopLocal             r4
-  PushConstant         CP#16
-  DirectCall           CP#17, 1
+  PushConstant         CP#14
+  DirectCall           CP#15, 1
   Drop1
   Push                 r4
   LoadContextParent
@@ -1358,7 +1352,7 @@
   LoadContextParent
   LoadContextVar       0, 16
   Push                 r1
-  InterfaceCall        CP#10, 2
+  AddInt
   StoreContextVar      1, 0
   Push                 r4
   LoadContextParent
@@ -1376,8 +1370,8 @@
   Push                 r4
   LoadContextVar       0, 10
   PopLocal             r4
-  PushConstant         CP#16
-  DirectCall           CP#17, 1
+  PushConstant         CP#14
+  DirectCall           CP#15, 1
   Drop1
   Push                 r4
   LoadContextParent
@@ -1420,7 +1414,7 @@
   LoadContextParent
   LoadContextVar       0, 16
   Push                 r1
-  InterfaceCall        CP#10, 2
+  AddInt
   StoreContextVar      1, 0
   Push                 r4
   LoadContextParent
@@ -1436,7 +1430,7 @@
   LoadContextVar       0, 3
   Push                 r4
   LoadContextVar       0, 4
-  DirectCall           CP#19, 2
+  DirectCall           CP#17, 2
   Drop1
   PushNull
   ReturnTOS
@@ -1459,7 +1453,7 @@
   LoadContextVar       0, 3
   Push                 r8
   Push                 r9
-  InterfaceCall        CP#21, 3
+  InterfaceCall        CP#19, 3
   Drop1
   Jump                 L12
 L12:
@@ -1812,13 +1806,13 @@
   StoreLocal           r2
   Push                 r2
   PushNull
-  StoreFieldTOS        CP#20
+  StoreFieldTOS        CP#18
   Push                 r2
   PushNull
-  StoreFieldTOS        CP#22
+  StoreFieldTOS        CP#20
   Push                 r2
   PushConstant         CP#4
-  StoreFieldTOS        CP#24
+  StoreFieldTOS        CP#22
   Push                 r2
   Push                 r0
   StoreFieldTOS        CP#6
@@ -1828,22 +1822,22 @@
   Push                 r0
   Push                 r0
   LoadContextVar       0, 8
-  DirectCall           CP#26, 1
+  DirectCall           CP#24, 1
   StoreContextVar      0, 3
   Push                 r0
   Push                 r0
   LoadContextVar       0, 8
-  DirectCall           CP#28, 1
+  DirectCall           CP#26, 1
   StoreContextVar      0, 4
   Push                 r0
   LoadContextVar       0, 1
   Push                 r0
   LoadContextVar       0, 8
-  DynamicCall          CP#30, 2
+  DynamicCall          CP#28, 2
   Drop1
   Push                 r0
   LoadContextVar       0, 1
-  InterfaceCall        CP#32, 1
+  InterfaceCall        CP#30, 1
   ReturnTOS
 }
 ConstantPool {
@@ -1857,30 +1851,28 @@
   [7] = Reserved
   [8] = DirectCall 'dart:async::_awaitHelper', ArgDesc num-args 4, num-type-args 0, names []
   [9] = Reserved
-  [10] = InterfaceCall 'dart:core::num::==', ArgDesc num-args 2, num-type-args 0, names []
+  [10] = DirectCall 'dart:core::_AssertionError::_throwNew', ArgDesc num-args 3, num-type-args 0, names []
   [11] = Reserved
-  [12] = DirectCall 'dart:core::_AssertionError::_throwNew', ArgDesc num-args 3, num-type-args 0, names []
+  [12] = DirectCall 'dart:async::_completeOnAsyncReturn', ArgDesc num-args 2, num-type-args 0, names []
   [13] = Reserved
-  [14] = DirectCall 'dart:async::_completeOnAsyncReturn', ArgDesc num-args 2, num-type-args 0, names []
-  [15] = Reserved
-  [16] = Type dynamic
-  [17] = InterfaceCall 'dart:async::Completer::completeError', ArgDesc num-args 3, num-type-args 0, names []
-  [18] = Reserved
-  [19] = EndClosureFunctionScope
-  [20] = InstanceField dart:core::_Closure::_instantiator_type_arguments (field)
+  [14] = Type dynamic
+  [15] = InterfaceCall 'dart:async::Completer::completeError', ArgDesc num-args 3, num-type-args 0, names []
+  [16] = Reserved
+  [17] = EndClosureFunctionScope
+  [18] = InstanceField dart:core::_Closure::_instantiator_type_arguments (field)
+  [19] = Reserved
+  [20] = InstanceField dart:core::_Closure::_function_type_arguments (field)
   [21] = Reserved
-  [22] = InstanceField dart:core::_Closure::_function_type_arguments (field)
+  [22] = InstanceField dart:core::_Closure::_function (field)
   [23] = Reserved
-  [24] = InstanceField dart:core::_Closure::_function (field)
+  [24] = DirectCall 'dart:async::_asyncThenWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
   [25] = Reserved
-  [26] = DirectCall 'dart:async::_asyncThenWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
+  [26] = DirectCall 'dart:async::_asyncErrorWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
   [27] = Reserved
-  [28] = DirectCall 'dart:async::_asyncErrorWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
+  [28] = DynamicCall 'start', ArgDesc num-args 2, num-type-args 0, names []
   [29] = Reserved
-  [30] = DynamicCall 'start', ArgDesc num-args 2, num-type-args 0, names []
+  [30] = InterfaceCall 'dart:async::Completer::get:future', ArgDesc num-args 1, num-type-args 0, names []
   [31] = Reserved
-  [32] = InterfaceCall 'dart:async::Completer::get:future', ArgDesc num-args 1, num-type-args 0, names []
-  [33] = Reserved
 }
 Closure #lib::testAssert::':async_op' ([ dynamic :result, dynamic :exception, dynamic :stack_trace ]) -> dynamic
 ClosureCode {
@@ -1931,13 +1923,12 @@
   JumpIfNoAsserts      L2
   Push                 r1
   PushInt              42
-  InterfaceCall        CP#10, 2
-  AssertBoolean        0
+  CompareIntEq
   JumpIfTrue           L2
   PushInt              0
   PushInt              0
   PushNull
-  DirectCall           CP#12, 3
+  DirectCall           CP#10, 3
   Drop1
 L2:
   Push                 r4
@@ -1949,7 +1940,7 @@
   LoadContextVar       0, 1
   Push                 r4
   LoadContextVar       0, 2
-  DirectCall           CP#14, 2
+  DirectCall           CP#12, 2
   Drop1
   PushNull
   ReturnTOS
@@ -1972,7 +1963,7 @@
   LoadContextVar       0, 1
   Push                 r8
   Push                 r9
-  InterfaceCall        CP#17, 3
+  InterfaceCall        CP#15, 3
   Drop1
   Jump                 L5
 L5:
@@ -2011,7 +2002,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    dart.core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
@@ -2019,7 +2010,7 @@
         #L1:
         {
           [yield] let dynamic #t1 = dart.async::_awaitHelper(x, :async_op_then, :async_op_error, :async_op) in null;
-          :result;
+          dart._internal::unsafeCast<dart.core::int*>(:result);
         }
         dart.async::_completeOnAsyncReturn(:async_completer, :return_value);
         return;
@@ -2039,7 +2030,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    dart.core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
@@ -2066,18 +2057,18 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    dart.core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
-    dynamic :async_temporary_0;
+    dart.core::int* :async_temporary_0;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
         #L3:
         {
           [yield] let dynamic #t2 = dart.async::_awaitHelper(a, :async_op_then, :async_op_error, :async_op) in null;
-          :async_temporary_0 = :result;
+          :async_temporary_0 = dart._internal::unsafeCast<dart.core::int*>(:result);
           [yield] let dynamic #t3 = dart.async::_awaitHelper(b, :async_op_then, :async_op_error, :async_op) in null;
-          :return_value = :async_temporary_0.{dart.core::num::+}(:result);
+          :return_value = :async_temporary_0.{dart.core::num::+}(dart._internal::unsafeCast<dart.core::int*>(:result));
           break #L3;
         }
         dart.async::_completeOnAsyncReturn(:async_completer, :return_value);
@@ -2098,11 +2089,11 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    dart.core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
-    dynamic :async_temporary_0;
-    dynamic :async_temporary_1;
+    dart.core::int* :async_temporary_0;
+    dart.core::int* :async_temporary_1;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
         #L4:
@@ -2113,7 +2104,7 @@
               :async_temporary_1 = sum;
               :async_temporary_0 = i.{dart.core::num::+}(j);
               [yield] let dynamic #t4 = dart.async::_awaitHelper(#lib::foo(), :async_op_then, :async_op_error, :async_op) in null;
-              sum = :async_temporary_1.{dart.core::num::+}(:async_temporary_0.{dart.core::num::+}(:result));
+              sum = :async_temporary_1.{dart.core::num::+}(:async_temporary_0.{dart.core::num::+}(dart._internal::unsafeCast<dart.core::int*>(:result)));
             }
           }
           for (dart.core::int* k = 0; k.{dart.core::num::<}(10); k = k.{dart.core::num::+}(1)) {
@@ -2140,16 +2131,16 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    dart.core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
     dynamic :saved_try_context_var1;
     dynamic :saved_try_context_var2;
     dynamic :exception0;
     dynamic :stack_trace0;
-    dynamic :async_temporary_0;
-    dynamic :async_temporary_1;
-    dynamic :async_temporary_2;
+    dart.core::int* :async_temporary_0;
+    dart.core::int* :async_temporary_1;
+    dart.core::int* :async_temporary_2;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
       try {
         #L5:
@@ -2159,7 +2150,7 @@
             try {
               :async_temporary_0 = x;
               [yield] let dynamic #t5 = dart.async::_awaitHelper(a, :async_op_then, :async_op_error, :async_op) in null;
-              x = :async_temporary_0.{dart.core::num::+}(:result);
+              x = :async_temporary_0.{dart.core::num::+}(dart._internal::unsafeCast<dart.core::int*>(:result));
             }
             on dynamic catch(final dynamic e) {
               if(e is dart.core::Error*) {
@@ -2168,14 +2159,14 @@
               }
               :async_temporary_1 = x;
               [yield] let dynamic #t6 = dart.async::_awaitHelper(b, :async_op_then, :async_op_error, :async_op) in null;
-              x = :async_temporary_1.{dart.core::num::+}(:result);
+              x = :async_temporary_1.{dart.core::num::+}(dart._internal::unsafeCast<dart.core::int*>(:result));
               rethrow;
             }
           finally {
             dart.core::print("fin");
             :async_temporary_2 = x;
             [yield] let dynamic #t7 = dart.async::_awaitHelper(c, :async_op_then, :async_op_error, :async_op) in null;
-            x = :async_temporary_2.{dart.core::num::+}(:result);
+            x = :async_temporary_2.{dart.core::num::+}(dart._internal::unsafeCast<dart.core::int*>(:result));
             :return_value = x;
             break #L5;
           }
@@ -2200,7 +2191,7 @@
       dynamic :async_stack_trace;
       dynamic :async_op_then;
       dynamic :async_op_error;
-      dynamic :await_jump_var = 0;
+      dart.core::int* :await_jump_var = 0;
       dynamic :await_ctx_var;
       dynamic :saved_try_context_var0;
       dynamic :saved_try_context_var1;
@@ -2212,7 +2203,7 @@
             try {
               x = 5;
               [yield] let dynamic #t8 = dart.async::_awaitHelper(a, :async_op_then, :async_op_error, :async_op) in null;
-              y = :result;
+              y = dart._internal::unsafeCast<dart.core::int*>(:result);
               :return_value = x.{dart.core::num::+}(y);
               break #L6;
             }
@@ -2240,7 +2231,7 @@
     dynamic :async_stack_trace;
     dynamic :async_op_then;
     dynamic :async_op_error;
-    dynamic :await_jump_var = 0;
+    dart.core::int* :await_jump_var = 0;
     dynamic :await_ctx_var;
     dynamic :saved_try_context_var0;
     function :async_op([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding 
@@ -2249,7 +2240,7 @@
         {
           assert {
             [yield] let dynamic #t9 = dart.async::_awaitHelper(a, :async_op_then, :async_op_error, :async_op) in null;
-            assert(:result.{dart.core::num::==}(42));
+            assert(dart._internal::unsafeCast<dart.core::int*>(:result).{dart.core::num::==}(42));
           }
           :return_value = 7;
           break #L7;
diff --git a/pkg/vm/testcases/transformations/type_flow/summary_collector/bool_expressions.dart.expect b/pkg/vm/testcases/transformations/type_flow/summary_collector/bool_expressions.dart.expect
index c6072b8..96a9042 100644
--- a/pkg/vm/testcases/transformations/type_flow/summary_collector/bool_expressions.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/summary_collector/bool_expressions.dart.expect
@@ -8,13 +8,13 @@
 t0* = _Call direct [#lib::foo] ()
 t1 = _TypeCheck (t0 against dart.core::bool) (for #lib::foo() as{TypeError} dart.core::bool*)
 t2* = _Call direct [#lib::bar] ()
-t3* = _Call [dart.core::num::+] (_T (dart.core::int*)+?, _T (dart.core::_Smi))
+t3* = _Call [dart.core::num::+] (_T (dart.core::int)+?, _T (dart.core::_Smi))
 i = _Join [dart.core::int*] (_T (dart.core::_Smi), t3)
 t5* = _Call [dart.core::num::<] (i, _T (dart.core::_Smi))
 t6* = _Call direct [#lib::bar] ()
-x = _Join [dart.core::bool*] (t6, _T (dart.core::bool*)+)
+x = _Join [dart.core::bool*] (t6, _T (dart.core::bool)+)
 t8* = _Call direct [#lib::foo] ()
-t9 = _Join [dynamic] (_T (dart.core::bool*)+, t8)
+t9 = _Join [dynamic] (_T (dart.core::bool)+, t8)
 t10 = _Narrow (t9 to _T ANY?)
 t11 = _TypeCheck (t10 against dart.core::bool) (for (x{dart.core::bool*} ?{dynamic} true : #lib::foo()) as{TypeError} dart.core::bool*)
 t12* = _Call direct [#lib::bar] ()
@@ -23,7 +23,7 @@
 t15 = _TypeCheck (t14 against dart.core::bool) (for #lib::foo() as{TypeError} dart.core::bool*)
 t16* = _Call direct [#lib::foo] ()
 t17 = _TypeCheck (t16 against dart.core::bool) (for #lib::foo() as{TypeError} dart.core::bool*)
-y = _Join [dart.core::bool*] (_T (dart.core::bool*)+, t11, _T (dart.core::bool*)+, _T (dart.core::bool*)+)
+y = _Join [dart.core::bool*] (_T (dart.core::bool)+, t11, _T (dart.core::bool)+, _T (dart.core::bool)+)
 RESULT: _T {}?
 ------------ #lib::main ------------
 
diff --git a/pkg/vm/testcases/transformations/type_flow/summary_collector/calls.dart.expect b/pkg/vm/testcases/transformations/type_flow/summary_collector/calls.dart.expect
index 5f9c5dd..55cbdec 100644
--- a/pkg/vm/testcases/transformations/type_flow/summary_collector/calls.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/summary_collector/calls.dart.expect
@@ -1,39 +1,39 @@
 ------------ #lib::A:: ------------
-%this = _Parameter #0 [_T (#lib::A*)+]
+%this = _Parameter #0 [_T (#lib::A)+]
 t1 = _Call direct [dart.core::Object::] (%this)
 RESULT: _T {}?
 ------------ #lib::A::foo1 ------------
-%this = _Parameter #0 [_T (#lib::A*)+]
-%x = _Parameter #1 [_T (dart.core::Object*)+?]
+%this = _Parameter #0 [_T (#lib::A)+]
+%x = _Parameter #1 [_T (dart.core::Object)+?]
 RESULT: _T {}?
 ------------ #lib::B:: ------------
-%this = _Parameter #0 [_T (#lib::B*)+]
+%this = _Parameter #0 [_T (#lib::B)+]
 t1 = _Call direct [dart.core::Object::] (%this)
 RESULT: _T {}?
 ------------ #lib::B::bar1 ------------
-%this = _Parameter #0 [_T (#lib::B*)+]
-%arg = _Parameter #1 [_T (dart.core::Object*)+?]
+%this = _Parameter #0 [_T (#lib::B)+]
+%arg = _Parameter #1 [_T (dart.core::Object)+?]
 RESULT: _T {}?
 ------------ #lib::B::bar2 ------------
-%this = _Parameter #0 [_T (#lib::B*)+]
+%this = _Parameter #0 [_T (#lib::B)+]
 RESULT: _T {}?
 ------------ #lib::B::bar3 ------------
-%this = _Parameter #0 [_T (#lib::B*)+]
-%y = _Parameter #1 [_T (dart.core::int*)+?]
+%this = _Parameter #0 [_T (#lib::B)+]
+%y = _Parameter #1 [_T (dart.core::int)+?]
 RESULT: _T {}?
 ------------ #lib::B::bar4 ------------
-%this = _Parameter #0 [_T (#lib::B*)+]
+%this = _Parameter #0 [_T (#lib::B)+]
 RESULT: _T {}?
 ------------ #lib::C:: ------------
-%this = _Parameter #0 [_T (#lib::C*)+]
+%this = _Parameter #0 [_T (#lib::C)+]
 t1 = _Call direct [dart.core::Object::] (%this)
 RESULT: _T {}?
 ------------ #lib::C::interfaceCalls ------------
-%this = _Parameter #0 [_T (#lib::C*)+]
-%aa = _Parameter #1 [_T (#lib::A*)+?]
-%a2 = _Parameter #2 [_T (dart.core::Object*)+?]
-%a3 = _Parameter #3 [_T (dart.core::Object*)+?]
-%a4 = _Parameter #4 [_T (dart.core::Object*)+?]
+%this = _Parameter #0 [_T (#lib::C)+]
+%aa = _Parameter #1 [_T (#lib::A)+?]
+%a2 = _Parameter #2 [_T (dart.core::Object)+?]
+%a3 = _Parameter #3 [_T (dart.core::Object)+?]
+%a4 = _Parameter #4 [_T (dart.core::Object)+?]
 t5 = _Call direct [#lib::B::] (_T (#lib::B))
 t6 = _Call [#lib::A::foo1] (%aa, _T (#lib::B))
 t7* = _Call get [#lib::A::foo2] (%aa)
@@ -45,11 +45,11 @@
 a4 = _Join [dart.core::Object*] (%a4, _T ANY?)
 RESULT: a4
 ------------ #lib::C::dynamicCalls ------------
-%this = _Parameter #0 [_T (#lib::C*)+]
+%this = _Parameter #0 [_T (#lib::C)+]
 %aa = _Parameter #1 [_T ANY?]
-%a2 = _Parameter #2 [_T (dart.core::Object*)+?]
-%a3 = _Parameter #3 [_T (dart.core::Object*)+?]
-%a4 = _Parameter #4 [_T (dart.core::Object*)+?]
+%a2 = _Parameter #2 [_T (dart.core::Object)+?]
+%a3 = _Parameter #3 [_T (dart.core::Object)+?]
+%a4 = _Parameter #4 [_T (dart.core::Object)+?]
 t5 = _Call direct [#lib::B::] (_T (#lib::B))
 t6 = _Call dynamic [foo1] (%aa, _T (#lib::B))
 t7* = _Call dynamic get [foo2] (%aa)
@@ -59,15 +59,15 @@
 a4 = _Join [dart.core::Object*] (%a4, t10)
 RESULT: a4
 ------------ #lib::D:: ------------
-%this = _Parameter #0 [_T (#lib::D*)+]
+%this = _Parameter #0 [_T (#lib::D)+]
 t1 = _Call direct [#lib::B::] (%this)
 RESULT: _T {}?
 ------------ #lib::D::superCalls ------------
-%this = _Parameter #0 [_T (#lib::D*)+]
-%a1 = _Parameter #1 [_T (dart.core::Object*)+?]
-%a2 = _Parameter #2 [_T (dart.core::Object*)+?]
-%a3 = _Parameter #3 [_T (dart.core::Object*)+?]
-%a4 = _Parameter #4 [_T (dart.core::Object*)+?]
+%this = _Parameter #0 [_T (#lib::D)+]
+%a1 = _Parameter #1 [_T (dart.core::Object)+?]
+%a2 = _Parameter #2 [_T (dart.core::Object)+?]
+%a3 = _Parameter #3 [_T (dart.core::Object)+?]
+%a4 = _Parameter #4 [_T (dart.core::Object)+?]
 t5 = _Call direct [#lib::B::bar1] (%this, %a1)
 t6* = _Call direct get [#lib::B::bar4] (%this)
 t7 = _Call direct set [#lib::B::bar3] (%this, t6)
diff --git a/pkg/vm/testcases/transformations/type_flow/summary_collector/class_generics_basic.dart.expect b/pkg/vm/testcases/transformations/type_flow/summary_collector/class_generics_basic.dart.expect
index 4a9d2ed..75d7a9e 100644
--- a/pkg/vm/testcases/transformations/type_flow/summary_collector/class_generics_basic.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/summary_collector/class_generics_basic.dart.expect
@@ -1,86 +1,86 @@
 ------------ #lib::C:: ------------
-%this = _Parameter #0 [_T (#lib::C<dynamic>*)+]
+%this = _Parameter #0 [_T (#lib::C)+]
 t1 = _Call direct [dart.core::Object::] (%this)
 RESULT: _T {}?
 ------------ #lib::C::foo ------------
-%this = _Parameter #0 [_T (#lib::C<dynamic>*)+]
+%this = _Parameter #0 [_T (#lib::C)+]
 t1 = _Extract (%this[#lib::C/0])
 t2 = _CreateConcreteType (#lib::D @ (t1))
 t3 = _Call direct [#lib::D::] (t2)
 RESULT: t2
 ------------ #lib::C::id1 ------------
-%this = _Parameter #0 [_T (#lib::C<dynamic>*)+]
+%this = _Parameter #0 [_T (#lib::C)+]
 %x = _Parameter #1
 t2 = _Extract (%this[#lib::C/0])
 t3 = _TypeCheck (%x against t2) (for x)
 RESULT: t3
 ------------ #lib::C::id2 ------------
-%this = _Parameter #0 [_T (#lib::C<dynamic>*)+]
+%this = _Parameter #0 [_T (#lib::C)+]
 %x = _Parameter #1
 t2 = _Extract (%this[#lib::C/0])
 t3 = _TypeCheck (%x against t2) (for x)
 RESULT: t3
 ------------ #lib::D:: ------------
-%this = _Parameter #0 [_T (#lib::D<dynamic>*)+]
+%this = _Parameter #0 [_T (#lib::D)+]
 t1 = _Call direct [dart.core::Object::] (%this)
 RESULT: _T {}?
 ------------ #lib::E:: ------------
-%this = _Parameter #0 [_T (#lib::E<dynamic, dynamic>*)+]
+%this = _Parameter #0 [_T (#lib::E)+]
 t1 = _Call direct [#lib::C::] (%this)
 RESULT: _T {}?
 ------------ #lib::E::foo ------------
-%this = _Parameter #0 [_T (#lib::E<dynamic, dynamic>*)+]
+%this = _Parameter #0 [_T (#lib::E)+]
 t1* = _Call direct [#lib::C::foo] (%this)
 RESULT: t1
 ------------ #lib::E::bar ------------
-%this = _Parameter #0 [_T (#lib::E<dynamic, dynamic>*)+]
+%this = _Parameter #0 [_T (#lib::E)+]
 t1 = _Extract (%this[#lib::E/0])
 t2 = _CreateConcreteType (#lib::D @ (t1))
 t3 = _Call direct [#lib::D::] (t2)
 RESULT: t2
 ------------ #lib::E::baz ------------
-%this = _Parameter #0 [_T (#lib::E<dynamic, dynamic>*)+]
+%this = _Parameter #0 [_T (#lib::E)+]
 t1 = _Extract (%this[#lib::E/1])
 t2 = _CreateConcreteType (#lib::D @ (t1))
 t3 = _Call direct [#lib::D::] (t2)
 RESULT: t2
 ------------ #lib::X:: ------------
-%this = _Parameter #0 [_T (#lib::X*)+]
+%this = _Parameter #0 [_T (#lib::X)+]
 t1 = _Call direct [dart.core::Object::] (%this)
 RESULT: _T {}?
 ------------ #lib::Y:: ------------
-%this = _Parameter #0 [_T (#lib::Y*)+]
+%this = _Parameter #0 [_T (#lib::Y)+]
 t1 = _Call direct [#lib::X::] (%this)
 RESULT: _T {}?
 ------------ #lib::Z:: ------------
-%this = _Parameter #0 [_T (#lib::Z*)+]
+%this = _Parameter #0 [_T (#lib::Z)+]
 t1 = _Call direct [#lib::X::] (%this)
 RESULT: _T {}?
 ------------ #lib::I:: ------------
-%this = _Parameter #0 [_T (#lib::I<dynamic>*)+]
+%this = _Parameter #0 [_T (#lib::I)+]
 t1 = _Call direct [dart.core::Object::] (%this)
 RESULT: _T {}?
 ------------ #lib::J:: ------------
-%this = _Parameter #0 [_T (#lib::J*)+]
+%this = _Parameter #0 [_T (#lib::J)+]
 t1 = _Call direct [#lib::I::] (%this)
 RESULT: _T {}?
 ------------ #lib::K:: ------------
-%this = _Parameter #0 [_T (#lib::K<dynamic>*)+]
+%this = _Parameter #0 [_T (#lib::K)+]
 t1 = _Call direct [dart.core::Object::] (%this)
 RESULT: _T {}?
 ------------ #lib::C2:: ------------
-%this = _Parameter #0 [_T (#lib::C2<dynamic>*)+]
+%this = _Parameter #0 [_T (#lib::C2)+]
 t1 = _Call direct [dart.core::Object::] (%this)
 RESULT: _T {}?
 ------------ #lib::C2::id3 ------------
-%this = _Parameter #0 [_T (#lib::C2<dynamic>*)+]
+%this = _Parameter #0 [_T (#lib::C2)+]
 %x = _Parameter #1
 t2 = _Extract (%this[#lib::C2/0])
 t3 = _CreateRuntimeType (dart.core::Comparable @ (t2))
 t4 = _TypeCheck (%x against t3) (for x)
 RESULT: t4
 ------------ #lib::C2::id4 ------------
-%this = _Parameter #0 [_T (#lib::C2<dynamic>*)+]
+%this = _Parameter #0 [_T (#lib::C2)+]
 %x = _Parameter #1
 t2 = _Extract (%this[#lib::C2/0])
 t3 = _CreateRuntimeType (#lib::I @ (t2))
@@ -102,7 +102,7 @@
 t11 = _Call direct [#lib::Z::] (_T (#lib::Z))
 t12 = _Call [#lib::C::id2] (_T (#lib::C<#lib::Y>), _T (#lib::Z))
 t13 = _Call direct [#lib::C2::] (_T (#lib::C2<dart.core::num>))
-t14 = _Call [#lib::C2::id3] (_T (#lib::C2<dart.core::num>), _T (dart.core::double*)+)
+t14 = _Call [#lib::C2::id3] (_T (#lib::C2<dart.core::num>), _T (dart.core::double)+)
 t15 = _Call direct [#lib::K::] (_T (#lib::K<#lib::J>))
 t16 = _Call [#lib::C2::id4] (_T (#lib::C2<dart.core::num>), _T (#lib::K<#lib::J>))
 used = _Join [dynamic] (_T {}?, t1, t3, t5, t7)
diff --git a/pkg/vm/testcases/transformations/type_flow/summary_collector/class_generics_case1.dart.expect b/pkg/vm/testcases/transformations/type_flow/summary_collector/class_generics_case1.dart.expect
index 1f6fa5b..6c510f9 100644
--- a/pkg/vm/testcases/transformations/type_flow/summary_collector/class_generics_case1.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/summary_collector/class_generics_case1.dart.expect
@@ -1,5 +1,5 @@
 ------------ #lib::Element:: ------------
-%this = _Parameter #0 [_T (#lib::Element*)+]
+%this = _Parameter #0 [_T (#lib::Element)+]
 t1 = _Call direct [dart.core::Object::] (%this)
 RESULT: _T {}?
 ------------ #lib::MockHashMap:: ------------
@@ -9,11 +9,11 @@
 t3 = _Call direct [#lib::_NotRealHashMap::] (t2)
 RESULT: t2
 ------------ #lib::_NotRealHashMap:: ------------
-%this = _Parameter #0 [_T (#lib::_NotRealHashMap<dynamic, dynamic>*)+]
+%this = _Parameter #0 [_T (#lib::_NotRealHashMap)+]
 t1 = _Call direct [dart.core::Object::] (%this)
 RESULT: _T {}?
 ------------ #lib::_NotRealHashMap::setEntry ------------
-%this = _Parameter #0 [_T (#lib::_NotRealHashMap<dynamic, dynamic>*)+]
+%this = _Parameter #0 [_T (#lib::_NotRealHashMap)+]
 %key = _Parameter #1
 %value = _Parameter #2
 t3 = _Extract (%this[#lib::_NotRealHashMap/0])
@@ -22,18 +22,18 @@
 t6 = _TypeCheck (%value against t5) (for value)
 RESULT: _T {}?
 ------------ #lib::InheritedElement:: ------------
-%this = _Parameter #0 [_T (#lib::InheritedElement*)+]
+%this = _Parameter #0 [_T (#lib::InheritedElement)+]
 t1 = _Call direct [#lib::Element::] (%this)
 RESULT: _T {}?
 ------------ #lib::InheritedElement::setDependencies ------------
-%this = _Parameter #0 [_T (#lib::InheritedElement*)+]
-%dependent = _Parameter #1 [_T (#lib::Element*)+?]
-%value = _Parameter #2 [_T (dart.core::Object*)+?]
+%this = _Parameter #0 [_T (#lib::InheritedElement)+]
+%dependent = _Parameter #1 [_T (#lib::Element)+?]
+%value = _Parameter #2 [_T (dart.core::Object)+?]
 t3* = _Call virtual get [#lib::InheritedElement::_dependents] (%this)
 t4 = _Call [#lib::MockHashMap::setEntry] (t3, %dependent, %value)
 RESULT: _T {}?
 ------------ #lib::InheritedElement::_dependents ------------
-%this = _Parameter #0 [_T (#lib::InheritedElement*)+]
+%this = _Parameter #0 [_T (#lib::InheritedElement)+]
 t1* = _Call direct [#lib::MockHashMap::] (#lib::Element, dart.core::Object)
 RESULT: t1
 ------------ #lib::main ------------
diff --git a/pkg/vm/testcases/transformations/type_flow/summary_collector/constants.dart.expect b/pkg/vm/testcases/transformations/type_flow/summary_collector/constants.dart.expect
index 39e0f94..40d9eb1 100644
--- a/pkg/vm/testcases/transformations/type_flow/summary_collector/constants.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/summary_collector/constants.dart.expect
@@ -3,15 +3,15 @@
 RESULT: _T (dart.core::_Smi)
 ------------ #lib::intLiteral ------------
 
-RESULT: _T (dart.core::int*)+
+RESULT: _T (dart.core::int)+
 ------------ #lib::strLiteral ------------
 
 RESULT: _T (dart.core::_OneByteString)
 ------------ #lib::indexingIntoConstantList1 ------------
-%i = _Parameter #0 [_T (dart.core::int*)+?]
+%i = _Parameter #0 [_T (dart.core::int)+?]
 RESULT: _T (dart.core::_Smi)
 ------------ #lib::indexingIntoConstantList2 ------------
-%i = _Parameter #0 [_T (dart.core::int*)+?]
+%i = _Parameter #0 [_T (dart.core::int)+?]
 t1 = _Join [dart.core::Object*] (_T (dart.core::_OneByteString), _T (dart.core::_Smi), _T {}?)
 RESULT: t1
 ------------ #lib::main ------------
diff --git a/pkg/vm/testcases/transformations/type_flow/summary_collector/hello.dart.expect b/pkg/vm/testcases/transformations/type_flow/summary_collector/hello.dart.expect
index 5488d3d..31ccb74 100644
--- a/pkg/vm/testcases/transformations/type_flow/summary_collector/hello.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/summary_collector/hello.dart.expect
@@ -1,4 +1,4 @@
 ------------ #lib::main ------------
-%args = _Parameter #0 [_T (dart.core::List<dynamic>*)+?]
+%args = _Parameter #0 [_T (dart.core::List)+?]
 t1 = _Call direct [dart.core::print] (_T (dart.core::_OneByteString))
 RESULT: _T {}?
diff --git a/pkg/vm/testcases/transformations/type_flow/summary_collector/implicit_return_null.dart.expect b/pkg/vm/testcases/transformations/type_flow/summary_collector/implicit_return_null.dart.expect
index 0546dec..9a3e510 100644
--- a/pkg/vm/testcases/transformations/type_flow/summary_collector/implicit_return_null.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/summary_collector/implicit_return_null.dart.expect
@@ -1,5 +1,5 @@
 ------------ #lib::T:: ------------
-%this = _Parameter #0 [_T (#lib::T*)+]
+%this = _Parameter #0 [_T (#lib::T)+]
 t1 = _Call direct [dart.core::Object::] (%this)
 RESULT: _T {}?
 ------------ #lib::empty1 ------------
@@ -18,7 +18,7 @@
 t0 = _Call direct [#lib::T::] (_T (#lib::T))
 RESULT: _T (#lib::T)
 ------------ #lib::return2 ------------
-%i = _Parameter #0 [_T (dart.core::int*)+?]
+%i = _Parameter #0 [_T (dart.core::int)+?]
 t1* = _Call [dart.core::num::-] (%i, _T (dart.core::_Smi))
 t2* = _Call direct [#lib::return2] (t1)
 RESULT: t2
@@ -32,77 +32,77 @@
 t0 = _Call direct [#lib::T::] (_T (#lib::T))
 RESULT: _T {}?
 ------------ #lib::expr2 ------------
-%c = _Parameter #0 [_T (dart.core::bool*)+?]
+%c = _Parameter #0 [_T (dart.core::bool)+?]
 t1 = _Call direct [#lib::T::] (_T (#lib::T))
 t2 = _Call direct [#lib::T::] (_T (#lib::T))
 %result = _Join [dynamic] (_T (#lib::T), _T {}?)
 RESULT: %result
 ------------ #lib::expr3 ------------
-%c = _Parameter #0 [_T (dart.core::bool*)+?]
-%x = _Parameter #1 [_T (dart.core::Object*)+?]
+%c = _Parameter #0 [_T (dart.core::bool)+?]
+%x = _Parameter #1 [_T (dart.core::Object)+?]
 t2 = _Call direct [#lib::T::] (_T (#lib::T))
 t3 = _Call [dart.core::Object::toString] (%x)
 %result = _Join [dynamic] (_T (#lib::T), _T {}?)
 RESULT: %result
 ------------ #lib::throw1 ------------
-%c = _Parameter #0 [_T (dart.core::bool*)+?]
-%x = _Parameter #1 [_T (dart.core::Object*)+?]
+%c = _Parameter #0 [_T (dart.core::bool)+?]
+%x = _Parameter #1 [_T (dart.core::Object)+?]
 RESULT: _T {}
 ------------ #lib::throw2 ------------
-%c = _Parameter #0 [_T (dart.core::bool*)+?]
-%x = _Parameter #1 [_T (dart.core::Object*)+?]
+%c = _Parameter #0 [_T (dart.core::bool)+?]
+%x = _Parameter #1 [_T (dart.core::Object)+?]
 t2 = _Call direct [#lib::T::] (_T (#lib::T))
 RESULT: _T (#lib::T)
 ------------ #lib::loop1 ------------
-%c = _Parameter #0 [_T (dart.core::bool*)+?]
-%x = _Parameter #1 [_T (dart.core::Object*)+?]
+%c = _Parameter #0 [_T (dart.core::bool)+?]
+%x = _Parameter #1 [_T (dart.core::Object)+?]
 RESULT: _T {}?
 ------------ #lib::loop2 ------------
-%c = _Parameter #0 [_T (dart.core::bool*)+?]
-%x = _Parameter #1 [_T (dart.core::Object*)+?]
+%c = _Parameter #0 [_T (dart.core::bool)+?]
+%x = _Parameter #1 [_T (dart.core::Object)+?]
 t2 = _Call direct [#lib::T::] (_T (#lib::T))
 %result = _Join [dynamic] (_T (#lib::T), _T {}?)
 RESULT: %result
 ------------ #lib::loop3 ------------
-%c = _Parameter #0 [_T (dart.core::bool*)+?]
-%x = _Parameter #1 [_T (dart.core::Object*)+?]
+%c = _Parameter #0 [_T (dart.core::bool)+?]
+%x = _Parameter #1 [_T (dart.core::Object)+?]
 t2 = _Call direct [#lib::T::] (_T (#lib::T))
 %result = _Join [dynamic] (_T (#lib::T), _T {}?)
 RESULT: %result
 ------------ #lib::switch_ ------------
-%c = _Parameter #0 [_T (dart.core::bool*)+?]
-%i = _Parameter #1 [_T (dart.core::int*)+?]
+%c = _Parameter #0 [_T (dart.core::bool)+?]
+%i = _Parameter #1 [_T (dart.core::int)+?]
 t2 = _Call direct [#lib::T::] (_T (#lib::T))
 %result = _Join [dynamic] (_T (#lib::T), _T {}?)
 RESULT: %result
 ------------ #lib::if1 ------------
-%c = _Parameter #0 [_T (dart.core::bool*)+?]
+%c = _Parameter #0 [_T (dart.core::bool)+?]
 t1 = _Call direct [#lib::T::] (_T (#lib::T))
 RESULT: _T (#lib::T)
 ------------ #lib::if2 ------------
-%c = _Parameter #0 [_T (dart.core::bool*)+?]
+%c = _Parameter #0 [_T (dart.core::bool)+?]
 t1 = _Call direct [#lib::T::] (_T (#lib::T))
 %result = _Join [dynamic] (_T (#lib::T), _T {}?)
 RESULT: %result
 ------------ #lib::if3 ------------
-%c = _Parameter #0 [_T (dart.core::bool*)+?]
+%c = _Parameter #0 [_T (dart.core::bool)+?]
 RESULT: _T {}?
 ------------ #lib::if4 ------------
-%c = _Parameter #0 [_T (dart.core::bool*)+?]
+%c = _Parameter #0 [_T (dart.core::bool)+?]
 RESULT: _T {}?
 ------------ #lib::if5 ------------
-%c = _Parameter #0 [_T (dart.core::bool*)+?]
+%c = _Parameter #0 [_T (dart.core::bool)+?]
 t1* = _Call direct [#lib::if5] (%c)
-t2* = _Call direct [#lib::if5] (_T (dart.core::bool*)+)
+t2* = _Call direct [#lib::if5] (_T (dart.core::bool)+)
 %result = _Join [void] (t1, t2, _T {}?)
 RESULT: %result
 ------------ #lib::label1 ------------
-%c = _Parameter #0 [_T (dart.core::bool*)+?]
+%c = _Parameter #0 [_T (dart.core::bool)+?]
 t1 = _Call direct [#lib::T::] (_T (#lib::T))
 %result = _Join [dynamic] (_T (#lib::T), _T {}?)
 RESULT: %result
 ------------ #lib::try1 ------------
-%c = _Parameter #0 [_T (dart.core::bool*)+?]
+%c = _Parameter #0 [_T (dart.core::bool)+?]
 t1 = _Call direct [#lib::T::] (_T (#lib::T))
 %result = _Join [dynamic] (_T (#lib::T), _T {}?)
 RESULT: %result
@@ -114,7 +114,7 @@
 t0 = _Call direct [#lib::T::] (_T (#lib::T))
 RESULT: _T (#lib::T)
 ------------ #lib::try4 ------------
-%c = _Parameter #0 [_T (dart.core::bool*)+?]
+%c = _Parameter #0 [_T (dart.core::bool)+?]
 t1 = _Call direct [#lib::T::] (_T (#lib::T))
 %result = _Join [dynamic] (_T (#lib::T), _T {}?)
 RESULT: %result
@@ -125,7 +125,7 @@
 t0 = _Call direct [#lib::T::] (_T (#lib::T))
 RESULT: _T (#lib::T)
 ------------ #lib::try7 ------------
-%c = _Parameter #0 [_T (dart.core::bool*)+?]
+%c = _Parameter #0 [_T (dart.core::bool)+?]
 t1 = _Call direct [#lib::T::] (_T (#lib::T))
 RESULT: _T (#lib::T)
 ------------ #lib::main ------------
diff --git a/pkg/vm/testcases/transformations/type_flow/summary_collector/setter_result.dart.expect b/pkg/vm/testcases/transformations/type_flow/summary_collector/setter_result.dart.expect
index ceb6d33..e79a010 100644
--- a/pkg/vm/testcases/transformations/type_flow/summary_collector/setter_result.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/summary_collector/setter_result.dart.expect
@@ -1,43 +1,43 @@
 ------------ #lib::T:: ------------
-%this = _Parameter #0 [_T (#lib::T*)+]
+%this = _Parameter #0 [_T (#lib::T)+]
 t1 = _Call direct [dart.core::Object::] (%this)
 RESULT: _T {}?
 ------------ #lib::A:: ------------
-%this = _Parameter #0 [_T (#lib::A*)+]
+%this = _Parameter #0 [_T (#lib::A)+]
 t1 = _Call direct [dart.core::Object::] (%this)
 RESULT: _T {}?
 ------------ #lib::A::foo ------------
-%this = _Parameter #0 [_T (#lib::A*)+]
+%this = _Parameter #0 [_T (#lib::A)+]
 RESULT: _T {}?
 ------------ #lib::B:: ------------
-%this = _Parameter #0 [_T (#lib::B*)+]
+%this = _Parameter #0 [_T (#lib::B)+]
 t1 = _Call direct [#lib::A::] (%this)
 RESULT: _T {}?
 ------------ #lib::B::foo ------------
-%this = _Parameter #0 [_T (#lib::B*)+]
+%this = _Parameter #0 [_T (#lib::B)+]
 %x = _Parameter #1 [_T ANY?]
 RESULT: _T {}?
 ------------ #lib::B::testPropertySet ------------
-%this = _Parameter #0 [_T (#lib::B*)+]
+%this = _Parameter #0 [_T (#lib::B)+]
 %x = _Parameter #1 [_T ANY?]
 t2 = _Call virtual set [#lib::B::foo] (%this, %x)
 t3 = _Call direct [#lib::use] (%x)
 RESULT: _T {}?
 ------------ #lib::B::testDynamicPropertySet ------------
-%this = _Parameter #0 [_T (#lib::B*)+]
+%this = _Parameter #0 [_T (#lib::B)+]
 %x = _Parameter #1 [_T ANY?]
 %y = _Parameter #2 [_T ANY?]
 t3 = _Call dynamic set [foo] (%x, %y)
 t4 = _Call direct [#lib::use] (%y)
 RESULT: _T {}?
 ------------ #lib::B::testSuperPropertySet ------------
-%this = _Parameter #0 [_T (#lib::B*)+]
+%this = _Parameter #0 [_T (#lib::B)+]
 %x = _Parameter #1 [_T ANY?]
 t2 = _Call direct set [#lib::A::foo] (%this, %x)
 t3 = _Call direct [#lib::use] (%x)
 RESULT: _T {}?
 ------------ #lib::B::testStaticPropertySet ------------
-%this = _Parameter #0 [_T (#lib::B*)+]
+%this = _Parameter #0 [_T (#lib::B)+]
 %x = _Parameter #1 [_T ANY?]
 t2 = _Call direct set [#lib::B::bar] (%x)
 t3 = _Call direct [#lib::use] (%x)
diff --git a/pkg/vm/testcases/transformations/type_flow/summary_collector/vars.dart.expect b/pkg/vm/testcases/transformations/type_flow/summary_collector/vars.dart.expect
index 81dbe5b..107564e 100644
--- a/pkg/vm/testcases/transformations/type_flow/summary_collector/vars.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/summary_collector/vars.dart.expect
@@ -1,14 +1,14 @@
 ------------ #lib::A:: ------------
-%this = _Parameter #0 [_T (#lib::A*)+]
+%this = _Parameter #0 [_T (#lib::A)+]
 t1 = _Call direct [dart.core::Object::] (%this)
 RESULT: _T {}?
 ------------ #lib::B:: ------------
-%this = _Parameter #0 [_T (#lib::B*)+]
+%this = _Parameter #0 [_T (#lib::B)+]
 t1 = _Call direct [dart.core::Object::] (%this)
 RESULT: _T {}?
 ------------ #lib::foo ------------
-%a1 = _Parameter #0 [_T (dart.core::Object*)+?]
-%a2 = _Parameter #1 [_T (dart.core::Object*)+?]
+%a1 = _Parameter #0 [_T (dart.core::Object)+?]
+%a2 = _Parameter #1 [_T (dart.core::Object)+?]
 t2* = _Call direct get [#lib::someStatic] ()
 t3 = _Call direct [#lib::A::] (_T (#lib::A))
 a1 = _Join [dart.core::Object*] (%a1, _T (#lib::A), _T (#lib::B))
@@ -16,29 +16,29 @@
 t6 = _Call direct [#lib::B::] (_T (#lib::B))
 t7* = _Call [dart.core::Object::==] (a1, %a2)
 t8 = _Join [dart.core::Object*] (a1, %a2)
-t9 = _Narrow (t8 to _T (dart.core::Object*)+?)
+t9 = _Narrow (t8 to _T (dart.core::Object)+?)
 RESULT: t9
 ------------ #lib::bar ------------
-%a1 = _Parameter #0 [_T (dart.core::Object*)+?]
-%a2 = _Parameter #1 [_T (dart.core::int*)+?]
-t2 = _Narrow (%a1 to _T (dart.core::int*)+)
+%a1 = _Parameter #0 [_T (dart.core::Object)+?]
+%a2 = _Parameter #1 [_T (dart.core::int)+?]
+t2 = _Narrow (%a1 to _T (dart.core::int)+)
 t3* = _Call [dart.core::num::+] (t2, %a2)
 t4* = _Call [dart.core::num::*] (t3, _T (dart.core::_Smi))
 t5* = _Call [dart.core::int::unary-] (_T (dart.core::_Smi))
 %result = _Join [dart.core::int*] (t4, t5)
 RESULT: %result
 ------------ #lib::loop1 ------------
-%a1 = _Parameter #0 [_T (dart.core::Object*)+?]
-%a2 = _Parameter #1 [_T (dart.core::Object*)+?]
-t2* = _Call direct [#lib::loop1] (_T (dart.core::Object*)+?, %a1)
+%a1 = _Parameter #0 [_T (dart.core::Object)+?]
+%a2 = _Parameter #1 [_T (dart.core::Object)+?]
+t2* = _Call direct [#lib::loop1] (_T (dart.core::Object)+?, %a1)
 x = _Join [dart.core::Object*] (%a1, t2, %a2)
 RESULT: x
 ------------ #lib::loop2 ------------
-%x = _Parameter #0 [_T (dart.core::int*)+?]
-t1* = _Call [dart.core::num::+] (_T (dart.core::int*)+?, _T (dart.core::_Smi))
+%x = _Parameter #0 [_T (dart.core::int)+?]
+t1* = _Call [dart.core::num::+] (_T (dart.core::int)+?, _T (dart.core::_Smi))
 i = _Join [dart.core::int*] (_T (dart.core::_Smi), t1)
 t3* = _Call [dart.core::num::<] (i, _T (dart.core::_Smi))
-t4* = _Call [dart.core::num::+] (_T (dart.core::int*)+?, _T (dart.core::_Smi))
+t4* = _Call [dart.core::num::+] (_T (dart.core::int)+?, _T (dart.core::_Smi))
 x = _Join [dart.core::int*] (%x, t4)
 RESULT: x
 ------------ #lib::main ------------
diff --git a/pkg/vm_service/README.md b/pkg/vm_service/README.md
index a87d2bc..11194fd 100644
--- a/pkg/vm_service/README.md
+++ b/pkg/vm_service/README.md
@@ -1,6 +1,6 @@
 # vm_service
 
-[![pub package](https://img.shields.io/pub/v/vm_service.svg)](https://pub.dartlang.org/packages/vm_service)
+[![pub package](https://img.shields.io/pub/v/vm_service.svg)](https://pub.dev/packages/vm_service)
 
 A library to access the VM Service Protocol.
 
diff --git a/runtime/bin/BUILD.gn b/runtime/bin/BUILD.gn
index 4933877..50a049d 100644
--- a/runtime/bin/BUILD.gn
+++ b/runtime/bin/BUILD.gn
@@ -540,7 +540,9 @@
   ]
   args = []
   if (use_nnbd) {
-    args += [ "--enable-experiment=non-nullable" ]
+    # TODO(sigmund): reenable this flag once the CFE can build targets without
+    # issues.
+    # args += [ "--enable-experiment=non-nullable" ]
   }
   args += [
     "--deterministic",
diff --git a/runtime/bin/vmservice/loader.dart b/runtime/bin/vmservice/loader.dart
index a450179..7407e50 100644
--- a/runtime/bin/vmservice/loader.dart
+++ b/runtime/bin/vmservice/loader.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.
 
+// @dart = 2.6
+
 part of vmservice_io;
 
 _sanitizeWindowsPath(path) {
diff --git a/runtime/bin/vmservice/server.dart b/runtime/bin/vmservice/server.dart
index f4cfc6a..88ee8fe 100644
--- a/runtime/bin/vmservice/server.dart
+++ b/runtime/bin/vmservice/server.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.
 
+// @dart = 2.6
+
 part of vmservice_io;
 
 final bool silentObservatory = new bool.fromEnvironment('SILENT_OBSERVATORY');
diff --git a/runtime/bin/vmservice/vmservice_io.dart b/runtime/bin/vmservice/vmservice_io.dart
index 393f1f3..4ed2f63 100644
--- a/runtime/bin/vmservice/vmservice_io.dart
+++ b/runtime/bin/vmservice/vmservice_io.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.
 
+// @dart = 2.6
+
 library vmservice_io;
 
 import 'dart:async';
diff --git a/runtime/docs/aot_binary_size_analysis.md b/runtime/docs/aot_binary_size_analysis.md
index 71e66fc..160b03d 100644
--- a/runtime/docs/aot_binary_size_analysis.md
+++ b/runtime/docs/aot_binary_size_analysis.md
@@ -17,6 +17,12 @@
 % pkg/vm/tool/precompiler2 --print-instructions-sizes-to=hello_sizes.json hello.dart hello.dart.aot
 ```
 
+In Flutter, pass this argument to `flutter build`:
+
+```
+% flutter build aot --release --extra-gen-snapshot-options=--print-instructions-sizes-to=hello_sizes.json
+```
+
 ## Visualizing the information from the binary size json file
 
 To visualize the information emitted by the AOT compiler one can use our binary
@@ -42,3 +48,25 @@
 +---------+--------+--------------+
 ...
 ```
+
+## Object-level data
+
+gen_snapshot also accepts an extra `--write-v8-snapshot-profile-to=hello.heapsnapshot`
+flag. If supplied the AOT compiler will emit snapshot size information for all objects in the snapshot
+to `sizes.json` in V8 snapshot format.
+
+This flag can be passed to `gen_snapshot` directly, or to the various wrapper
+scripts (e.g. `pkg/vm/tool/precompiler2`):
+
+```
+% tools/build.py -mrelease -ax64 runtime_kernel dart_precompiled_runtime
+% pkg/vm/tool/precompiler2 --write-v8-snapshot-profile-to=hello.heapsnapshot hello.dart hello.dart.aot
+```
+
+In Flutter, pass this argument to `flutter build`:
+
+```
+% flutter build aot --release --extra-gen-snapshot-options=--write-v8-snapshot-profile-to=hello.heapsnapshot
+```
+
+This output can be visualized by loading it in the "Memory" tab in Chrome's developer tools, or by loading it into [Graph Explorer](../tools/graphexplorer/graphexplorer.html).
diff --git a/runtime/lib/ffi.cc b/runtime/lib/ffi.cc
index 355d1e3..9a7b24e 100644
--- a/runtime/lib/ffi.cc
+++ b/runtime/lib/ffi.cc
@@ -277,7 +277,8 @@
 
   auto& new_value_type =
       AbstractType::Handle(zone, new_value.GetType(Heap::kNew));
-  if (!new_value_type.IsSubtypeOf(pointer_type_arg, Heap::kNew)) {
+  if (!new_value_type.IsSubtypeOf(NNBDMode::kLegacy, pointer_type_arg,
+                                  Heap::kNew)) {
     const String& error = String::Handle(String::NewFormatted(
         "New value (%s) is not a subtype of '%s'.",
         String::Handle(new_value_type.UserVisibleName()).ToCString(),
diff --git a/runtime/lib/isolate.cc b/runtime/lib/isolate.cc
index 058f2ec..465c84f 100644
--- a/runtime/lib/isolate.cc
+++ b/runtime/lib/isolate.cc
@@ -28,11 +28,6 @@
 
 namespace dart {
 
-DEFINE_FLAG(bool,
-            enable_isolate_groups,
-            true,
-            "Whether to enable support for isolate groups.");
-
 DEFINE_NATIVE_ENTRY(CapabilityImpl_factory, 0, 1) {
   ASSERT(
       TypeArguments::CheckedHandle(zone, arguments->NativeArgAt(0)).IsNull());
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc
index 9c8f617..9a1ca57 100644
--- a/runtime/lib/mirrors.cc
+++ b/runtime/lib/mirrors.cc
@@ -633,16 +633,17 @@
     // TODO(regis): Until mirrors reflect nullability, force kLegacy, except for
     // Null type, which should remain nullable.
     if (!type.IsNullType()) {
-      const Type& legacy_type =
-          Type::Handle(Type::Cast(type).ToNullability(kLegacy, Heap::kOld));
+      const Type& legacy_type = Type::Handle(
+          Type::Cast(type).ToNullability(Nullability::kLegacy, Heap::kOld));
       return CreateClassMirror(cls, legacy_type, Bool::False(),
                                Object::null_instance());
     }
     return CreateClassMirror(cls, type, Bool::False(), Object::null_instance());
   } else if (type.IsTypeParameter()) {
     // TODO(regis): Until mirrors reflect nullability, force kLegacy.
-    const TypeParameter& legacy_type = TypeParameter::Handle(
-        TypeParameter::Cast(type).ToNullability(kLegacy, Heap::kOld));
+    const TypeParameter& legacy_type =
+        TypeParameter::Handle(TypeParameter::Cast(type).ToNullability(
+            Nullability::kLegacy, Heap::kOld));
     return CreateTypeVariableMirror(legacy_type, Object::null_instance());
   }
   UNREACHABLE();
@@ -710,8 +711,8 @@
     instantiator_type_args = instantiator.arguments();
   }
   AbstractType& result = AbstractType::Handle(type.InstantiateFrom(
-      instantiator_type_args, Object::null_type_arguments(), kAllFree, NULL,
-      Heap::kOld));
+      NNBDMode::kLegacy, instantiator_type_args, Object::null_type_arguments(),
+      kAllFree, NULL, Heap::kOld));
   ASSERT(result.IsFinalized());
   return result.Canonicalize();
 }
@@ -1480,8 +1481,8 @@
       // type arguments of the type reflected by the class mirror.
       ASSERT(redirect_type.IsInstantiated(kFunctions));
       redirect_type ^= redirect_type.InstantiateFrom(
-          type_arguments, Object::null_type_arguments(), kNoneFree, NULL,
-          Heap::kOld);
+          NNBDMode::kLegacy, type_arguments, Object::null_type_arguments(),
+          kNoneFree, NULL, Heap::kOld);
       redirect_type ^= redirect_type.Canonicalize();
     }
 
@@ -1510,7 +1511,8 @@
       ArgumentsDescriptor::New(kTypeArgsLen, args.Length(), arg_names));
 
   ArgumentsDescriptor args_descriptor(args_descriptor_array);
-  if (!redirected_constructor.AreValidArguments(args_descriptor, NULL)) {
+  if (!redirected_constructor.AreValidArguments(NNBDMode::kLegacy,
+                                                args_descriptor, NULL)) {
     external_constructor_name = redirected_constructor.name();
     ThrowNoSuchMethod(AbstractType::Handle(klass.RareType()),
                       external_constructor_name, explicit_args, arg_names,
@@ -1520,7 +1522,7 @@
   }
   const Object& type_error =
       Object::Handle(redirected_constructor.DoArgumentTypesMatch(
-          args, args_descriptor, type_arguments));
+          NNBDMode::kLegacy, args, args_descriptor, type_arguments));
   if (!type_error.IsNull()) {
     Exceptions::PropagateError(Error::Cast(type_error));
     UNREACHABLE();
@@ -1758,7 +1760,7 @@
 DEFINE_NATIVE_ENTRY(TypeMirror_subtypeTest, 0, 2) {
   GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, a, arguments->NativeArgAt(0));
   GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, b, arguments->NativeArgAt(1));
-  return Bool::Get(a.IsSubtypeOf(b, Heap::kNew)).raw();
+  return Bool::Get(a.IsSubtypeOf(NNBDMode::kLegacy, b, Heap::kNew)).raw();
 }
 
 #endif  // !DART_PRECOMPILED_RUNTIME
diff --git a/runtime/lib/object.cc b/runtime/lib/object.cc
index 7d40155..c7b78de 100644
--- a/runtime/lib/object.cc
+++ b/runtime/lib/object.cc
@@ -141,8 +141,9 @@
   const AbstractType& type =
       AbstractType::CheckedHandle(zone, arguments->NativeArgAt(3));
   ASSERT(type.IsFinalized());
-  const bool is_instance_of = instance.IsInstanceOf(
-      type, instantiator_type_arguments, function_type_arguments);
+  const bool is_instance_of = instance.IsInstanceOf(NNBDMode::kLegacy, type,
+                                                    instantiator_type_arguments,
+                                                    function_type_arguments);
   if (FLAG_trace_type_checks) {
     const char* result_str = is_instance_of ? "true" : "false";
     OS::PrintErr("Native Object.instanceOf: result %s\n", result_str);
@@ -166,7 +167,8 @@
   ASSERT(type.IsFinalized());
   ASSERT(type.IsInstantiated());
   const bool is_instance_of = instance.IsInstanceOf(
-      type, Object::null_type_arguments(), Object::null_type_arguments());
+      NNBDMode::kLegacy, type, Object::null_type_arguments(),
+      Object::null_type_arguments());
   return Bool::Get(is_instance_of).raw();
 }
 
@@ -223,8 +225,8 @@
       if (!cur_interface_type_args.IsNull() &&
           !cur_interface_type_args.IsInstantiated()) {
         cur_interface_type_args = cur_interface_type_args.InstantiateFrom(
-            instance_type_args, Object::null_type_arguments(), kNoneFree, NULL,
-            Heap::kNew);
+            NNBDMode::kLegacy, instance_type_args,
+            Object::null_type_arguments(), kNoneFree, NULL, Heap::kNew);
       }
       if (ExtractInterfaceTypeArgs(zone, cur_interface_cls,
                                    cur_interface_type_args, interface_cls,
@@ -378,7 +380,8 @@
 
     // The supertype may not be instantiated.
     if (!AbstractType::InstantiateAndTestSubtype(
-            &subtype, &supertype, instantiator_type_args, function_type_args)) {
+            NNBDMode::kLegacy, &subtype, &supertype, instantiator_type_args,
+            function_type_args)) {
       // Throw a dynamic type error.
       TokenPosition location;
       {
diff --git a/runtime/lib/stacktrace.cc b/runtime/lib/stacktrace.cc
index 1b9600a..1df0056 100644
--- a/runtime/lib/stacktrace.cc
+++ b/runtime/lib/stacktrace.cc
@@ -23,7 +23,7 @@
 
   // Determine how big the stack trace is.
   const intptr_t stack_trace_length =
-      StackTraceUtils::CountFrames(thread, skip_frames, null_function);
+      StackTraceUtils::CountFrames(thread, skip_frames, null_function, nullptr);
 
   // Allocate once.
   const Array& code_array =
@@ -64,8 +64,9 @@
 
   // Determine the size of the stack trace.
   const intptr_t extra_frames = for_async_function ? 1 : 0;
-  const intptr_t synchronous_stack_trace_length =
-      StackTraceUtils::CountFrames(thread, skip_frames, async_function);
+  bool sync_async_end = false;
+  const intptr_t synchronous_stack_trace_length = StackTraceUtils::CountFrames(
+      thread, skip_frames, async_function, &sync_async_end);
 
   const intptr_t capacity = synchronous_stack_trace_length +
                             extra_frames;  // For the asynchronous gap.
@@ -94,7 +95,11 @@
 
   ASSERT(write_cursor == capacity);
 
-  return StackTrace::New(code_array, pc_offset_array, async_stack_trace);
+  const StackTrace& result = StackTrace::Handle(
+      zone, StackTrace::New(code_array, pc_offset_array, async_stack_trace,
+                            sync_async_end));
+
+  return result.raw();
 }
 
 RawStackTrace* GetStackTraceForException() {
diff --git a/runtime/observatory/lib/src/allocation_profile/allocation_profile.dart b/runtime/observatory/lib/src/allocation_profile/allocation_profile.dart
index fa64125..c1e7aa1 100644
--- a/runtime/observatory/lib/src/allocation_profile/allocation_profile.dart
+++ b/runtime/observatory/lib/src/allocation_profile/allocation_profile.dart
@@ -11,6 +11,7 @@
   final DateTime lastAccumulatorReset;
   final S.HeapSpace newSpace;
   final S.HeapSpace oldSpace;
+  final S.HeapSpace totalSpace;
   final Iterable<M.ClassHeapStats> members;
 
   AllocationProfile(S.ServiceMap map, {Map/*<String, List<String>>*/ defaults})
@@ -18,7 +19,11 @@
         lastServiceGC = _intString2DateTime(map[_lastServiceGC]),
         oldSpace = new S.HeapSpace()..update(map['_heaps']['old']),
         newSpace = new S.HeapSpace()..update(map['_heaps']['new']),
-        members = _convertMembers(map['members'], defaults: defaults);
+        totalSpace = new S.HeapSpace(),
+        members = _convertMembers(map['members'], defaults: defaults) {
+    totalSpace.add(oldSpace);
+    totalSpace.add(newSpace);
+  }
 
   static DateTime _intString2DateTime(String milliseconds) {
     if ((milliseconds == null) || milliseconds == '') {
@@ -66,15 +71,11 @@
   final String displayName = null;
   final S.Allocations newSpace;
   final S.Allocations oldSpace;
-  final int promotedInstances;
-  final int promotedBytes;
 
   ClassHeapStats(Map map)
       : clazz = map['class'],
         oldSpace = new S.Allocations()..update(map['_old']),
-        newSpace = new S.Allocations()..update(map['_new']),
-        promotedInstances = map['_promotedInstances'],
-        promotedBytes = map['_promotedBytes'];
+        newSpace = new S.Allocations()..update(map['_new']);
 }
 
 class ClassesHeapStats implements M.ClassHeapStats {
@@ -82,12 +83,8 @@
   final String displayName;
   final S.Allocations newSpace;
   final S.Allocations oldSpace;
-  final int promotedInstances;
-  final int promotedBytes;
 
   ClassesHeapStats(this.displayName, Iterable<ClassHeapStats> classes)
       : oldSpace = new S.Allocations()..combine(classes.map((m) => m.oldSpace)),
-        newSpace = new S.Allocations()..combine(classes.map((m) => m.newSpace)),
-        promotedInstances = classes.fold(0, (v, m) => v + m.promotedInstances),
-        promotedBytes = classes.fold(0, (v, m) => v + m.promotedBytes);
+        newSpace = new S.Allocations()..combine(classes.map((m) => m.newSpace));
 }
diff --git a/runtime/observatory/lib/src/elements/allocation_profile.dart b/runtime/observatory/lib/src/elements/allocation_profile.dart
index b4ddc92..d589289 100644
--- a/runtime/observatory/lib/src/elements/allocation_profile.dart
+++ b/runtime/observatory/lib/src/elements/allocation_profile.dart
@@ -21,18 +21,18 @@
 import 'package:observatory/utils.dart';
 
 enum _SortingField {
-  accumulatedSize,
-  accumulatedInstances,
-  currentSize,
-  currentInstances,
-  newAccumulatedSize,
-  newAccumulatedInstances,
-  newCurrentSize,
-  newCurrentInstances,
-  oldAccumulatedSize,
-  oldAccumulatedInstances,
-  oldCurrentSize,
-  oldCurrentInstances,
+  newInstances,
+  newInternalSize,
+  newExternalSize,
+  newSize,
+  oldInstances,
+  oldInternalSize,
+  oldExternalSize,
+  oldSize,
+  instances,
+  internalSize,
+  externalSize,
+  size,
   className,
 }
 
@@ -64,7 +64,7 @@
   bool _autoRefresh = false;
   bool _isCompacted = false;
   StreamSubscription _gcSubscription;
-  _SortingField _sortingField = _SortingField.currentSize;
+  _SortingField _sortingField = _SortingField.size;
   _SortingDirection _sortingDirection = _SortingDirection.descending;
 
   M.VMRef get vm => _vm;
@@ -126,9 +126,6 @@
                 label: 'Download', disabled: _profile == null, queue: _r.queue)
               ..onRefresh.listen((_) => _downloadCSV()))
             .element,
-        (new NavRefreshElement(label: 'Reset Accumulator', queue: _r.queue)
-              ..onRefresh.listen((_) => _refresh(reset: true)))
-            .element,
         (new NavRefreshElement(label: 'GC', queue: _r.queue)
               ..onRefresh.listen((_) => _refresh(gc: true)))
             .element,
@@ -166,6 +163,8 @@
       final newChartLegend = new DivElement()..classes = ['legend'];
       final oldChartHost = new DivElement()..classes = ['host'];
       final oldChartLegend = new DivElement()..classes = ['legend'];
+      final totalChartHost = new DivElement()..classes = ['host'];
+      final totalChartLegend = new DivElement()..classes = ['legend'];
       children.addAll([
         new DivElement()
           ..classes = ['content-centered-big']
@@ -187,18 +186,6 @@
                                 ? '---'
                                 : '${_profile.lastServiceGC}',
                         ],
-                      new DivElement()
-                        ..classes = ['memberItem']
-                        ..children = <Element>[
-                          new DivElement()
-                            ..classes = ['memberName']
-                            ..text = 'last accumulator reset at',
-                          new DivElement()
-                            ..classes = ['memberValue']
-                            ..text = _profile.lastAccumulatorReset == null
-                                ? '---'
-                                : '${_profile.lastAccumulatorReset}',
-                        ]
                     ],
                   new HRElement(),
                 ],
@@ -225,12 +212,12 @@
                         ..children = <Element>[newChartLegend, newChartHost]
                     ],
             new DivElement()
-              ..classes = ['heap-space', 'right']
+              ..classes = ['heap-space', 'left']
               ..children = _isCompacted
                   ? [
                       new HeadingElement.h2()
-                        ..text = '(${_usedCaption(_profile.oldSpace)}) '
-                            'Old Generation',
+                        ..text = 'Old Generation '
+                            '(${_usedCaption(_profile.oldSpace)})',
                     ]
                   : [
                       new HeadingElement.h2()..text = 'Old Generation',
@@ -243,13 +230,32 @@
                         ..classes = ['chart']
                         ..children = <Element>[oldChartLegend, oldChartHost]
                     ],
+            new DivElement()
+              ..classes = ['heap-space', 'left']
+              ..children = _isCompacted
+                  ? [
+                      new HeadingElement.h2()
+                        ..text = 'Total '
+                            '(${_usedCaption(_profile.totalSpace)})',
+                    ]
+                  : [
+                      new HeadingElement.h2()..text = 'Total',
+                      new BRElement(),
+                      new DivElement()
+                        ..classes = ['memberList']
+                        ..children = _createSpaceMembers(_profile.totalSpace),
+                      new BRElement(),
+                      new DivElement()
+                        ..classes = ['chart']
+                        ..children = <Element>[totalChartLegend, totalChartHost]
+                    ],
             new ButtonElement()
               ..classes = ['compact']
               ..text = _isCompacted ? 'expand â–¼' : 'compact â–²'
               ..onClick.listen((_) {
-                _isCompacted = !_isCompacted;
-                _r.dirty();
-              }),
+                    _isCompacted = !_isCompacted;
+                          _r.dirty();
+               }),
             new HRElement()
           ],
         new DivElement()
@@ -266,47 +272,48 @@
       ]);
       _renderGraph(newChartHost, newChartLegend, _profile.newSpace);
       _renderGraph(oldChartHost, oldChartLegend, _profile.oldSpace);
+      _renderGraph(totalChartHost, totalChartLegend, _profile.totalSpace);
     }
   }
 
   _createSorter() {
     var getter;
     switch (_sortingField) {
-      case _SortingField.accumulatedSize:
-        getter = _getAccumulatedSize;
+      case _SortingField.newInternalSize:
+        getter = _getNewInternalSize;
         break;
-      case _SortingField.accumulatedInstances:
-        getter = _getAccumulatedInstances;
+      case _SortingField.newExternalSize:
+        getter = _getNewExternalSize;
         break;
-      case _SortingField.currentSize:
-        getter = _getCurrentSize;
+      case _SortingField.newSize:
+        getter = _getNewSize;
         break;
-      case _SortingField.currentInstances:
-        getter = _getCurrentInstances;
+      case _SortingField.newInstances:
+        getter = _getNewInstances;
         break;
-      case _SortingField.newAccumulatedSize:
-        getter = _getNewAccumulatedSize;
+      case _SortingField.oldInternalSize:
+        getter = _getOldInternalSize;
         break;
-      case _SortingField.newAccumulatedInstances:
-        getter = _getNewAccumulatedInstances;
+      case _SortingField.oldExternalSize:
+        getter = _getOldExternalSize;
         break;
-      case _SortingField.newCurrentSize:
-        getter = _getNewCurrentSize;
+      case _SortingField.oldSize:
+        getter = _getOldSize;
         break;
-      case _SortingField.newCurrentInstances:
-        getter = _getNewCurrentInstances;
+      case _SortingField.oldInstances:
+        getter = _getOldInstances;
         break;
-      case _SortingField.oldAccumulatedSize:
-        getter = _getOldAccumulatedSize;
+      case _SortingField.internalSize:
+        getter = _getInternalSize;
         break;
-      case _SortingField.oldAccumulatedInstances:
-        getter = _getOldAccumulatedInstances;
+      case _SortingField.externalSize:
+        getter = _getExternalSize;
         break;
-      case _SortingField.oldCurrentSize:
-        getter = _getOldCurrentSize;
+      case _SortingField.size:
+        getter = _getSize;
         break;
-      case _SortingField.oldCurrentInstances:
-        getter = _getOldCurrentInstances;
+      case _SortingField.instances:
+        getter = _getInstances;
         break;
       case _SortingField.className:
         getter = (M.ClassHeapStats s) => s.clazz.name;
@@ -333,8 +340,8 @@
         ..classes = ['bytes']
         ..text = '0B',
       new SpanElement()
-        ..classes = ['instances']
-        ..text = '0',
+        ..classes = ['bytes']
+        ..text = '0B',
       new SpanElement()
         ..classes = ['bytes']
         ..text = '0B',
@@ -345,8 +352,8 @@
         ..classes = ['bytes']
         ..text = '0B',
       new SpanElement()
-        ..classes = ['instances']
-        ..text = '0',
+        ..classes = ['bytes']
+        ..text = '0B',
       new SpanElement()
         ..classes = ['bytes']
         ..text = '0B',
@@ -357,8 +364,8 @@
         ..classes = ['bytes']
         ..text = '0B',
       new SpanElement()
-        ..classes = ['instances']
-        ..text = '0',
+        ..classes = ['bytes']
+        ..text = '0B',
       new SpanElement()
         ..classes = ['bytes']
         ..text = '0B',
@@ -374,65 +381,53 @@
           ..children = <Element>[
             new SpanElement()
               ..classes = ['group']
-              ..text = 'Accumulated',
+              ..text = 'New Generation',
             new SpanElement()
               ..classes = ['group']
-              ..text = 'Current',
+              ..text = 'Old Generation',
             new SpanElement()
               ..classes = ['group']
-              ..text = '(NEW) Accumulated',
+              ..text = 'Total',
             new SpanElement()
               ..classes = ['group']
-              ..text = '(NEW) Current',
-            new SpanElement()
-              ..classes = ['group']
-              ..text = '(OLD) Accumulated',
-            new SpanElement()
-              ..classes = ['group']
-              ..text = '(OLD) Current',
+              ..text = '',
           ],
         new DivElement()
           ..classes = ['collection-item']
           ..children = <Element>[
+            _createHeaderButton(const ['bytes'], 'Internal',
+                _SortingField.newInternalSize, _SortingDirection.descending),
+            _createHeaderButton(const ['bytes'], 'External',
+                _SortingField.newExternalSize, _SortingDirection.descending),
             _createHeaderButton(const ['bytes'], 'Size',
-                _SortingField.accumulatedSize, _SortingDirection.descending),
+                _SortingField.newSize, _SortingDirection.descending),
             _createHeaderButton(
-                const ['instances'],
-                'Instances',
-                _SortingField.accumulatedInstances,
+                const ['instances'], 'Instances',
+                _SortingField.newInstances,
                 _SortingDirection.descending),
+
+            _createHeaderButton(const ['bytes'], 'Internal',
+                _SortingField.oldInternalSize, _SortingDirection.descending),
+            _createHeaderButton(const ['bytes'], 'External',
+                _SortingField.oldExternalSize, _SortingDirection.descending),
             _createHeaderButton(const ['bytes'], 'Size',
-                _SortingField.currentSize, _SortingDirection.descending),
-            _createHeaderButton(const ['instances'], 'Instances',
-                _SortingField.currentInstances, _SortingDirection.descending),
-            _createHeaderButton(const ['bytes'], 'Size',
-                _SortingField.newAccumulatedSize, _SortingDirection.descending),
+                _SortingField.oldSize, _SortingDirection.descending),
             _createHeaderButton(
-                const ['instances'],
-                'Instances',
-                _SortingField.newAccumulatedInstances,
+                const ['instances'], 'Instances',
+                _SortingField.oldInstances,
                 _SortingDirection.descending),
+
+            _createHeaderButton(const ['bytes'], 'Internal',
+                _SortingField.internalSize, _SortingDirection.descending),
+            _createHeaderButton(const ['bytes'], 'External',
+                _SortingField.externalSize, _SortingDirection.descending),
             _createHeaderButton(const ['bytes'], 'Size',
-                _SortingField.newCurrentSize, _SortingDirection.descending),
+                _SortingField.size, _SortingDirection.descending),
             _createHeaderButton(
-                const ['instances'],
-                'Instances',
-                _SortingField.newCurrentInstances,
+                const ['instances'], 'Instances',
+                _SortingField.instances,
                 _SortingDirection.descending),
-            _createHeaderButton(const ['bytes'], 'Size',
-                _SortingField.oldAccumulatedSize, _SortingDirection.descending),
-            _createHeaderButton(
-                const ['instances'],
-                'Instances',
-                _SortingField.oldAccumulatedInstances,
-                _SortingDirection.descending),
-            _createHeaderButton(const ['bytes'], 'Size',
-                _SortingField.oldCurrentSize, _SortingDirection.descending),
-            _createHeaderButton(
-                const ['instances'],
-                'Instances',
-                _SortingField.oldCurrentInstances,
-                _SortingDirection.descending),
+
             _createHeaderButton(const ['name'], 'Class',
                 _SortingField.className, _SortingDirection.ascending)
           ],
@@ -468,18 +463,18 @@
 
   void _updateCollectionLine(Element e, itemDynamic, index) {
     M.ClassHeapStats item = itemDynamic;
-    e.children[0].text = Utils.formatSize(_getAccumulatedSize(item));
-    e.children[1].text = '${_getAccumulatedInstances(item)}';
-    e.children[2].text = Utils.formatSize(_getCurrentSize(item));
-    e.children[3].text = '${_getCurrentInstances(item)}';
-    e.children[4].text = Utils.formatSize(_getNewAccumulatedSize(item));
-    e.children[5].text = '${_getNewAccumulatedInstances(item)}';
-    e.children[6].text = Utils.formatSize(_getNewCurrentSize(item));
-    e.children[7].text = '${_getNewCurrentInstances(item)}';
-    e.children[8].text = Utils.formatSize(_getOldAccumulatedSize(item));
-    e.children[9].text = '${_getOldAccumulatedInstances(item)}';
-    e.children[10].text = Utils.formatSize(_getOldCurrentSize(item));
-    e.children[11].text = '${_getOldCurrentInstances(item)}';
+    e.children[0].text = Utils.formatSize(_getNewInternalSize(item));
+    e.children[1].text = Utils.formatSize(_getNewExternalSize(item));
+    e.children[2].text = Utils.formatSize(_getNewSize(item));
+    e.children[3].text = '${_getNewInstances(item)}';
+    e.children[4].text = Utils.formatSize(_getOldInternalSize(item));
+    e.children[5].text = Utils.formatSize(_getOldExternalSize(item));
+    e.children[6].text = Utils.formatSize(_getOldSize(item));
+    e.children[7].text = '${_getOldInstances(item)}';
+    e.children[8].text = Utils.formatSize(_getInternalSize(item));
+    e.children[9].text = Utils.formatSize(_getExternalSize(item));
+    e.children[10].text = Utils.formatSize(_getSize(item));
+    e.children[11].text = '${_getInstances(item)}';
     e.children[12] = new ClassRefElement(_isolate, item.clazz, queue: _r.queue)
         .element
       ..classes = ['name'];
@@ -546,26 +541,6 @@
             ..classes = ['memberValue']
             ..text = avgCollectionTime
         ],
-      new DivElement()
-        ..classes = ['memberItem']
-        ..children = <Element>[
-          new DivElement()
-            ..classes = ['memberName']
-            ..text = 'cumulative collection time',
-          new DivElement()
-            ..classes = ['memberValue']
-            ..text = totalCollectionTime
-        ],
-      new DivElement()
-        ..classes = ['memberItem']
-        ..children = <Element>[
-          new DivElement()
-            ..classes = ['memberName']
-            ..text = 'average time between collections',
-          new DivElement()
-            ..classes = ['memberValue']
-            ..text = avgCollectionPeriod
-        ]
     ];
   }
 
@@ -604,18 +579,18 @@
   void _downloadCSV() {
     assert(_profile != null);
     final header = [
-          '"Accumulator Size"',
-          '"Accumulator Instances"',
-          '"Current Size"',
-          '"Current Instances"',
-          '"(NEW) Accumulator Size"',
-          '"(NEW) Accumulator Instances"',
-          '"(NEW) Current Size"',
-          '"(NEW) Current Instances"',
-          '"(OLD) Accumulator Size"',
-          '"(OLD) Accumulator Instances"',
-          '"(OLD) Current Size"',
-          '"(OLD) Current Instances"',
+          '"New Internal"',
+          '"New External"',
+          '"New Size"',
+          '"New Instances"',
+          '"Old Internal"',
+          '"Old External"',
+          '"Old Size"',
+          '"Old Instances"',
+          '"Internal"',
+          '"External"',
+          '"Size"',
+          '"Instances"',
           'Class'
         ].join(',') +
         '\n';
@@ -632,42 +607,44 @@
 
   static _csvOut(M.ClassHeapStats s) {
     return [
-      _getAccumulatedSize(s),
-      _getAccumulatedInstances(s),
-      _getCurrentSize(s),
-      _getCurrentInstances(s),
-      _getNewAccumulatedSize(s),
-      _getNewAccumulatedInstances(s),
-      _getNewCurrentSize(s),
-      _getNewCurrentInstances(s),
-      _getOldAccumulatedSize(s),
-      _getOldAccumulatedInstances(s),
-      _getOldCurrentSize(s),
-      _getOldCurrentInstances(s),
+      _getNewInternalSize(s),
+      _getNewExternalSize(s),
+      _getNewSize(s),
+      _getNewInstances(s),
+      _getOldInternalSize(s),
+      _getOldExternalSize(s),
+      _getOldSize(s),
+      _getOldInstances(s),
+      _getInternalSize(s),
+      _getExternalSize(s),
+      _getSize(s),
+      _getInstances(s),
       s.clazz.name
     ].join(',');
   }
 
-  static int _getAccumulatedSize(M.ClassHeapStats s) =>
-      s.newSpace.accumulated.bytes + s.oldSpace.accumulated.bytes;
-  static int _getAccumulatedInstances(M.ClassHeapStats s) =>
-      s.newSpace.accumulated.instances + s.oldSpace.accumulated.instances;
-  static int _getCurrentSize(M.ClassHeapStats s) =>
-      s.newSpace.current.bytes + s.oldSpace.current.bytes;
-  static int _getCurrentInstances(M.ClassHeapStats s) =>
-      s.newSpace.current.instances + s.oldSpace.current.instances;
-  static int _getNewAccumulatedSize(M.ClassHeapStats s) =>
-      s.newSpace.accumulated.bytes;
-  static int _getNewAccumulatedInstances(M.ClassHeapStats s) =>
-      s.newSpace.accumulated.instances;
-  static int _getNewCurrentSize(M.ClassHeapStats s) => s.newSpace.current.bytes;
-  static int _getNewCurrentInstances(M.ClassHeapStats s) =>
-      s.newSpace.current.instances;
-  static int _getOldAccumulatedSize(M.ClassHeapStats s) =>
-      s.oldSpace.accumulated.bytes;
-  static int _getOldAccumulatedInstances(M.ClassHeapStats s) =>
-      s.oldSpace.accumulated.instances;
-  static int _getOldCurrentSize(M.ClassHeapStats s) => s.oldSpace.current.bytes;
-  static int _getOldCurrentInstances(M.ClassHeapStats s) =>
-      s.oldSpace.current.instances;
+  static int _getNewInstances(M.ClassHeapStats s) =>
+      s.newSpace.instances;
+  static int _getNewInternalSize(M.ClassHeapStats s) =>
+      s.newSpace.internalSize;
+  static int _getNewExternalSize(M.ClassHeapStats s) =>
+      s.newSpace.externalSize;
+  static int _getNewSize(M.ClassHeapStats s) =>
+      s.newSpace.size;
+  static int _getOldInstances(M.ClassHeapStats s) =>
+      s.oldSpace.instances;
+  static int _getOldInternalSize(M.ClassHeapStats s) =>
+      s.oldSpace.internalSize;
+  static int _getOldExternalSize(M.ClassHeapStats s) =>
+      s.oldSpace.externalSize;
+  static int _getOldSize(M.ClassHeapStats s) =>
+      s.oldSpace.size;
+  static int _getInstances(M.ClassHeapStats s) =>
+      s.newSpace.instances + s.oldSpace.instances;
+  static int _getInternalSize(M.ClassHeapStats s) =>
+      s.newSpace.internalSize + s.oldSpace.internalSize;
+  static int _getExternalSize(M.ClassHeapStats s) =>
+      s.newSpace.externalSize + s.oldSpace.externalSize;
+  static int _getSize(M.ClassHeapStats s) =>
+      s.newSpace.size + s.oldSpace.size;
 }
diff --git a/runtime/observatory/lib/src/elements/class_instances.dart b/runtime/observatory/lib/src/elements/class_instances.dart
index 792f8e9..b81d859 100644
--- a/runtime/observatory/lib/src/elements/class_instances.dart
+++ b/runtime/observatory/lib/src/elements/class_instances.dart
@@ -87,10 +87,8 @@
         new StronglyReachableInstancesElement(
             _isolate, _cls, _stronglyReachableInstances, _objects,
             queue: _r.queue);
-    final instanceCount =
-        _cls.newSpace.current.instances + _cls.oldSpace.current.instances;
-    final size = Utils.formatSize(
-        _cls.newSpace.current.bytes + _cls.oldSpace.current.bytes);
+    final instanceCount = _cls.newSpace.instances + _cls.oldSpace.instances;
+    final size = Utils.formatSize(_cls.newSpace.size + _cls.oldSpace.size);
     children = <Element>[
       new DivElement()
         ..classes = ['memberList']
diff --git a/runtime/observatory/lib/src/elements/css/shared.css b/runtime/observatory/lib/src/elements/css/shared.css
index f573064..da445fe 100644
--- a/runtime/observatory/lib/src/elements/css/shared.css
+++ b/runtime/observatory/lib/src/elements/css/shared.css
@@ -399,7 +399,7 @@
 
 .allocation-profile .heap-space {
   display: inline-block;
-  width: 50%;
+  width: 33%;
 }
 
 .allocation-profile .heap-space.right,
@@ -499,33 +499,41 @@
 }
 
 .allocation-profile .collection-item :nth-child(2n+2).group,
-.allocation-profile .collection-item :nth-child(4n+3),
-.allocation-profile .collection-item :nth-child(4n+4) {
+.allocation-profile .collection-item :nth-child(8n+1),
+.allocation-profile .collection-item :nth-child(8n+2),
+.allocation-profile .collection-item :nth-child(8n+3),
+.allocation-profile .collection-item :nth-child(8n+4) {
   background-color: #EEEEEE;
 }
 
-.allocation-profile .collection-item:hover :nth-child(2n+2).group,
-.allocation-profile .collection-item:hover :nth-child(4n+3),
-.allocation-profile .collection-item:hover :nth-child(4n+4) {
+.allocation-profile .collection-item:hover :nth-child(2n+1).group,
+.allocation-profile .collection-item:hover :nth-child(8n+1),
+.allocation-profile .collection-item:hover :nth-child(8n+2),
+.allocation-profile .collection-item:hover :nth-child(8n+3),
+.allocation-profile .collection-item:hover :nth-child(8n+4) {
   background-color: #afd5fd;
 }
 
-.allocation-profile .header .collection-item :nth-child(2n+1).group,
-.allocation-profile .header .collection-item :nth-child(4n+1),
-.allocation-profile .header .collection-item :nth-child(4n+2) {
+.allocation-profile .header .collection-item :nth-child(2n+2).group,
+.allocation-profile .header .collection-item :nth-child(8n+5),
+.allocation-profile .header .collection-item :nth-child(8n+6),
+.allocation-profile .header .collection-item :nth-child(8n+7),
+.allocation-profile .header .collection-item :nth-child(8n+8) {
   background-color: #FFFFFF;
 }
 
-.allocation-profile .header .collection-item :nth-child(2n+2).group,
-.allocation-profile .header .collection-item :nth-child(4n+3),
-.allocation-profile .header .collection-item :nth-child(4n+4) {
+.allocation-profile .header .collection-item :nth-child(2n+1).group,
+.allocation-profile .header .collection-item :nth-child(8n+1),
+.allocation-profile .header .collection-item :nth-child(8n+2),
+.allocation-profile .header .collection-item :nth-child(8n+3),
+.allocation-profile .header .collection-item :nth-child(8n+4) {
   background-color: #DDDDDD;
 }
 
 .allocation-profile .collection-item .group {
   display: inline-block;
-  width: 12em;
-  text-align: right;
+  width: 24em;
+  text-align: center;
   padding-right: 0.5em;
   line-height: 20px;
   border-right: solid 1px #AAAAAA;
diff --git a/runtime/observatory/lib/src/elements/timeline_page.dart b/runtime/observatory/lib/src/elements/timeline_page.dart
index 7e54388..8619098 100644
--- a/runtime/observatory/lib/src/elements/timeline_page.dart
+++ b/runtime/observatory/lib/src/elements/timeline_page.dart
@@ -65,7 +65,7 @@
   attached() {
     super.attached();
     _r.enable();
-    _setupInitialState();
+    _updateRecorderUI();
   }
 
   @override
@@ -84,6 +84,9 @@
   void render() {
     if (_frame == null) {
       _frame = new IFrameElement()..src = 'timeline.html';
+      _frame.onLoad.listen((event) {
+        _refresh();
+      });
     }
     if (_content == null) {
       _content = new DivElement()..classes = ['content-centered-big'];
@@ -187,8 +190,7 @@
                 "This VM is forwarding timeline events to Fuchsia's system tracing. See the ",
           new AnchorElement()
             ..text = "Fuchsia Tracing Usage Guide"
-            ..href =
-                "https://fuchsia.googlesource.com/garnet/+/master/docs/tracing_usage_guide.md",
+            ..href = "https://fuchsia.dev/fuchsia-src/development/tracing",
           new SpanElement()..text = ".",
         ];
     }
@@ -232,6 +234,7 @@
   }
 
   Future _refresh() async {
+    _postMessage('loading');
     final traceData = await _repository.getTimeline(vm);
     return _postMessage('refresh', traceData);
   }
@@ -260,11 +263,6 @@
     return null;
   }
 
-  Future _setupInitialState() async {
-    await _updateRecorderUI();
-    await _refresh();
-  }
-
   void _applyPreset(M.TimelineProfile profile) {
     _recordedStreams = new Set<M.TimelineStream>.from(profile.streams);
     _applyStreamChanges();
diff --git a/runtime/observatory/lib/src/models/objects/allocation_profile.dart b/runtime/observatory/lib/src/models/objects/allocation_profile.dart
index 4f113a6..f9aa5a6 100644
--- a/runtime/observatory/lib/src/models/objects/allocation_profile.dart
+++ b/runtime/observatory/lib/src/models/objects/allocation_profile.dart
@@ -9,6 +9,7 @@
   DateTime get lastAccumulatorReset;
   HeapSpace get newSpace;
   HeapSpace get oldSpace;
+  HeapSpace get totalSpace;
   Iterable<ClassHeapStats> get members;
 }
 
@@ -20,16 +21,11 @@
   String get displayName;
   Allocations get newSpace;
   Allocations get oldSpace;
-  int get promotedInstances;
-  int get promotedBytes;
 }
 
 abstract class Allocations {
-  AllocationCount get accumulated;
-  AllocationCount get current;
-}
-
-abstract class AllocationCount {
-  int get instances;
-  int get bytes;
+  int instances = 0;
+  int internalSize = 0;
+  int externalSize = 0;
+  int size = 0;
 }
diff --git a/runtime/observatory/lib/src/service/object.dart b/runtime/observatory/lib/src/service/object.dart
index 754075c..86f8cc7 100644
--- a/runtime/observatory/lib/src/service/object.dart
+++ b/runtime/observatory/lib/src/service/object.dart
@@ -1268,6 +1268,20 @@
     totalCollectionTimeInSeconds = heapMap['time'];
     averageCollectionPeriodInMillis = heapMap['avgCollectionPeriodMillis'];
   }
+
+  void add(HeapSpace other) {
+    used += other.used;
+    capacity += other.capacity;
+    external += other.external;
+    collections += other.collections;
+    totalCollectionTimeInSeconds += other.totalCollectionTimeInSeconds;
+    if (collections == 0) {
+      averageCollectionPeriodInMillis = 0.0;
+    } else {
+      averageCollectionPeriodInMillis =
+          (totalCollectionTimeInSeconds / collections) * 1000.0;
+    }
+  }
 }
 
 class IsolateGroup extends ServiceObjectOwner implements M.IsolateGroup {
@@ -2519,50 +2533,30 @@
   String toString() => "Library($uri)";
 }
 
-class AllocationCount implements M.AllocationCount {
-  int instances = 0;
-  int bytes = 0;
-
-  void reset() {
-    instances = 0;
-    bytes = 0;
-  }
-
-  bool get empty => (instances == 0) && (bytes == 0);
-  bool get notEmpty => (instances != 0) || (bytes != 0);
-}
-
 class Allocations implements M.Allocations {
   // Indexes into VM provided array. (see vm/class_table.h).
-  static const ALLOCATED_BEFORE_GC = 0;
-  static const ALLOCATED_BEFORE_GC_SIZE = 1;
-  static const LIVE_AFTER_GC = 2;
-  static const LIVE_AFTER_GC_SIZE = 3;
-  static const ALLOCATED_SINCE_GC = 4;
-  static const ALLOCATED_SINCE_GC_SIZE = 5;
-  static const ACCUMULATED = 6;
-  static const ACCUMULATED_SIZE = 7;
 
-  final AllocationCount accumulated = new AllocationCount();
-  final AllocationCount current = new AllocationCount();
+  int instances = 0;
+  int internalSize = 0;
+  int externalSize = 0;
+  int size = 0;
 
   void update(List stats) {
-    accumulated.instances = stats[ACCUMULATED];
-    accumulated.bytes = stats[ACCUMULATED_SIZE];
-    current.instances = stats[LIVE_AFTER_GC] + stats[ALLOCATED_SINCE_GC];
-    current.bytes = stats[LIVE_AFTER_GC_SIZE] + stats[ALLOCATED_SINCE_GC_SIZE];
+    instances = stats[0];
+    internalSize = stats[1];
+    externalSize = stats[2];
+    size = internalSize + externalSize;
   }
 
   void combine(Iterable<Allocations> allocations) {
-    accumulated.instances =
-        allocations.fold(0, (v, a) => v + a.accumulated.instances);
-    accumulated.bytes = allocations.fold(0, (v, a) => v + a.accumulated.bytes);
-    current.instances = allocations.fold(0, (v, a) => v + a.current.instances);
-    current.bytes = allocations.fold(0, (v, a) => v + a.current.bytes);
+    instances = allocations.fold(0, (v, a) => v + a.instances);
+    internalSize = allocations.fold(0, (v, a) => v + a.internalSize);
+    externalSize = allocations.fold(0, (v, a) => v + a.externalSize);
+    size = allocations.fold(0, (v, a) => v + a.size);
   }
 
-  bool get empty => accumulated.empty && current.empty;
-  bool get notEmpty => accumulated.notEmpty || current.notEmpty;
+  bool get empty => size == 0;
+  bool get notEmpty => size != 0;
 }
 
 class Class extends HeapObject implements M.Class {
@@ -2580,7 +2574,6 @@
 
   final Allocations newSpace = new Allocations();
   final Allocations oldSpace = new Allocations();
-  final AllocationCount promotedByLastNewGC = new AllocationCount();
 
   bool get hasAllocations => newSpace.notEmpty || oldSpace.notEmpty;
   bool get hasNoAllocations => newSpace.empty && oldSpace.empty;
@@ -2663,14 +2656,6 @@
 
     traceAllocations =
         (map['_traceAllocations'] != null) ? map['_traceAllocations'] : false;
-
-    var allocationStats = map['_allocationStats'];
-    if (allocationStats != null) {
-      newSpace.update(allocationStats['_new']);
-      oldSpace.update(allocationStats['_old']);
-      promotedByLastNewGC.instances = allocationStats['promotedInstances'];
-      promotedByLastNewGC.bytes = allocationStats['promotedBytes'];
-    }
   }
 
   void _addSubclass(Class subclass) {
diff --git a/runtime/observatory/tests/service/allocations_test.dart b/runtime/observatory/tests/service/allocations_test.dart
index e21ec15..4b0f23b 100644
--- a/runtime/observatory/tests/service/allocations_test.dart
+++ b/runtime/observatory/tests/service/allocations_test.dart
@@ -18,15 +18,12 @@
 
 var tests = <IsolateTest>[
   (Isolate isolate) async {
-    Library lib = await isolate.rootLibrary.load();
-    expect(lib.uri.endsWith('allocations_test.dart'), isTrue);
-    expect(lib.classes.length, equals(1));
-    Class fooClass = await lib.classes.first.load();
-    expect(fooClass.name, equals('Foo'));
-    expect(
-        fooClass.newSpace.current.instances +
-            fooClass.oldSpace.current.instances,
-        equals(3));
+    var profile = await isolate.invokeRpcNoUpgrade('_getAllocationProfile', {});
+    var classHeapStats = profile['members'].singleWhere((stats) {
+      return stats['class']['name'] == 'Foo';
+    });
+    expect(classHeapStats['instancesCurrent'], equals(3));
+    expect(classHeapStats['instancesAccumulated'], equals(3));
   },
 ];
 
diff --git a/runtime/observatory/tests/service/causal_async_stack_contents_test.dart b/runtime/observatory/tests/service/causal_async_stack_contents_test.dart
index 209c2f6b..c21879b 100644
--- a/runtime/observatory/tests/service/causal_async_stack_contents_test.dart
+++ b/runtime/observatory/tests/service/causal_async_stack_contents_test.dart
@@ -11,8 +11,8 @@
 import 'test_helper.dart';
 
 const LINE_C = 19;
-const LINE_A = 24;
-const LINE_B = 30;
+const LINE_A = 25;
+const LINE_B = 31;
 
 foobar() {
   debugger();
@@ -20,6 +20,7 @@
 }
 
 helper() async {
+  await 0; // force async gap
   debugger();
   print('helper'); // LINE_A.
   foobar();
@@ -64,10 +65,10 @@
     expect(asyncStack[3].toString(), contains('testMain'));
     // Line 19.
     expect(await asyncStack[0].location.toUserString(), contains('.dart:19'));
-    // Line 25.
-    expect(await asyncStack[1].location.toUserString(), contains('.dart:25'));
-    // Line 30.
-    expect(await asyncStack[3].location.toUserString(), contains('.dart:30'));
+    // Line 26.
+    expect(await asyncStack[1].location.toUserString(), contains('.dart:26'));
+    // Line 31.
+    expect(await asyncStack[3].location.toUserString(), contains('.dart:31'));
   },
 ];
 
diff --git a/runtime/observatory/tests/service/causal_async_star_stack_contents_test.dart b/runtime/observatory/tests/service/causal_async_star_stack_contents_test.dart
index 3525105..80eb931 100644
--- a/runtime/observatory/tests/service/causal_async_star_stack_contents_test.dart
+++ b/runtime/observatory/tests/service/causal_async_star_stack_contents_test.dart
@@ -10,11 +10,12 @@
 import 'service_test_common.dart';
 import 'test_helper.dart';
 
-const LINE_A = 26;
-const LINE_B = 19;
-const LINE_C = 21;
+const LINE_A = 28;
+const LINE_B = 20;
+const LINE_C = 22;
 
 foobar() async* {
+  await 0; // force async gap
   debugger();
   yield 1; // LINE_B.
   debugger();
@@ -22,6 +23,7 @@
 }
 
 helper() async {
+  await 0; // force async gap
   debugger();
   print('helper'); // LINE_A.
   await for (var i in foobar()) {
@@ -76,12 +78,13 @@
     expect(asyncStack[2].toString(), contains('helper'));
     expect(asyncStack[3].kind, equals(M.FrameKind.asyncSuspensionMarker));
     expect(asyncStack[4].toString(), contains('testMain'));
-    // Line 21.
-    expect(await asyncStack[0].location.toUserString(), contains('.dart:21'));
-    // Line 27.
-    expect(await asyncStack[2].location.toUserString(), contains('.dart:27'));
-    // Line 30.
-    expect(await asyncStack[4].location.toUserString(), contains('.dart:33'));
+    // Line 22.
+    expect(
+        await asyncStack[0].location.toUserString(), contains('.dart:$LINE_C'));
+    // Line 29.
+    expect(await asyncStack[2].location.toUserString(), contains('.dart:29'));
+    // Line 35.
+    expect(await asyncStack[4].location.toUserString(), contains('.dart:35'));
   },
 ];
 
diff --git a/runtime/observatory/tests/service/get_allocation_profile_rpc_test.dart b/runtime/observatory/tests/service/get_allocation_profile_rpc_test.dart
index a03cbfc..8d5c88e 100644
--- a/runtime/observatory/tests/service/get_allocation_profile_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_allocation_profile_rpc_test.dart
@@ -32,8 +32,6 @@
     expect(member['type'], equals('ClassHeapStats'));
     expect(member.containsKey('_new'), isTrue);
     expect(member.containsKey('_old'), isTrue);
-    expect(member.containsKey('_promotedInstances'), isTrue);
-    expect(member.containsKey('_promotedBytes'), isTrue);
     expect(member.containsKey('instancesAccumulated'), isTrue);
     expect(member.containsKey('instancesCurrent'), isTrue);
     expect(member.containsKey('bytesCurrent'), isTrue);
@@ -57,8 +55,6 @@
     expect(member['type'], equals('ClassHeapStats'));
     expect(member.containsKey('_new'), isTrue);
     expect(member.containsKey('_old'), isTrue);
-    expect(member.containsKey('_promotedInstances'), isTrue);
-    expect(member.containsKey('_promotedBytes'), isTrue);
     expect(member.containsKey('instancesAccumulated'), isTrue);
     expect(member.containsKey('instancesCurrent'), isTrue);
     expect(member.containsKey('bytesCurrent'), isTrue);
@@ -88,8 +84,6 @@
     expect(member['type'], equals('ClassHeapStats'));
     expect(member.containsKey('_new'), isTrue);
     expect(member.containsKey('_old'), isTrue);
-    expect(member.containsKey('_promotedInstances'), isTrue);
-    expect(member.containsKey('_promotedBytes'), isTrue);
     expect(member.containsKey('instancesAccumulated'), isTrue);
     expect(member.containsKey('instancesCurrent'), isTrue);
     expect(member.containsKey('bytesCurrent'), isTrue);
diff --git a/runtime/observatory/tests/service/pause_on_unhandled_async_exceptions2_test.dart b/runtime/observatory/tests/service/pause_on_unhandled_async_exceptions2_test.dart
index 89ebcbf..90cbea3b 100644
--- a/runtime/observatory/tests/service/pause_on_unhandled_async_exceptions2_test.dart
+++ b/runtime/observatory/tests/service/pause_on_unhandled_async_exceptions2_test.dart
@@ -10,7 +10,7 @@
 import 'test_helper.dart';
 import 'service_test_common.dart';
 
-const LINE_A = 34;
+const LINE_A = 35;
 
 class Foo {}
 
@@ -20,6 +20,7 @@
 }
 
 asyncThrower() async {
+  await 0; // force async gap
   doThrow();
 }
 
diff --git a/runtime/observatory/tests/service/pause_on_unhandled_async_exceptions_test.dart b/runtime/observatory/tests/service/pause_on_unhandled_async_exceptions_test.dart
index b832931..8f955f3 100644
--- a/runtime/observatory/tests/service/pause_on_unhandled_async_exceptions_test.dart
+++ b/runtime/observatory/tests/service/pause_on_unhandled_async_exceptions_test.dart
@@ -9,7 +9,7 @@
 import 'test_helper.dart';
 import 'service_test_common.dart';
 
-const LINE_A = 34;
+const LINE_A = 35;
 
 class Foo {}
 
@@ -19,6 +19,7 @@
 }
 
 asyncThrower() async {
+  await 0; // force async gap
   doThrow();
 }
 
diff --git a/runtime/observatory/tests/service/step_through_mixin_from_sdk_test.dart b/runtime/observatory/tests/service/step_through_mixin_from_sdk_test.dart
index c36f561..5c4a65a 100644
--- a/runtime/observatory/tests/service/step_through_mixin_from_sdk_test.dart
+++ b/runtime/observatory/tests/service/step_through_mixin_from_sdk_test.dart
@@ -35,19 +35,19 @@
 List<String> expected = [
   "$file:${LINE + 0}:17", // on "Foo" (in "new Foo()")
   "$file:${LINE + 1}:11", // on "="
-  "list.dart:105:24", // on parameter to "contains"
-  "list.dart:106:23", // on "length" in "this.length"
-  "list.dart:107:16", // on "=" in "i = 0"
-  "list.dart:107:23", // on "<" in "i < length"
-  "list.dart:108:15", // on "[" in "this[i]"
+  "list.dart:107:24", // on parameter to "contains"
+  "list.dart:108:23", // on "length" in "this.length"
+  "list.dart:109:16", // on "=" in "i = 0"
+  "list.dart:109:23", // on "<" in "i < length"
+  "list.dart:110:15", // on "[" in "this[i]"
   "$file:${LINE + 13}:23", // on parameter in "operator []"
   "$file:${LINE + 14}:5", // on "return"
-  "list.dart:108:19", // on "=="
-  "list.dart:109:26", // on "length" in "this.length"
-  "list.dart:109:18", // on "!="
-  "list.dart:107:34", // on "++" in "i++"
-  "list.dart:107:23", // on "<" in "i < length"
-  "list.dart:113:5", // on "return"
+  "list.dart:110:19", // on "=="
+  "list.dart:111:26", // on "length" in "this.length"
+  "list.dart:111:18", // on "!="
+  "list.dart:109:34", // on "++" in "i++"
+  "list.dart:109:23", // on "<" in "i < length"
+  "list.dart:115:5", // on "return"
   "$file:${LINE + 4}:5", // on "print"
   "$file:${LINE + 6}:1" // on ending '}'
 ];
diff --git a/runtime/observatory/tests/service/verify_http_timeline_test.dart b/runtime/observatory/tests/service/verify_http_timeline_test.dart
new file mode 100644
index 0000000..9b41df0
--- /dev/null
+++ b/runtime/observatory/tests/service/verify_http_timeline_test.dart
@@ -0,0 +1,288 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--timeline_streams=Dart
+
+import 'dart:async';
+import 'dart:developer';
+import 'dart:io';
+import 'dart:math';
+import 'package:observatory/service_io.dart';
+import 'package:unittest/unittest.dart';
+
+import 'test_helper.dart';
+
+final rng = Random();
+
+// Enable to test redirects.
+const shouldTestRedirects = false;
+
+const maxRequestDelayMs = 3000;
+const maxResponseDelayMs = 500;
+const serverShutdownDelayMs = 2000;
+
+void randomlyAddCookie(HttpResponse response) {
+  if (rng.nextInt(3) == 0) {
+    response.cookies.add(Cookie('Cookie-Monster', 'Me-want-cookie!'));
+  }
+}
+
+Future<bool> randomlyRedirect(HttpServer server, HttpResponse response) async {
+  if (shouldTestRedirects && rng.nextInt(5) == 0) {
+    final redirectUri = Uri(host: 'www.google.com', port: 80);
+    response.redirect(redirectUri);
+    return true;
+  }
+  return false;
+}
+
+// Execute HTTP requests with random delays so requests have some overlap. This
+// way we can be certain that timeline events are matching up properly even when
+// connections are interrupted or can't be established.
+Future<void> executeWithRandomDelay(Function f) =>
+    Future<void>.delayed(Duration(milliseconds: rng.nextInt(maxRequestDelayMs)))
+        .then((_) async {
+      try {
+        await f();
+      } on HttpException catch (_) {} on SocketException catch (_) {} on StateError catch (_) {}
+    });
+
+Uri randomlyAddRequestParams(Uri uri) {
+  const possiblePathSegments = <String>['foo', 'bar', 'baz', 'foobar'];
+  final segmentSubset =
+      possiblePathSegments.sublist(0, rng.nextInt(possiblePathSegments.length));
+  uri = uri.replace(pathSegments: segmentSubset);
+  if (rng.nextInt(3) == 0) {
+    uri = uri.replace(queryParameters: {
+      'foo': 'bar',
+      'year': '2019',
+    });
+  }
+  return uri;
+}
+
+Future<HttpServer> startServer() async {
+  final server = await HttpServer.bind(InternetAddress.loopbackIPv4, 8011);
+  server.listen((request) async {
+    final response = request.response;
+    randomlyAddCookie(response);
+    if (await randomlyRedirect(server, response)) {
+      // Redirect calls close() on the response.
+      return;
+    }
+    // Randomly delay response.
+    await Future.delayed(
+        Duration(milliseconds: rng.nextInt(maxResponseDelayMs)));
+    response.close();
+  });
+  return server;
+}
+
+Future<void> testMain() async {
+  // Ensure there's a chance some requests will be interrupted.
+  expect(maxRequestDelayMs > serverShutdownDelayMs, isTrue);
+  expect(maxResponseDelayMs < serverShutdownDelayMs, isTrue);
+
+  final server = await startServer();
+  HttpClient.enableTimelineLogging = true;
+  final client = HttpClient();
+  final requests = <Future>[];
+  final address =
+      Uri(scheme: 'http', host: server.address.host, port: server.port);
+
+  // HTTP DELETE
+  for (int i = 0; i < 10; ++i) {
+    final future = executeWithRandomDelay(() async {
+      final r = await client.deleteUrl(randomlyAddRequestParams(address));
+      await r.close();
+    });
+    requests.add(future);
+  }
+
+  // HTTP GET
+  for (int i = 0; i < 10; ++i) {
+    final future = executeWithRandomDelay(() async {
+      final r = await client.getUrl(randomlyAddRequestParams(address));
+      await r.close();
+    });
+    requests.add(future);
+  }
+
+  // HTTP HEAD
+  for (int i = 0; i < 10; ++i) {
+    final future = executeWithRandomDelay(() async {
+      final r = await client.headUrl(randomlyAddRequestParams(address));
+      await r.close();
+    });
+    requests.add(future);
+  }
+
+  // HTTP CONNECT
+  for (int i = 0; i < 10; ++i) {
+    final future = executeWithRandomDelay(() async {
+      final r =
+          await client.openUrl('connect', randomlyAddRequestParams(address));
+      await r.close();
+    });
+    requests.add(future);
+  }
+
+  // HTTP PATCH
+  for (int i = 0; i < 10; ++i) {
+    final future = executeWithRandomDelay(() async {
+      final r = await client.patchUrl(randomlyAddRequestParams(address));
+      await r.close();
+    });
+    requests.add(future);
+  }
+
+  // HTTP POST
+  for (int i = 0; i < 10; ++i) {
+    final future = executeWithRandomDelay(() async {
+      final r = await client.postUrl(randomlyAddRequestParams(address));
+      await r.close();
+    });
+    requests.add(future);
+  }
+
+  // HTTP PUT
+  for (int i = 0; i < 10; ++i) {
+    final future = executeWithRandomDelay(() async {
+      final r = await client.putUrl(randomlyAddRequestParams(address));
+      await r.close();
+    });
+    requests.add(future);
+  }
+
+  // Purposefully close server before some connections can be made to ensure
+  // that refused / interrupted connections correctly create finish timeline
+  // events.
+  await Future.delayed(Duration(milliseconds: serverShutdownDelayMs));
+  await server.close();
+
+  // Ensure all requests complete before finishing.
+  await Future.wait(requests);
+}
+
+bool isStartEvent(Map event) => (event['ph'] == 'b');
+bool isFinishEvent(Map event) => (event['ph'] == 'e');
+
+bool hasCompletedEvents(List traceEvents) {
+  final events = <String, int>{};
+  for (final event in traceEvents) {
+    if (isStartEvent(event)) {
+      final id = event['id'];
+      events.putIfAbsent(id, () => 0);
+      events[id]++;
+    } else if (isFinishEvent(event)) {
+      final id = event['id'];
+      events[id]--;
+    }
+  }
+  bool valid = true;
+  events.forEach((id, count) {
+    if (count != 0) {
+      valid = false;
+    }
+  });
+  return valid;
+}
+
+List filterEventsByName(List traceEvents, String name) =>
+    traceEvents.where((e) => e['name'].contains(name)).toList();
+
+void hasValidHttpConnections(List traceEvents) {
+  final events = filterEventsByName(traceEvents, 'HTTP Connection');
+  expect(hasCompletedEvents(events), isTrue);
+}
+
+void validateHttpStartEvent(Map event, String method) {
+  expect(event.containsKey('args'), isTrue);
+  final args = event['args'];
+  expect(args.containsKey('method'), isTrue);
+  expect(args['method'], method);
+  if (!args.containsKey('error')) {
+    expect(args.containsKey('requestHeaders'), isTrue);
+    expect(args['requestHeaders'] != null, isTrue);
+    expect(args.containsKey('compressionState'), isTrue);
+    expect(args.containsKey('connectionInfo'), isTrue);
+    expect(args.containsKey('contentLength'), isTrue);
+    expect(args.containsKey('cookies'), isTrue);
+    expect(args.containsKey('responseHeaders'), isTrue);
+    expect(args.containsKey('isRedirect'), isTrue);
+    expect(args.containsKey('persistentConnection'), isTrue);
+    expect(args.containsKey('reasonPhrase'), isTrue);
+    expect(args.containsKey('redirects'), isTrue);
+    expect(args.containsKey('statusCode'), isTrue);
+    // If proxyInfo is non-null, uri and port _must_ be non-null.
+    if (args.containsKey('proxyInfo')) {
+      final proxyInfo = args['proxyInfo'];
+      expect(proxyInfo.containsKey('uri'), isTrue);
+      expect(proxyInfo.containsKey('port'), isTrue);
+    }
+  }
+}
+
+void validateHttpFinishEvent(Map event) {
+  expect(event.containsKey('args'), isTrue);
+  final args = event['args'];
+  expect(args.containsKey('compressionState'), isTrue);
+  expect(args.containsKey('connectionInfo'), isTrue);
+  expect(args.containsKey('contentLength'), isTrue);
+  expect(args.containsKey('cookies'), isTrue);
+  expect(args.containsKey('responseHeaders'), isTrue);
+  expect(args.containsKey('isRedirect'), isTrue);
+  expect(args.containsKey('persistentConnection'), isTrue);
+  expect(args.containsKey('reasonPhrase'), isTrue);
+  expect(args.containsKey('redirects'), isTrue);
+  expect(args.containsKey('statusCode'), isTrue);
+}
+
+void hasValidHttpRequests(List traceEvents, String method) {
+  final events = filterEventsByName(traceEvents, 'HTTP Client $method');
+  expect(hasCompletedEvents(events), isTrue);
+  for (final event in events) {
+    if (isStartEvent(event)) {
+      validateHttpStartEvent(event, method);
+    } else if (isFinishEvent(event)) {
+      validateHttpFinishEvent(event);
+    } else {
+      fail('unexpected event type: ${event["ph"]}');
+    }
+  }
+}
+
+void hasValidHttpCONNECTs(List traceEvents) =>
+    hasValidHttpRequests(traceEvents, 'CONNECT');
+void hasValidHttpDELETEs(List traceEvents) =>
+    hasValidHttpRequests(traceEvents, 'DELETE');
+void hasValidHttpGETs(List traceEvents) =>
+    hasValidHttpRequests(traceEvents, 'GET');
+void hasValidHttpHEADs(List traceEvents) =>
+    hasValidHttpRequests(traceEvents, 'HEAD');
+void hasValidHttpPATCHs(List traceEvents) =>
+    hasValidHttpRequests(traceEvents, 'PATCH');
+void hasValidHttpPOSTs(List traceEvents) =>
+    hasValidHttpRequests(traceEvents, 'POST');
+void hasValidHttpPUTs(List traceEvents) =>
+    hasValidHttpRequests(traceEvents, 'PUT');
+
+var tests = <IsolateTest>[
+  (Isolate isolate) async {
+    final result = await isolate.vm.invokeRpcNoUpgrade('getVMTimeline', {});
+    expect(result['type'], 'Timeline');
+    expect(result.containsKey('traceEvents'), isTrue);
+    final traceEvents = result['traceEvents'];
+    expect(traceEvents.length > 0, isTrue);
+    hasValidHttpConnections(traceEvents);
+    hasValidHttpCONNECTs(traceEvents);
+    hasValidHttpDELETEs(traceEvents);
+    hasValidHttpGETs(traceEvents);
+    hasValidHttpHEADs(traceEvents);
+    hasValidHttpPATCHs(traceEvents);
+    hasValidHttpPOSTs(traceEvents);
+    hasValidHttpPUTs(traceEvents);
+  },
+];
+
+main(args) async => runIsolateTests(args, tests, testeeBefore: testMain);
diff --git a/runtime/observatory/web/timeline_message_handler.js b/runtime/observatory/web/timeline_message_handler.js
index 04925ec..4b3f11a 100644
--- a/runtime/observatory/web/timeline_message_handler.js
+++ b/runtime/observatory/web/timeline_message_handler.js
@@ -20,6 +20,9 @@
   var params = request['params'];
   console.log('method: ' + method)
   switch (method) {
+    case 'loading':
+      showLoadingOverlay('Fetching timeline...');
+    break;
     case 'refresh':
       traceObject = params;
       if (typeof populateTimeline != 'undefined') {
diff --git a/runtime/tests/vm/dart/causal_stacks/sync_async_start_pkg_test_test.dart b/runtime/tests/vm/dart/causal_stacks/sync_async_start_pkg_test_test.dart
new file mode 100644
index 0000000..e2bcd2f
--- /dev/null
+++ b/runtime/tests/vm/dart/causal_stacks/sync_async_start_pkg_test_test.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2019, 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.
+//
+// This test ensures that "pkg:stack_trace" (used by "pkg:test") doesn't break
+// when causal async stacks are enabled by dropping frames below a synchronous
+// start to an async function.
+
+import "package:test/test.dart";
+import "package:stack_trace/src/stack_zone_specification.dart";
+
+import 'dart:async';
+
+void main() {
+  test("Stacktrace includes sync-starts.", () async {
+    final st = await firstMethod();
+    expect("$st", allOf([contains("firstMethod"), contains("secondMethod")]));
+  });
+}
+
+Future<StackTrace> firstMethod() async {
+  return await secondMethod();
+}
+
+Future<StackTrace> secondMethod() async {
+  return StackTrace.current;
+}
diff --git a/runtime/tests/vm/dart/causal_stacks/utils.dart b/runtime/tests/vm/dart/causal_stacks/utils.dart
index 6038e33..ce5116b 100644
--- a/runtime/tests/vm/dart/causal_stacks/utils.dart
+++ b/runtime/tests/vm/dart/causal_stacks/utils.dart
@@ -124,11 +124,8 @@
 Map<int, String> noYieldsMapCausal = {
   0: '#0      throwSync ',
   1: '#1      noYields3 ',
-  2: '<asynchronous suspension>',
-  3: '#2      noYields2 ',
-  4: '<asynchronous suspension>',
-  5: '#3      noYields ',
-  4: '<asynchronous suspension>',
+  2: '#2      noYields2 ',
+  3: '#3      noYields ',
   // Callers, like doTest and main ..
 };
 
@@ -168,11 +165,9 @@
   0: '#0      throwAsync ',
   1: '<asynchronous suspension>',
   2: '#1      mixedYields3 ',
-  3: '<asynchronous suspension>',
-  4: '#2      mixedYields2 ',
-  5: '<asynchronous suspension>',
-  6: '#3      mixedYields ',
-  7: '<asynchronous suspension>',
+  3: '#2      mixedYields2 ',
+  4: '<asynchronous suspension>',
+  5: '#3      mixedYields ',
   // Callers, like doTest and main ..
 };
 
@@ -207,7 +202,6 @@
   3: '#2      syncSuffix2 ',
   4: '<asynchronous suspension>',
   5: '#3      syncSuffix ',
-  6: '<asynchronous suspension>',
   // Callers, like doTest and main ..
 };
 
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index 9cd25d6..1801067 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -175,6 +175,9 @@
 dart/data_uri_spawn_test: Skip # Please triage.
 dart/snapshot_version_test: RuntimeError # Please triage.
 
+[ $hot_reload || $hot_reload_rollback ]
+dart/isolates/spawn_function_test: Skip # This test explicitly enables isolate groups (off-by-default atm). It will be enabled once full IG reloading is implemented.
+
 [ ($compiler == dartk || $compiler == dartkb) && ($hot_reload || $hot_reload_rollback) ]
 dart/data_uri_spawn_test: Skip # Timeout
 dart/kernel_determinism_test: SkipSlow
diff --git a/runtime/tools/dartfuzz/dartfuzz.dart b/runtime/tools/dartfuzz/dartfuzz.dart
index d47151e..82d0316 100644
--- a/runtime/tools/dartfuzz/dartfuzz.dart
+++ b/runtime/tools/dartfuzz/dartfuzz.dart
@@ -14,7 +14,7 @@
 // Version of DartFuzz. Increase this each time changes are made
 // to preserve the property that a given version of DartFuzz yields
 // the same fuzzed program for a deterministic random seed.
-const String version = '1.65';
+const String version = '1.71';
 
 // Restriction on statements and expressions.
 const int stmtDepth = 1;
@@ -27,6 +27,7 @@
 const int numMethodParams = 4;
 const int numClasses = 4;
 const int numExtensionMethodsPerClass = 3;
+const int numDartTypeExtensions = 5;
 
 // Naming conventions.
 const varName = 'var';
@@ -69,16 +70,15 @@
     fuzzer.emitNewline();
   }
 
-  void emitCall(int depth,
-      {RhsFilter rhsFilter,
-      bool includeSemicolon = false,
-      bool extensionApplication = false}) {
+  String emitCall(int depth,
+      {RhsFilter rhsFilter, bool includeSemicolon = false}) {
     String outputName = name;
     fuzzer.emitLn(outputName, newline: false);
     fuzzer.emitExprList(depth + 1, parameters, rhsFilter: rhsFilter);
     if (includeSemicolon) {
       fuzzer.emit(';');
     }
+    return outputName;
   }
 
   // Main emitter for a method.
@@ -134,10 +134,8 @@
       : super(name, parameters, fuzzer) {}
 
   @override
-  void emitCall(int depth,
-      {RhsFilter rhsFilter,
-      bool includeSemicolon = false,
-      bool extensionApplication = false}) {
+  String emitCall(int depth,
+      {RhsFilter rhsFilter, bool includeSemicolon = false}) {
     String outputName = name;
     if (fuzzer.currentClass == null) {
       // If we're calling an instance method from outside the class, then we
@@ -149,6 +147,7 @@
     if (includeSemicolon) {
       fuzzer.emit(';');
     }
+    return outputName;
   }
 
   final String className;
@@ -157,23 +156,26 @@
 // Class for extension methods generated by DartFuzz.
 class ExtensionMethod extends Method {
   ExtensionMethod(String name, List<DartType> parameters, DartFuzz fuzzer,
-      this.className, this.extensionName)
+      this.className, this.extensionName, this.type)
       : super(name, parameters, fuzzer) {}
-
   @override
-  void emitCall(int depth,
-      {RhsFilter rhsFilter,
-      bool includeSemicolon = false,
-      bool extensionApplication = false}) {
+  String emitCall(int depth,
+      {RhsFilter rhsFilter, bool includeSemicolon = false}) {
     String outputName = name;
-    if (fuzzer.currentClass == null) {
-      // If we're calling an extension method from outside the class, we can
-      // call it using an object of the class or using explicit extension
-      // application.
-      if (extensionApplication) {
-        outputName = "${extensionName}(${className}()).${name}";
+
+    // If we're calling an extension method on a class from outside the class,
+    // we must call it using an object of the class or using explicit extension
+    // application. Extension methods on Dart types are presently always called
+    // using a variable of the Dart type or using explicit extension
+    // application.
+    if (fuzzer.currentClass == null || type != null) {
+      String invokingObject =
+          type != null ? fuzzer.pickScalarVar(type) : "${className}()";
+
+      if (extensionName != null && fuzzer.coinFlip()) {
+        outputName = "${extensionName}(${invokingObject}).${name}";
       } else {
-        outputName = "${className}().${name}";
+        outputName = "${invokingObject}.${name}";
       }
     }
     fuzzer.emitLn(outputName, newline: false);
@@ -181,10 +183,12 @@
     if (includeSemicolon) {
       fuzzer.emit(';');
     }
+    return outputName;
   }
 
   final String className;
   final String extensionName;
+  final DartType type;
 }
 
 // Class that tracks the state of the filter applied to the
@@ -213,54 +217,52 @@
 /// Class that specifies the api for calling library and ffi functions (if
 /// enabled).
 class DartApi {
-  DartApi(bool ffi)
-      : intLibs = [
-          if (ffi) ...const [
-            DartLib('intComputation', 'VIIII'),
-            DartLib('takeMaxUint16', 'VI'),
-            DartLib('sumPlus42', 'VII'),
-            DartLib('returnMaxUint8', 'VV'),
-            DartLib('returnMaxUint16', 'VV'),
-            DartLib('returnMaxUint32', 'VV'),
-            DartLib('returnMinInt8', 'VV'),
-            DartLib('returnMinInt16', 'VV'),
-            DartLib('returnMinInt32', 'VV'),
-            DartLib('takeMinInt16', 'VI'),
-            DartLib('takeMinInt32', 'VI'),
-            DartLib('uintComputation', 'VIIII'),
-            DartLib('sumSmallNumbers', 'VIIIIII'),
-            DartLib('takeMinInt8', 'VI'),
-            DartLib('takeMaxUint32', 'VI'),
-            DartLib('takeMaxUint8', 'VI'),
-            DartLib('minInt64', 'VV'),
-            DartLib('minInt32', 'VV'),
-            // Use small int to avoid overflow divergences due to size
-            // differences in intptr_t on 32-bit and 64-bit platforms.
-            DartLib('sumManyIntsOdd', 'Viiiiiiiiiii'),
-            DartLib('sumManyInts', 'Viiiiiiiiii'),
-            DartLib('regress37069', 'Viiiiiiiiiii'),
-          ],
-          ...DartLib.intLibs,
+  DartApi(bool ffi) : typeToLibraryMethods = DartLib.typeToLibraryMethods {
+    if (ffi) {
+      typeToLibraryMethods[DartType.INT] = [
+        ...const [
+          DartLib('intComputation', 'VIIII'),
+          DartLib('takeMaxUint16', 'VI'),
+          DartLib('sumPlus42', 'VII'),
+          DartLib('returnMaxUint8', 'VV'),
+          DartLib('returnMaxUint16', 'VV'),
+          DartLib('returnMaxUint32', 'VV'),
+          DartLib('returnMinInt8', 'VV'),
+          DartLib('returnMinInt16', 'VV'),
+          DartLib('returnMinInt32', 'VV'),
+          DartLib('takeMinInt16', 'VI'),
+          DartLib('takeMinInt32', 'VI'),
+          DartLib('uintComputation', 'VIIII'),
+          DartLib('sumSmallNumbers', 'VIIIIII'),
+          DartLib('takeMinInt8', 'VI'),
+          DartLib('takeMaxUint32', 'VI'),
+          DartLib('takeMaxUint8', 'VI'),
+          DartLib('minInt64', 'VV'),
+          DartLib('minInt32', 'VV'),
+          // Use small int to avoid overflow divergences due to size
+          // differences in intptr_t on 32-bit and 64-bit platforms.
+          DartLib('sumManyIntsOdd', 'Viiiiiiiiiii'),
+          DartLib('sumManyInts', 'Viiiiiiiiii'),
+          DartLib('regress37069', 'Viiiiiiiiiii'),
         ],
-        doubleLibs = [
-          if (ffi) ...const [
-            DartLib('times1_337Float', 'VD'),
-            DartLib('sumManyDoubles', 'VDDDDDDDDDD'),
-            DartLib('times1_337Double', 'VD'),
-            DartLib('sumManyNumbers', 'VIDIDIDIDIDIDIDIDIDID'),
-            DartLib('inventFloatValue', 'VV'),
-            DartLib('smallDouble', 'VV'),
-          ],
-          ...DartLib.doubleLibs,
-        ];
+        ...DartLib.intLibs,
+      ];
 
-  final boolLibs = DartLib.boolLibs;
-  final stringLibs = DartLib.stringLibs;
-  final listLibs = DartLib.listLibs;
-  final setLibs = DartLib.setLibs;
-  final mapLibs = DartLib.mapLibs;
-  final List<DartLib> intLibs;
-  final List<DartLib> doubleLibs;
+      typeToLibraryMethods[DartType.DOUBLE] = [
+        if (ffi) ...const [
+          DartLib('times1_337Float', 'VD'),
+          DartLib('sumManyDoubles', 'VDDDDDDDDDD'),
+          DartLib('times1_337Double', 'VD'),
+          DartLib('sumManyNumbers', 'VIDIDIDIDIDIDIDIDIDID'),
+          DartLib('inventFloatValue', 'VV'),
+          DartLib('smallDouble', 'VV'),
+        ],
+        ...DartLib.doubleLibs,
+      ];
+    }
+  }
+
+  final typeToLibraryMethods;
 }
 
 /// Class that generates a random, but runnable Dart program for fuzz testing.
@@ -305,6 +307,12 @@
     emitHeader();
     emitVariableDeclarations(varName, globalVars);
     emitMethods(globalMethods);
+    for (int i = 0; i < numDartTypeExtensions; ++i) {
+      DartType type = oneOfSet(dartType.allTypes);
+      emitAndAddExtensionMethods(globalMethods, type.name, "${methodName}E${i}",
+          "${methodName}${i}_Extension",
+          type: type);
+    }
     emitClasses();
     emitMain();
     // Sanity.
@@ -315,13 +323,16 @@
     assert(localVars.isEmpty);
   }
 
-  List<Method> getMethods(int maxMethods, int maxParams, MethodType type,
-      {String className = "", String extensionName = "", String namePrefix}) {
+  List<Method> getMethods(int maxMethods, int maxParams, MethodType methodType,
+      {String className,
+      String extensionName,
+      String namePrefix,
+      DartType type}) {
     final List<Method> list = <Method>[];
     for (int i = 0, n = chooseOneUpTo(maxMethods); i < n; i++) {
-      final List<DartType> params =
-          fillTypes1(limit: maxParams, isFfi: type == MethodType.ffiMethod);
-      switch (type) {
+      final List<DartType> params = fillTypes1(
+          limit: maxParams, isFfi: methodType == MethodType.ffiMethod);
+      switch (methodType) {
         case MethodType.globalMethod:
           list.add(GlobalMethod("${namePrefix}${i}", params, this));
           break;
@@ -333,8 +344,8 @@
               InstanceMethod("${namePrefix}${i}", params, this, className));
           break;
         case MethodType.extensionMethod:
-          list.add(ExtensionMethod(
-              "${namePrefix}${i}", params, this, className, extensionName));
+          list.add(ExtensionMethod("${namePrefix}${i}", params, this, className,
+              extensionName, type));
           break;
       }
     }
@@ -727,23 +738,29 @@
       });
       emitNewline();
       emitNewline();
-      emitExtensionMethods();
+      emitAndAddExtensionMethods(classMethods[currentClass], "X${currentClass}",
+          "XE${currentClass}", "${methodName}${currentClass}_Extension");
       currentClass = null;
     }
   }
 
-  void emitExtensionMethods() {
-    classMethods[currentClass].addAll(getMethods(numExtensionMethodsPerClass,
-        numMethodParams, MethodType.extensionMethod,
-        className: "X${currentClass}",
-        extensionName: "XE${currentClass}",
-        namePrefix: "${methodName}${currentClass}_Extension"));
-    emit("extension XE$currentClass on X$currentClass ");
+  void emitAndAddExtensionMethods(
+      List<Method> methodList, className, extensionName, namePrefix,
+      {DartType type}) {
+    int endIndex = methodList.length;
+    methodList.addAll(getMethods(numExtensionMethodsPerClass, numMethodParams,
+        MethodType.extensionMethod,
+        className: className,
+        // Randomly select between named and anonymous extensions.
+        extensionName: coinFlip() ? extensionName : "",
+        namePrefix: namePrefix,
+        type: type));
+    emit("extension $extensionName on $className ");
     emitBraceWrapped(() {
-      for (int i = 0; i < classMethods[currentClass].length; i++) {
+      // Emit the newly added methods.
+      for (int i = endIndex; i < methodList.length; i++) {
         currentMethod = i;
-        if (classMethods[currentClass][i] is ExtensionMethod)
-          classMethods[currentClass][i].emit();
+        methodList[i].emit();
         currentMethod = null;
       }
     });
@@ -771,24 +788,23 @@
 
         // Call each global method once.
         for (int i = 0; i < globalMethods.length; i++) {
-          final outputName = '$methodName$i';
-          emitTryCatchFinally(() {
-            globalMethods[i].emitCall(1, includeSemicolon: true);
-          }, () {
-            emitPrint('$outputName() throws');
-          });
+          String outputName;
+          emitTryCatchFinally(
+              () => outputName =
+                  globalMethods[i].emitCall(1, includeSemicolon: true),
+              () => emitPrint('$outputName() throws'));
           emitNewline();
         }
 
         // Call each class method once.
         for (int i = 0; i < classMethods.length; i++) {
           for (int j = 0; j < classMethods[i].length; j++) {
+            String outputName;
             emitNewline();
-            emitTryCatchFinally(() {
-              classMethods[i][j].emitCall(1, includeSemicolon: true);
-            }, () {
-              emitPrint('X$i().${classMethods[i][j].name}() throws');
-            });
+            emitTryCatchFinally(
+                () => outputName =
+                    classMethods[i][j].emitCall(1, includeSemicolon: true),
+                () => emitPrint('${outputName} throws'));
           }
           // Call each virtual class method once.
           int parentClass = classParents[i];
@@ -797,12 +813,12 @@
               for (int j = 0;
                   j < virtualClassMethods[i][parentClass].length;
                   j++) {
-                final outputName = 'X${i}().$methodName${parentClass}_${j}';
+                String outputName;
                 emitNewline();
                 emitTryCatchFinally(
-                    () => classMethods[parentClass][j]
+                    () => outputName = classMethods[parentClass][j]
                         .emitCall(1, includeSemicolon: true),
-                    () => emitPrint('$outputName() throws'));
+                    () => emitPrint('${outputName} throws'));
               }
             }
             parentClass = classParents[parentClass];
@@ -897,7 +913,6 @@
 
   // Emit an assignment statement.
   bool emitAssign() {
-    // Select a type at random.
     final tp = oneOfSet(dartType.allTypes);
     String assignOp;
     if (DartType.isGrowableType(tp)) {
@@ -1218,7 +1233,7 @@
       return emitAssign();
     }
     // Possibly nested statement.
-    switch (choose(16)) {
+    switch (choose(17)) {
       // Favors assignment.
       case 0:
         return emitPrint();
@@ -1248,6 +1263,9 @@
         return emitTryCatch(depth);
       case 13:
         return emitForEach(depth);
+      case 14:
+        emitLibraryCall(depth, DartType.VOID, includeSemicolon: true);
+        return true;
       default:
         return emitAssign();
     }
@@ -1564,7 +1582,8 @@
     }
   }
 
-  String emitScalarVar(DartType tp, {bool isLhs = false, RhsFilter rhsFilter}) {
+  // Pick an existing variable of the given type.
+  String pickScalarVar(DartType tp, {bool isLhs = false, RhsFilter rhsFilter}) {
     // Randomly specialize interface type, unless emitting left hand side.
     if (!isLhs) tp = maybeSpecializeInterface(tp);
     // Collect all choices from globals, fields, locals, and parameters.
@@ -1617,11 +1636,18 @@
     if (choices.isEmpty) {
       throw 'No variable to emit for type ${tp.name}';
     }
-    final emittedVar = '${choices.elementAt(choose(choices.length))}';
-    if (rhsFilter != null && (emittedVar == rhsFilter.lhsVar)) {
-      rhsFilter.consume();
+
+    return '${choices.elementAt(choose(choices.length))}';
+  }
+
+  String emitScalarVar(DartType tp, {bool isLhs = false, RhsFilter rhsFilter}) {
+    final emittedVar = pickScalarVar(tp, isLhs: isLhs, rhsFilter: rhsFilter);
+    if (emittedVar != null) {
+      if (rhsFilter != null && (emittedVar == rhsFilter.lhsVar)) {
+        rhsFilter.consume();
+      }
+      emit(emittedVar);
     }
-    emit(emittedVar);
     return emittedVar;
   }
 
@@ -1761,31 +1787,45 @@
     }
   }
 
+  bool isTypedDataFloatType(String proto) {
+    for (int i = 0; i < proto.length; ++i) {
+      if (DartLib.typedDataFloatTypes.contains(proto[i])) {
+        return true;
+      }
+    }
+    return false;
+  }
+
   // Emit library call.
-  void emitLibraryCall(int depth, DartType tp, {RhsFilter rhsFilter}) {
+  void emitLibraryCall(int depth, DartType tp,
+      {RhsFilter rhsFilter, bool includeSemicolon = false}) {
     DartLib lib = getLibraryMethod(tp);
-    if (lib == null) {
-      // no matching lib: resort to literal.
+    if (lib == null || (!fp && isTypedDataFloatType(lib.proto))) {
+      // We cannot find a library method, or we found a library method but its
+      // prototype has a floating point type, and fp is disabled. This can only
+      // happen for non-void types. In those cases, we resort to a literal.
+      assert(tp != DartType.VOID);
       emitLiteral(depth + 1, tp, rhsFilter: rhsFilter);
       return;
     }
     emitParenWrapped(() {
-      String proto = lib.proto;
+      String prototype = lib.proto;
       // Receiver.
-      if (proto[0] != 'V') {
+      if (prototype[0] != 'V') {
         emitParenWrapped(
-            () => emitArg(depth + 1, proto[0], rhsFilter: rhsFilter));
+            () => emitArg(depth + 1, prototype[0], rhsFilter: rhsFilter));
         emit('.');
       }
       // Call.
       emit('${lib.name}');
       // Parameters.
-      if (proto[1] != 'v') {
+      if (prototype[1] != 'v') {
         emitParenWrapped(() {
-          if (proto[1] != 'V') {
+          if (prototype[1] != 'V') {
             emitCommaSeparated(
-                (int i) => emitArg(depth + 1, proto[i], rhsFilter: rhsFilter),
-                proto.length,
+                (int i) =>
+                    emitArg(depth + 1, prototype[i], rhsFilter: rhsFilter),
+                prototype.length,
                 start: 1);
           }
         });
@@ -1795,6 +1835,9 @@
         emit(' as ${tp.name}');
       }
     });
+    if (includeSemicolon) {
+      emit(';');
+    }
   }
 
   // Helper for a method call.
@@ -1802,9 +1845,7 @@
       {RhsFilter rhsFilter}) {
     for (int i = m - 1; i >= 0; i--) {
       if (tp == methods[i].returnType) {
-        bool extensionApplication = methods[i] is ExtensionMethod && coinFlip();
-        methods[i].emitCall(depth + 1,
-            rhsFilter: rhsFilter, extensionApplication: extensionApplication);
+        methods[i].emitCall(depth + 1, rhsFilter: rhsFilter);
         return true;
       }
     }
@@ -1917,58 +1958,29 @@
   //
 
   // Get a library method that returns given type.
-  DartLib getLibraryMethod(DartType tp) {
-    if (tp == DartType.BOOL) {
-      return oneOf(api.boolLibs);
-    } else if (tp == DartType.INT) {
-      return oneOf(api.intLibs);
-    } else if (tp == DartType.DOUBLE) {
-      return oneOf(api.doubleLibs);
-    } else if (tp == DartType.STRING) {
-      return oneOf(DartLib.stringLibs);
-    } else if (tp == DartType.LIST_INT) {
-      return oneOf(DartLib.listLibs);
-    } else if (tp == DartType.SET_INT) {
-      return oneOf(DartLib.setLibs);
-    } else if (tp == DartType.MAP_INT_STRING) {
-      return oneOf(DartLib.mapLibs);
-    }
-    // No library method available that returns this type.
-    return null;
-  }
+  DartLib getLibraryMethod(DartType tp) =>
+      api.typeToLibraryMethods.containsKey(tp)
+          ? oneOf(api.typeToLibraryMethods[tp])
+          : null;
 
   // Emit a library argument, possibly subject to restrictions.
   void emitArg(int depth, String p, {RhsFilter rhsFilter}) {
     switch (p) {
-      case 'B':
-        emitExpr(depth, DartType.BOOL);
-        break;
       case 'i': // emit small int
         emitSmallPositiveInt();
         break;
-      case 'I':
-        emitExpr(depth, DartType.INT);
-        break;
-      case 'D':
+      case 'D': // resort to INT if floating point is disabled
         emitExpr(depth, fp ? DartType.DOUBLE : DartType.INT);
         break;
-      case 'S':
-        emitExpr(depth, DartType.STRING, rhsFilter: rhsFilter);
-        break;
       case 's': // emit small string
         emitString(length: 2);
         break;
-      case 'L':
-        emitExpr(depth, DartType.LIST_INT, rhsFilter: rhsFilter);
-        break;
-      case 'X':
-        emitExpr(depth, DartType.SET_INT, rhsFilter: rhsFilter);
-        break;
-      case 'M':
-        emitExpr(depth, DartType.MAP_INT_STRING, rhsFilter: rhsFilter);
-        break;
       default:
-        throw ArgumentError('Invalid p value: $p');
+        DartType type = DartLib.stringToType[p];
+        if (type == null) {
+          throw ArgumentError('Invalid p value: $p');
+        }
+        emitExpr(depth, type, rhsFilter: rhsFilter);
     }
   }
 
diff --git a/runtime/tools/dartfuzz/dartfuzz_api_table.dart b/runtime/tools/dartfuzz/dartfuzz_api_table.dart
index 26e4852..c2f5948 100644
--- a/runtime/tools/dartfuzz/dartfuzz_api_table.dart
+++ b/runtime/tools/dartfuzz/dartfuzz_api_table.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 "dartfuzz_type_table.dart";
+
 /// Class that represents Dart library methods.
 ///
 /// The invididual lists are organized by return type.
@@ -24,7 +26,23 @@
 ///   L List<int>
 ///   X Set<int>
 ///   M Map<int, String>
-///
+///   A Int8List
+///   C Int16List
+///   E Int32List
+///   F Int32x4
+///   G Int32x4List
+///   H Int64List
+///   J Float32List
+///   K Float32x4
+///   N Float32x4List
+///   O Float64List
+///   P Float64x2
+///   Q Float64x2List
+///   R uint8ClampedList
+///   T uint8List
+///   U uint16List
+///   W uint32List
+///   Y uint64List
 /// NOTE: this code has been generated automatically.
 ///
 class DartLib {
@@ -32,12 +50,90 @@
   final String proto;
   const DartLib(this.name, this.proto);
 
+  static const stringToType = {
+    'V': DartType.VOID,
+    'B': DartType.BOOL,
+    'I': DartType.INT,
+    'D': DartType.DOUBLE,
+    'S': DartType.STRING,
+    'L': DartType.LIST_INT,
+    'X': DartType.SET_INT,
+    'M': DartType.MAP_INT_STRING,
+    'A': DartType.INT8LIST,
+    'C': DartType.INT16LIST,
+    'E': DartType.INT32LIST,
+    'F': DartType.INT32X4,
+    'G': DartType.INT32X4LIST,
+    'H': DartType.INT64LIST,
+    'J': DartType.FLOAT32LIST,
+    'K': DartType.FLOAT32X4,
+    'N': DartType.FLOAT32X4LIST,
+    'O': DartType.FLOAT64LIST,
+    'P': DartType.FLOAT64X2,
+    'Q': DartType.FLOAT64X2LIST,
+    'R': DartType.UINT8CLAMPEDLIST,
+    'T': DartType.UINT8LIST,
+    'U': DartType.UINT16LIST,
+    'W': DartType.UINT32LIST,
+    'Y': DartType.UINT64LIST,
+  };
+  static final typeToLibraryMethods = {
+    DartType.VOID: voidLibs,
+    DartType.BOOL: boolLibs,
+    DartType.INT: intLibs,
+    DartType.DOUBLE: doubleLibs,
+    DartType.STRING: stringLibs,
+    DartType.LIST_INT: listLibs,
+    DartType.SET_INT: setLibs,
+    DartType.MAP_INT_STRING: mapLibs,
+    DartType.INT8LIST: int8ListLibs,
+    DartType.INT16LIST: int16ListLibs,
+    DartType.INT32LIST: int32ListLibs,
+    DartType.INT32X4: int32x4Libs,
+    DartType.INT32X4LIST: int32x4ListLibs,
+    DartType.INT64LIST: int64ListLibs,
+    DartType.FLOAT32LIST: float32ListLibs,
+    DartType.FLOAT32X4: float32x4Libs,
+    DartType.FLOAT32X4LIST: float32x4ListLibs,
+    DartType.FLOAT64LIST: float64ListLibs,
+    DartType.FLOAT64X2: float64x2Libs,
+    DartType.FLOAT64X2LIST: float64x2ListLibs,
+    DartType.UINT8CLAMPEDLIST: uint8ClampedListLibs,
+    DartType.UINT8LIST: uint8ListLibs,
+    DartType.UINT16LIST: uint16ListLibs,
+    DartType.UINT32LIST: uint32ListLibs,
+    DartType.UINT64LIST: uint64ListLibs,
+  };
+  static const typedDataFloatTypes = [
+    'J',
+    'K',
+    'N',
+    'O',
+    'P',
+    'Q',
+  ];
+  static const voidLibs = [
+    DartLib('RangeError.checkNotNegative', 'VISS'),
+    DartLib('RangeError.checkValueInInterval', 'VIIISS'),
+    DartLib('add', 'LI'),
+    DartLib('addAll', 'MM'),
+    DartLib('clear', 'LV'),
+    DartLib('clear', 'MV'),
+    DartLib('clear', 'XV'),
+    DartLib('fillRange', 'LIII'),
+    DartLib('insert', 'LII'),
+    DartLib('removeRange', 'LII'),
+  ];
   static const boolLibs = [
     DartLib('NetworkInterface.listSupported', 'Vv'),
     DartLib('SecurityContext.alpnSupported', 'Vv'),
     DartLib('add', 'XI'),
     DartLib('bool.fromEnvironment', 'VS'),
     DartLib('endsWith', 'SS'),
+    DartLib('flagW', 'Fv'),
+    DartLib('flagX', 'Fv'),
+    DartLib('flagY', 'Fv'),
+    DartLib('flagZ', 'Fv'),
     DartLib('isEmpty', 'Mv'),
     DartLib('isEmpty', 'Sv'),
     DartLib('isEven', 'Iv'),
@@ -658,8 +754,8 @@
     DartLib('ceil', 'DV'),
     DartLib('ceil', 'IV'),
     DartLib('codeUnitAt', 'SI'),
-    DartLib('compareTo', 'DD'),
     DartLib('compareTo', 'SS'),
+    DartLib('compareTo', 'DD'),
     DartLib('floor', 'IV'),
     DartLib('floor', 'DV'),
     DartLib('floor', 'DV'),
@@ -670,8 +766,8 @@
     DartLib('int.tryParse', 'VS'),
     DartLib('lastIndexOf', 'LII'),
     DartLib('length', 'Mv'),
-    DartLib('length', 'Lv'),
     DartLib('length', 'Sv'),
+    DartLib('length', 'Lv'),
     DartLib('modInverse', 'II'),
     DartLib('modPow', 'III'),
     DartLib('removeAt', 'LI'),
@@ -680,14 +776,21 @@
     DartLib('round', 'IV'),
     DartLib('round', 'DV'),
     DartLib('sign', 'Iv'),
+    DartLib('signMask', 'Pv'),
+    DartLib('signMask', 'Kv'),
+    DartLib('signMask', 'Fv'),
     DartLib('toInt', 'DV'),
     DartLib('toSigned', 'II'),
     DartLib('toUnsigned', 'II'),
-    DartLib('truncate', 'DV'),
     DartLib('truncate', 'IV'),
     DartLib('truncate', 'DV'),
+    DartLib('truncate', 'DV'),
     DartLib('unicodeBomCharacterRune', 'Vv'),
     DartLib('unicodeReplacementCharacterRune', 'Vv'),
+    DartLib('w', 'Fv'),
+    DartLib('x', 'Fv'),
+    DartLib('y', 'Fv'),
+    DartLib('z', 'Fv'),
   ];
   static const doubleLibs = [
     DartLib('abs', 'DV'),
@@ -697,8 +800,8 @@
     DartLib('atan', 'VD'),
     DartLib('atan2', 'VDD'),
     DartLib('ceilToDouble', 'DV'),
-    DartLib('ceilToDouble', 'DV'),
     DartLib('ceilToDouble', 'IV'),
+    DartLib('ceilToDouble', 'DV'),
     DartLib('clamp', 'DDD'),
     DartLib('cos', 'VD'),
     DartLib('double.infinity', 'Vv'),
@@ -733,9 +836,15 @@
     DartLib('sqrt2', 'Vv'),
     DartLib('tan', 'VD'),
     DartLib('toDouble', 'DV'),
+    DartLib('truncateToDouble', 'DV'),
     DartLib('truncateToDouble', 'IV'),
     DartLib('truncateToDouble', 'DV'),
-    DartLib('truncateToDouble', 'DV'),
+    DartLib('w', 'Kv'),
+    DartLib('x', 'Kv'),
+    DartLib('x', 'Pv'),
+    DartLib('y', 'Pv'),
+    DartLib('y', 'Kv'),
+    DartLib('z', 'Kv'),
   ];
   static const stringLibs = [
     DartLib('ListBase.listToString', 'VL'),
@@ -771,23 +880,129 @@
     DartLib('trimRight', 'SV'),
   ];
   static const listLibs = [
-    DartLib('List.filled', 'ViI'),
+    DartLib('List<int>.filled', 'ViI'),
     DartLib('Uri.parseIPv4Address', 'VS'),
     DartLib('Uri.parseIPv6Address', 'VSII'),
     DartLib('codeUnits', 'Sv'),
     DartLib('sublist', 'LII'),
   ];
   static const setLibs = [
-    DartLib('Set.identity', 'VV'),
+    DartLib('Set<int>.identity', 'VV'),
     DartLib('difference', 'XX'),
     DartLib('intersection', 'XX'),
     DartLib('toSet', 'XV'),
     DartLib('union', 'XX'),
   ];
   static const mapLibs = [
-    DartLib('Map.from', 'VM'),
-    DartLib('Map.identity', 'VV'),
-    DartLib('Map.of', 'VM'),
-    DartLib('Map.unmodifiable', 'VM'),
+    DartLib('Map<int, String>.from', 'VM'),
+    DartLib('Map<int, String>.identity', 'VV'),
+    DartLib('Map<int, String>.of', 'VM'),
+    DartLib('Map<int, String>.unmodifiable', 'VM'),
+  ];
+  static const int8ListLibs = [
+    DartLib('Int8List.fromList', 'VL'),
+    DartLib('sublist', 'AII'),
+  ];
+  static const int16ListLibs = [
+    DartLib('Int16List.fromList', 'VL'),
+    DartLib('sublist', 'CII'),
+  ];
+  static const int32ListLibs = [
+    DartLib('Int32List.fromList', 'VL'),
+    DartLib('sublist', 'EII'),
+  ];
+  static const int32x4Libs = [
+    DartLib('Int32x4.bool', 'VBBBB'),
+    DartLib('Int32x4.fromFloat32x4Bits', 'VK'),
+    DartLib('equal', 'KK'),
+    DartLib('greaterThan', 'KK'),
+    DartLib('greaterThanOrEqual', 'KK'),
+    DartLib('lessThan', 'KK'),
+    DartLib('lessThanOrEqual', 'KK'),
+    DartLib('notEqual', 'KK'),
+    DartLib('shuffle', 'FI'),
+    DartLib('shuffleMix', 'FFI'),
+    DartLib('withFlagW', 'FB'),
+    DartLib('withFlagX', 'FB'),
+    DartLib('withFlagY', 'FB'),
+    DartLib('withFlagZ', 'FB'),
+    DartLib('withW', 'FI'),
+    DartLib('withX', 'FI'),
+    DartLib('withY', 'FI'),
+    DartLib('withZ', 'FI'),
+  ];
+  static const int32x4ListLibs = [
+    DartLib('sublist', 'GII'),
+  ];
+  static const int64ListLibs = [
+    DartLib('Int64List.fromList', 'VL'),
+    DartLib('sublist', 'HII'),
+  ];
+  static const float32ListLibs = [
+    DartLib('sublist', 'JII'),
+  ];
+  static const float32x4Libs = [
+    DartLib('Float32x4.fromFloat64x2', 'VP'),
+    DartLib('Float32x4.fromInt32x4Bits', 'VF'),
+    DartLib('Float32x4.splat', 'VD'),
+    DartLib('Float32x4.zero', 'VV'),
+    DartLib('abs', 'KV'),
+    DartLib('clamp', 'KKK'),
+    DartLib('max', 'KK'),
+    DartLib('min', 'KK'),
+    DartLib('reciprocal', 'KV'),
+    DartLib('reciprocalSqrt', 'KV'),
+    DartLib('scale', 'KD'),
+    DartLib('select', 'FKK'),
+    DartLib('shuffle', 'KI'),
+    DartLib('shuffleMix', 'KKI'),
+    DartLib('sqrt', 'KV'),
+    DartLib('withW', 'KD'),
+    DartLib('withX', 'KD'),
+    DartLib('withY', 'KD'),
+    DartLib('withZ', 'KD'),
+  ];
+  static const float32x4ListLibs = [
+    DartLib('sublist', 'NII'),
+  ];
+  static const float64ListLibs = [
+    DartLib('sublist', 'OII'),
+  ];
+  static const float64x2Libs = [
+    DartLib('Float64x2.fromFloat32x4', 'VK'),
+    DartLib('Float64x2.splat', 'VD'),
+    DartLib('Float64x2.zero', 'VV'),
+    DartLib('abs', 'PV'),
+    DartLib('clamp', 'PPP'),
+    DartLib('max', 'PP'),
+    DartLib('min', 'PP'),
+    DartLib('scale', 'PD'),
+    DartLib('sqrt', 'PV'),
+    DartLib('withX', 'PD'),
+    DartLib('withY', 'PD'),
+  ];
+  static const float64x2ListLibs = [
+    DartLib('sublist', 'QII'),
+  ];
+  static const uint8ClampedListLibs = [
+    DartLib('Uint8ClampedList.fromList', 'VL'),
+    DartLib('sublist', 'RII'),
+  ];
+  static const uint8ListLibs = [
+    DartLib('Uint8List.fromList', 'VL'),
+    DartLib('base64Decode', 'VS'),
+    DartLib('sublist', 'TII'),
+  ];
+  static const uint16ListLibs = [
+    DartLib('Uint16List.fromList', 'VL'),
+    DartLib('sublist', 'UII'),
+  ];
+  static const uint32ListLibs = [
+    DartLib('Uint32List.fromList', 'VL'),
+    DartLib('sublist', 'WII'),
+  ];
+  static const uint64ListLibs = [
+    DartLib('Uint64List.fromList', 'VL'),
+    DartLib('sublist', 'YII'),
   ];
 }
diff --git a/runtime/tools/dartfuzz/dartfuzz_type_table.dart b/runtime/tools/dartfuzz/dartfuzz_type_table.dart
index bcd16d2..889b210 100644
--- a/runtime/tools/dartfuzz/dartfuzz_type_table.dart
+++ b/runtime/tools/dartfuzz/dartfuzz_type_table.dart
@@ -148,6 +148,7 @@
     return _allTypes;
   }
 
+  static const VOID = const DartType._withName("void");
   static const INT8LIST = const DartType._withName("Int8List");
   static const UINT8LIST = const DartType._withName("Uint8List");
   static const UINT8CLAMPEDLIST = const DartType._withName("Uint8ClampedList");
@@ -2939,6 +2940,8 @@
     return _allTypes;
   }
 
+  static const VOID = const DartType._withName("void");
+
   // All types extracted from analyzer.
   static const _allTypes = {
     DartType.INT8LIST,
@@ -4649,6 +4652,8 @@
     return _allTypes;
   }
 
+  static const VOID = const DartType._withName("void");
+
   // All types extracted from analyzer.
   static const _allTypes = {
     DartType.INT8LIST,
@@ -6576,6 +6581,8 @@
     return _allTypes;
   }
 
+  static const VOID = const DartType._withName("void");
+
   // All types extracted from analyzer.
   static const _allTypes = {
     DartType.INT8LIST,
diff --git a/runtime/tools/dartfuzz/gen_api_table.dart b/runtime/tools/dartfuzz/gen_api_table.dart
index f8f2ba1..a2f7a6b 100644
--- a/runtime/tools/dartfuzz/gen_api_table.dart
+++ b/runtime/tools/dartfuzz/gen_api_table.dart
@@ -29,6 +29,7 @@
 }
 
 // Lists of recognized methods, organized by return type.
+var voidTable = <DartLib>[];
 var boolTable = <DartLib>[];
 var intTable = <DartLib>[];
 var doubleTable = <DartLib>[];
@@ -36,6 +37,140 @@
 var listTable = <DartLib>[];
 var setTable = <DartLib>[];
 var mapTable = <DartLib>[];
+var int8ListTable = <DartLib>[];
+var int16ListTable = <DartLib>[];
+var int32ListTable = <DartLib>[];
+var int32x4Table = <DartLib>[];
+var int32x4ListTable = <DartLib>[];
+var int64ListTable = <DartLib>[];
+var float32ListTable = <DartLib>[];
+var float32x4ListTable = <DartLib>[];
+var float32x4Table = <DartLib>[];
+var float64ListTable = <DartLib>[];
+var float64x2Table = <DartLib>[];
+var float64x2ListTable = <DartLib>[];
+var uint8ClampedListTable = <DartLib>[];
+var uint8ListTable = <DartLib>[];
+var uint16ListTable = <DartLib>[];
+var uint32ListTable = <DartLib>[];
+var uint64ListTable = <DartLib>[];
+
+const voidEncoding = 'V';
+const boolEncoding = 'B';
+const intEncoding = 'I';
+const doubleEncoding = 'D';
+const stringEncoding = 'S';
+const listEncoding = 'L';
+const setEncoding = 'X';
+const mapEncoding = 'M';
+const int8ListEncoding = 'A';
+const int16ListEncoding = 'C';
+const int32ListEncoding = 'E';
+const int32x4Encoding = 'F';
+const int32x4ListEncoding = 'G';
+const int64ListEncoding = 'H';
+const float32ListEncoding = 'J';
+const float32x4Encoding = 'K';
+const float32x4ListEncoding = 'N';
+const float64ListEncoding = 'O';
+const float64x2Encoding = 'P';
+const float64x2ListEncoding = 'Q';
+const uint8ClampedListEncoding = 'R';
+const uint8ListEncoding = 'T';
+const uint16ListEncoding = 'U';
+const uint32ListEncoding = 'W';
+const uint64ListEncoding = 'Y';
+
+final voidLibs = 'voidLibs';
+final boolLibs = 'boolLibs';
+final intLibs = 'intLibs';
+final doubleLibs = 'doubleLibs';
+final stringLibs = 'stringLibs';
+final listLibs = 'listLibs';
+final setLibs = 'setLibs';
+final mapLibs = 'mapLibs';
+final int8ListLibs = 'int8ListLibs';
+final int16ListLibs = 'int16ListLibs';
+final int32ListLibs = 'int32ListLibs';
+final int32x4Libs = 'int32x4Libs';
+final int32x4ListLibs = 'int32x4ListLibs';
+final int64ListLibs = 'int64ListLibs';
+final float32ListLibs = 'float32ListLibs';
+final float32x4Libs = 'float32x4Libs';
+final float32x4ListLibs = 'float32x4ListLibs';
+final float64ListLibs = 'float64ListLibs';
+final float64x2Libs = 'float64x2Libs';
+final float64x2ListLibs = 'float64x2ListLibs';
+final uint8ClampedListLibs = 'uint8ClampedListLibs';
+final uint8ListLibs = 'uint8ListLibs';
+final uint16ListLibs = 'uint16ListLibs';
+final uint32ListLibs = 'uint32ListLibs';
+final uint64ListLibs = 'uint64ListLibs';
+
+final stringToType = {
+  voidEncoding: 'DartType.VOID',
+  boolEncoding: 'DartType.BOOL',
+  intEncoding: 'DartType.INT',
+  doubleEncoding: 'DartType.DOUBLE',
+  stringEncoding: 'DartType.STRING',
+  listEncoding: 'DartType.LIST_INT',
+  setEncoding: 'DartType.SET_INT',
+  mapEncoding: 'DartType.MAP_INT_STRING',
+  int8ListEncoding: 'DartType.INT8LIST',
+  int16ListEncoding: 'DartType.INT16LIST',
+  int32ListEncoding: 'DartType.INT32LIST',
+  int32x4Encoding: 'DartType.INT32X4',
+  int32x4ListEncoding: 'DartType.INT32X4LIST',
+  int64ListEncoding: 'DartType.INT64LIST',
+  float32ListEncoding: 'DartType.FLOAT32LIST',
+  float32x4Encoding: 'DartType.FLOAT32X4',
+  float32x4ListEncoding: 'DartType.FLOAT32X4LIST',
+  float64ListEncoding: 'DartType.FLOAT64LIST',
+  float64x2Encoding: 'DartType.FLOAT64X2',
+  float64x2ListEncoding: 'DartType.FLOAT64X2LIST',
+  uint8ClampedListEncoding: 'DartType.UINT8CLAMPEDLIST',
+  uint8ListEncoding: 'DartType.UINT8LIST',
+  uint16ListEncoding: 'DartType.UINT16LIST',
+  uint32ListEncoding: 'DartType.UINT32LIST',
+  uint64ListEncoding: 'DartType.UINT64LIST'
+};
+
+final typeToLibraryMethods = {
+  'DartType.VOID': voidLibs,
+  'DartType.BOOL': boolLibs,
+  'DartType.INT': intLibs,
+  'DartType.DOUBLE': doubleLibs,
+  'DartType.STRING': stringLibs,
+  'DartType.LIST_INT': listLibs,
+  'DartType.SET_INT': setLibs,
+  'DartType.MAP_INT_STRING': mapLibs,
+  'DartType.INT8LIST': int8ListLibs,
+  'DartType.INT16LIST': int16ListLibs,
+  'DartType.INT32LIST': int32ListLibs,
+  'DartType.INT32X4': int32x4Libs,
+  'DartType.INT32X4LIST': int32x4ListLibs,
+  'DartType.INT64LIST': int64ListLibs,
+  'DartType.FLOAT32LIST': float32ListLibs,
+  'DartType.FLOAT32X4': float32x4Libs,
+  'DartType.FLOAT32X4LIST': float32x4ListLibs,
+  'DartType.FLOAT64LIST': float64ListLibs,
+  'DartType.FLOAT64X2': float64x2Libs,
+  'DartType.FLOAT64X2LIST': float64x2ListLibs,
+  'DartType.UINT8CLAMPEDLIST': uint8ClampedListLibs,
+  'DartType.UINT8LIST': uint8ListLibs,
+  'DartType.UINT16LIST': uint16ListLibs,
+  'DartType.UINT32LIST': uint32ListLibs,
+  'DartType.UINT64LIST': uint64ListLibs
+};
+
+final typedDataFloatTypes = [
+  float32ListEncoding,
+  float32x4Encoding,
+  float32x4ListEncoding,
+  float64ListEncoding,
+  float64x2Encoding,
+  float64x2ListEncoding
+];
 
 main() async {
   final AnalysisSession session = GenUtil.createAnalysisSession();
@@ -53,13 +188,34 @@
 
   // Generate the tables in a stand-alone Dart class.
   dumpHeader();
-  dumpTable('boolLibs', boolTable);
-  dumpTable('intLibs', intTable);
-  dumpTable('doubleLibs', doubleTable);
-  dumpTable('stringLibs', stringTable);
-  dumpTable('listLibs', listTable);
-  dumpTable('setLibs', setTable);
-  dumpTable('mapLibs', mapTable);
+  dumpStringToTypeMap();
+  dumpTypeToLibraryMethodMap();
+  dumpTypedDataFloatTypes();
+  dumpTable(voidLibs, voidTable);
+  dumpTable(boolLibs, boolTable);
+  dumpTable(intLibs, intTable);
+  dumpTable(doubleLibs, doubleTable);
+  dumpTable(stringLibs, stringTable);
+  dumpTable(listLibs, listTable);
+  dumpTable(setLibs, setTable);
+  dumpTable(mapLibs, mapTable);
+  dumpTable(int8ListLibs, int8ListTable);
+  dumpTable(int16ListLibs, int16ListTable);
+  dumpTable(int32ListLibs, int32ListTable);
+  dumpTable(int32x4Libs, int32x4Table);
+  dumpTable(int32x4ListLibs, int32x4ListTable);
+  dumpTable(int64ListLibs, int64ListTable);
+  dumpTable(float32ListLibs, float32ListTable);
+  dumpTable(float32x4Libs, float32x4Table);
+  dumpTable(float32x4ListLibs, float32x4ListTable);
+  dumpTable(float64ListLibs, float64ListTable);
+  dumpTable(float64x2Libs, float64x2Table);
+  dumpTable(float64x2ListLibs, float64x2ListTable);
+  dumpTable(uint8ClampedListLibs, uint8ClampedListTable);
+  dumpTable(uint8ListLibs, uint8ListTable);
+  dumpTable(uint16ListLibs, uint16ListTable);
+  dumpTable(uint32ListLibs, uint32ListTable);
+  dumpTable(uint64ListLibs, uint64ListTable);
   dumpFooter();
 }
 
@@ -122,7 +278,7 @@
         constructor.name.isNotEmpty) {
       addToTable(
           typeString(classElement.thisType),
-          '${classElement.name}.${constructor.name}',
+          '${classString(classElement)}.${constructor.name}',
           protoString(null, constructor.parameters));
     }
   }
@@ -131,7 +287,7 @@
       if (method.isStatic) {
         addToTable(
             typeString(method.returnType),
-            '${classElement.name}.${method.name}',
+            '${classString(classElement)}.${method.name}',
             protoString(null, method.parameters));
       } else {
         addToTable(typeString(method.returnType), method.name,
@@ -153,50 +309,101 @@
   }
 }
 
+// Function that returns the explicit class name.
+String classString(ClassElement classElement) {
+  switch (typeString(classElement.thisType)) {
+    case setEncoding:
+      return 'Set<int>';
+    case listEncoding:
+      return 'List<int>';
+    case mapEncoding:
+      return 'Map<int, String>';
+    default:
+      return classElement.name;
+  }
+}
+
 // Types are represented by an instance of `DartType`. For classes, the type
 // will be an instance of `InterfaceType`, which will provide access to the
 // defining (class) element, as well as any type arguments.
 String typeString(DartType type) {
   if (type.isDartCoreBool) {
-    return 'B';
+    return boolEncoding;
   } else if (type.isDartCoreInt) {
-    return 'I';
+    return intEncoding;
   } else if (type.isDartCoreDouble) {
-    return 'D';
+    return doubleEncoding;
   } else if (type.isDartCoreString) {
-    return 'S';
+    return stringEncoding;
   }
   // Supertypes or type parameters are specialized in a consistent manner.
   // TODO(ajcbik): inspect type structure semantically, not by display name
   //               and unify DartFuzz's DartType with analyzer DartType.
   switch (type.displayName) {
+    case 'void':
+      return voidEncoding;
     case 'E':
-      return 'I';
+      return intEncoding;
     case 'num':
-      return 'D';
+      return doubleEncoding;
     case 'List<E>':
     case 'List<Object>':
     case 'List<dynamic>':
     case 'List<int>':
     case 'List':
-      return 'L';
+      return listEncoding;
     case 'Set<E>':
     case 'Set<Object>':
     case 'Set<dynamic>':
     case 'Set<int>':
     case 'Set':
-      return 'X';
+      return setEncoding;
     case 'Map<K, V>':
     case 'Map<dynamic, dynamic>':
     case 'Map<int, String>':
     case 'Map':
-      return 'M';
+      return mapEncoding;
+    // TypedData types.
+    case 'Int8List':
+      return int8ListEncoding;
+    case 'Int16List':
+      return int16ListEncoding;
+    case 'Int32List':
+      return int32ListEncoding;
+    case 'Int32x4':
+      return int32x4Encoding;
+    case 'Int32x4List':
+      return int32x4ListEncoding;
+    case 'Int64List':
+      return int64ListEncoding;
+    case 'Float32List':
+      return float32ListEncoding;
+    case 'Float32x4':
+      return float32x4Encoding;
+    case 'Float32x4List':
+      return float32x4ListEncoding;
+    case 'Float64List':
+      return float64ListEncoding;
+    case 'Float64x2':
+      return float64x2Encoding;
+    case 'Float64x2List':
+      return float64x2ListEncoding;
+    case 'Uint8ClampedList':
+      return uint8ClampedListEncoding;
+    case 'Uint8List':
+      return uint8ListEncoding;
+    case 'Uint16List':
+      return uint16ListEncoding;
+    case 'Uint32List':
+      return uint32ListEncoding;
+    case 'Uint64List':
+      return uint64ListEncoding;
   }
   return '?';
 }
 
 String protoString(DartType receiver, List<ParameterElement> parameters) {
-  var proto = receiver == null ? 'V' : typeString(receiver);
+  var proto = receiver == null ? voidEncoding : typeString(receiver);
   // Construct prototype for non-named parameters.
   for (ParameterElement parameter in parameters) {
     if (!parameter.isNamed) {
@@ -204,25 +411,62 @@
     }
   }
   // Use 'void' for an empty parameter list.
-  return proto.length == 1 ? proto + 'V' : proto;
+  return proto.length == 1 ? proto + voidEncoding : proto;
 }
 
 List<DartLib> getTable(String ret) {
   switch (ret) {
-    case 'B':
+    case voidEncoding:
+      return voidTable;
+    case boolEncoding:
       return boolTable;
-    case 'I':
+    case intEncoding:
       return intTable;
-    case 'D':
+    case doubleEncoding:
       return doubleTable;
-    case 'S':
+    case stringEncoding:
       return stringTable;
-    case 'L':
+    case listEncoding:
       return listTable;
-    case 'X':
+    case setEncoding:
       return setTable;
-    case 'M':
+    case mapEncoding:
       return mapTable;
+    // TypedData types.
+    case int8ListEncoding:
+      return int8ListTable;
+    case int16ListEncoding:
+      return int16ListTable;
+    case int32ListEncoding:
+      return int32ListTable;
+    case int32x4Encoding:
+      return int32x4Table;
+    case int32x4ListEncoding:
+      return int32x4ListTable;
+    case int64ListEncoding:
+      return int64ListTable;
+    case float32ListEncoding:
+      return float32ListTable;
+    case float32x4Encoding:
+      return float32x4Table;
+    case float32x4ListEncoding:
+      return float32x4ListTable;
+    case float64ListEncoding:
+      return float64ListTable;
+    case float64x2Encoding:
+      return float64x2Table;
+    case float64x2ListEncoding:
+      return float64x2ListTable;
+    case uint8ClampedListEncoding:
+      return uint8ClampedListTable;
+    case uint8ListEncoding:
+      return uint8ListTable;
+    case uint16ListEncoding:
+      return uint16ListTable;
+    case uint32ListEncoding:
+      return uint32ListTable;
+    case uint64ListEncoding:
+      return uint64ListTable;
     default:
       throw ArgumentError('Invalid ret value: $ret');
   }
@@ -235,8 +479,11 @@
   if (ret.contains('?') || proto.contains('?')) {
     return;
   }
-  // Avoid some obvious false divergences.
-  if (name == 'pid' || name == 'hashCode' || name == 'exitCode') {
+  // Avoid the exit function and other functions that give false divergences.
+  if (name == 'exit' ||
+      name == 'pid' ||
+      name == 'hashCode' ||
+      name == 'exitCode') {
     return;
   }
   // Restrict parameters for a few hardcoded cases,
@@ -244,8 +491,8 @@
   // allocation in the generated fuzzing program.
   if (name == 'padLeft' || name == 'padRight') {
     proto = proto.replaceFirst('IS', 'is');
-  } else if (name == 'List.filled') {
-    proto = proto.replaceFirst('I', 'i');
+  } else if (name == 'List<int>.filled') {
+    proto = proto.replaceFirst(intEncoding, 'i');
   }
   // Add to table.
   getTable(ret).add(DartLib(name, proto));
@@ -257,6 +504,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 \"dartfuzz_type_table.dart\";
+
 /// Class that represents Dart library methods.
 ///
 /// The invididual lists are organized by return type.
@@ -279,7 +528,23 @@
 ///   L List<int>
 ///   X Set<int>
 ///   M Map<int, String>
-///
+///   A Int8List
+///   C Int16List
+///   E Int32List
+///   F Int32x4
+///   G Int32x4List
+///   H Int64List
+///   J Float32List
+///   K Float32x4
+///   N Float32x4List
+///   O Float64List
+///   P Float64x2
+///   Q Float64x2List
+///   R uint8ClampedList
+///   T uint8List
+///   U uint16List
+///   W uint32List
+///   Y uint64List
 /// NOTE: this code has been generated automatically.
 ///
 class DartLib {
@@ -289,6 +554,30 @@
 """);
 }
 
+void dumpStringToTypeMap() {
+  print('  static const stringToType = {');
+  for (var key in stringToType.keys) {
+    print('    \'${key}\': ${stringToType[key]},');
+  }
+  print('  };');
+}
+
+void dumpTypeToLibraryMethodMap() {
+  print('  static final typeToLibraryMethods = {');
+  for (var key in typeToLibraryMethods.keys) {
+    print('    ${key}: ${typeToLibraryMethods[key]},');
+  }
+  print('  };');
+}
+
+void dumpTypedDataFloatTypes() {
+  print('  static const typedDataFloatTypes = [');
+  for (var type in typedDataFloatTypes) {
+    print('    \'${type}\',');
+  }
+  print('  ];');
+}
+
 void dumpTable(String identifier, List<DartLib> table) {
   print('  static const $identifier = [');
   table.sort((a, b) => a.name.compareTo(b.name));
diff --git a/runtime/tools/dartfuzz/gen_type_table.dart b/runtime/tools/dartfuzz/gen_type_table.dart
index f2a08eb..945d7f0 100644
--- a/runtime/tools/dartfuzz/gen_type_table.dart
+++ b/runtime/tools/dartfuzz/gen_type_table.dart
@@ -655,6 +655,7 @@
 
 """);
 
+  print("  static const VOID = const " + "DartType._withName(\"void\");");
   Set<String> instTypes = {};
 
   // Generate one static DartType instance for all instantiable types.
diff --git a/runtime/vm/BUILD.gn b/runtime/vm/BUILD.gn
index cc4a18f..1b76c4e 100644
--- a/runtime/vm/BUILD.gn
+++ b/runtime/vm/BUILD.gn
@@ -134,7 +134,12 @@
     }
     single_root_scheme = "org-dartlang-sdk"
     single_root_base = rebase_path("../../")
-    libraries_specification_uri = "org-dartlang-sdk:///sdk/lib/libraries.json"
+    if (use_nnbd) {
+      libraries_specification_uri =
+          "org-dartlang-sdk:///sdk_nnbd/lib/libraries.json"
+    } else {
+      libraries_specification_uri = "org-dartlang-sdk:///sdk/lib/libraries.json"
+    }
     outputs = [
       "$root_out_dir/vm_platform" + output_postfix + ".dill",
       "$root_out_dir/vm_outline" + output_postfix + ".dill",
@@ -148,7 +153,9 @@
       "-Ddart.isVM=true",
     ]
     if (use_nnbd) {
-      args += [ "--enable-experiment=non-nullable" ]
+      # TODO(sigmund): reenable this flag once the CFE can build targets without
+      # issues.
+      # args += [ "--enable-experiment=non-nullable" ]
     }
     if (defined(invoker.exclude_source) && invoker.exclude_source) {
       args += [ "--exclude-source" ]
diff --git a/runtime/vm/bitmap_test.cc b/runtime/vm/bitmap_test.cc
index 8447aab..e8f6418 100644
--- a/runtime/vm/bitmap_test.cc
+++ b/runtime/vm/bitmap_test.cc
@@ -56,8 +56,8 @@
   EXPECT(it1.MoveNext());
 
   EXPECT_EQ(kTestPcOffset, it1.pc_offset());
-  EXPECT_EQ(kTestSpillSlotBitCount, it1.spill_slot_bit_count());
-  EXPECT_EQ(1024, it1.length());
+  EXPECT_EQ(kTestSpillSlotBitCount, it1.SpillSlotBitCount());
+  EXPECT_EQ(1024, it1.Length());
   value = true;
   for (int32_t i = 0; i < 1024; i++) {
     EXPECT_EQ(value, it1.IsObject(i));
@@ -88,8 +88,8 @@
   EXPECT(it2.MoveNext());
 
   EXPECT_EQ(kTestPcOffset, it2.pc_offset());
-  EXPECT_EQ(kTestSpillSlotBitCount, it2.spill_slot_bit_count());
-  EXPECT_EQ(2049, it2.length());
+  EXPECT_EQ(kTestSpillSlotBitCount, it2.SpillSlotBitCount());
+  EXPECT_EQ(2049, it2.Length());
   for (int32_t i = 0; i <= 256; i++) {
     EXPECT(!it2.IsObject(i));
   }
diff --git a/runtime/vm/bootstrap_natives.cc b/runtime/vm/bootstrap_natives.cc
index f8030dc..4b667d2 100644
--- a/runtime/vm/bootstrap_natives.cc
+++ b/runtime/vm/bootstrap_natives.cc
@@ -23,7 +23,7 @@
 // point.
 static struct NativeEntries {
   const char* name_;
-  Dart_NativeFunction function_;
+  BootstrapNativeFunction function_;
   int argument_count_;
 } BootStrapEntries[] = {BOOTSTRAP_NATIVE_LIST(REGISTER_NATIVE_ENTRY)
 #if !defined(DART_PRECOMPILED_RUNTIME)
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 7fceaf7..233c978 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -485,7 +485,8 @@
   static const uint8_t* Symbol(Dart_NativeFunction* nf);
 
 #define DECLARE_BOOTSTRAP_NATIVE(name, ignored)                                \
-  static void DN_##name(Dart_NativeArguments args);
+  static RawObject* DN_##name(Thread* thread, Zone* zone,                      \
+                              NativeArguments* arguments);
 
   BOOTSTRAP_NATIVE_LIST(DECLARE_BOOTSTRAP_NATIVE)
 #if !defined(DART_PRECOMPILED_RUNTIME)
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index b730cf6..f8ad310 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -383,14 +383,16 @@
           !pending_arguments.IsSubvectorInstantiated(first_type_param,
                                                      num_type_params)) {
         const TypeArguments& instantiated_arguments = TypeArguments::Handle(
-            zone, arguments.InstantiateFrom(Object::null_type_arguments(),
+            zone, arguments.InstantiateFrom(NNBDMode::kLegacy,
+                                            Object::null_type_arguments(),
                                             Object::null_type_arguments(),
                                             kNoneFree, NULL, Heap::kNew));
         const TypeArguments& instantiated_pending_arguments =
-            TypeArguments::Handle(zone, pending_arguments.InstantiateFrom(
-                                            Object::null_type_arguments(),
-                                            Object::null_type_arguments(),
-                                            kNoneFree, NULL, Heap::kNew));
+            TypeArguments::Handle(
+                zone, pending_arguments.InstantiateFrom(
+                          NNBDMode::kLegacy, Object::null_type_arguments(),
+                          Object::null_type_arguments(), kNoneFree, NULL,
+                          Heap::kNew));
         if (!instantiated_pending_arguments.IsSubvectorEquivalent(
                 instantiated_arguments, first_type_param, num_type_params)) {
           const String& type_name = String::Handle(zone, type.Name());
@@ -619,9 +621,13 @@
             arguments.SetTypeAt(i, super_type_arg);
             continue;
           }
+          // The nullability of the supertype should never be relevant.
+          // TODO(regis): Should we introduce a kIgnore mode in addition to
+          // the kLegacy mode of instantiation so that unnecessary cloning
+          // never occurs?
           super_type_arg = super_type_arg.InstantiateFrom(
-              arguments, Object::null_type_arguments(), kNoneFree,
-              instantiation_trail, Heap::kOld);
+              NNBDMode::kLegacy, arguments, Object::null_type_arguments(),
+              kNoneFree, instantiation_trail, Heap::kOld);
           if (super_type_arg.IsBeingFinalized()) {
             // The super_type_arg was instantiated from a type being finalized.
             // We need to finish finalizing its type arguments.
@@ -778,8 +784,8 @@
           const TypeArguments& instantiator_type_arguments =
               TypeArguments::Handle(zone, fun_type.arguments());
           signature = signature.InstantiateSignatureFrom(
-              instantiator_type_arguments, Object::null_type_arguments(),
-              kNoneFree, Heap::kOld);
+              NNBDMode::kLegacy, instantiator_type_arguments,
+              Object::null_type_arguments(), kNoneFree, Heap::kOld);
           // Note that if instantiator_type_arguments contains type parameters,
           // as in F<K>, the signature is still uninstantiated (the typedef type
           // parameters were substituted in the signature with typedef type
@@ -1631,6 +1637,7 @@
   for (intptr_t i = 0; i < types.Length(); i++) {
     type ^= types.At(i);
     bool present = types_table.Insert(type);
+    // Two recursive types with different topology (and hashes) may be equal.
     ASSERT(!present || type.IsRecursive());
   }
   object_store->set_canonical_types(types_table.Release());
@@ -1662,6 +1669,7 @@
   for (intptr_t i = 0; i < typeargs.Length(); i++) {
     typearg ^= typeargs.At(i);
     bool present = typeargs_table.Insert(typearg);
+    // Two recursive types with different topology (and hashes) may be equal.
     ASSERT(!present || typearg.IsRecursive());
   }
   object_store->set_canonical_type_arguments(typeargs_table.Release());
diff --git a/runtime/vm/class_table.cc b/runtime/vm/class_table.cc
index fa8108f..83d65f5 100644
--- a/runtime/vm/class_table.cc
+++ b/runtime/vm/class_table.cc
@@ -9,6 +9,7 @@
 #include "vm/growable_array.h"
 #include "vm/heap/heap.h"
 #include "vm/object.h"
+#include "vm/object_graph.h"
 #include "vm/raw_object.h"
 #include "vm/visitor.h"
 
@@ -47,10 +48,10 @@
     table_[kNeverCid] = vm_shared_class_table->SizeAt(kNeverCid);
   }
 #ifndef PRODUCT
-  class_heap_stats_table_ = static_cast<ClassHeapStats*>(
-      malloc(capacity_ * sizeof(ClassHeapStats)));  // NOLINT
+  trace_allocation_table_ =
+      static_cast<uint8_t*>(malloc(capacity_ * sizeof(uint8_t)));  // NOLINT
   for (intptr_t i = 0; i < capacity_; i++) {
-    class_heap_stats_table_[i].Initialize();
+    trace_allocation_table_[i] = 0;
   }
 #endif  // !PRODUCT
 }
@@ -60,14 +61,13 @@
     delete old_tables_;
     free(table_);
   }
-  NOT_IN_PRODUCT(free(class_heap_stats_table_));
+  NOT_IN_PRODUCT(free(trace_allocation_table_));
 }
 
 ClassTable::ClassTable(SharedClassTable* shared_class_table)
     : top_(kNumPredefinedCids),
       capacity_(0),
       table_(NULL),
-      old_tables_(new MallocGrowableArray<ClassAndSize*>()),
       old_class_tables_(new MallocGrowableArray<RawClass**>()),
       shared_class_table_(shared_class_table) {
   if (Dart::vm_isolate() == NULL) {
@@ -100,33 +100,33 @@
     : top_(original->top_),
       capacity_(original->top_),
       table_(original->table_),
-      old_tables_(nullptr),
       old_class_tables_(nullptr),
       shared_class_table_(shared_class_table) {}
 
 ClassTable::~ClassTable() {
-  if (old_tables_ != nullptr || old_class_tables_ != nullptr) {
+  if (old_class_tables_ != nullptr) {
     FreeOldTables();
-    delete old_tables_;
     delete old_class_tables_;
   }
   free(table_);
 }
 
-void ClassTable::AddOldTable(ClassAndSize* old_table) {
+void ClassTable::AddOldTable(RawClass** old_class_table) {
   ASSERT(Thread::Current()->IsMutatorThread());
-  old_tables_->Add(old_table);
+  old_class_tables_->Add(old_class_table);
 }
 
 void ClassTable::FreeOldTables() {
-  while (old_tables_->length() > 0) {
-    free(old_tables_->RemoveLast());
-  }
   while (old_class_tables_->length() > 0) {
     free(old_class_tables_->RemoveLast());
   }
 }
 
+void SharedClassTable::AddOldTable(intptr_t* old_table) {
+  ASSERT(Thread::Current()->IsMutatorThread());
+  old_tables_->Add(old_table);
+}
+
 void SharedClassTable::FreeOldTables() {
   while (old_tables_->length() > 0) {
     free(old_tables_->RemoveLast());
@@ -254,21 +254,18 @@
   memmove(new_table, table_, top_ * sizeof(intptr_t));
   memset(new_table + top_, 0, (new_capacity - top_) * sizeof(intptr_t));
 #ifndef PRODUCT
-  auto new_stats_table = reinterpret_cast<ClassHeapStats*>(
-      malloc(new_capacity * sizeof(ClassHeapStats)));
-  for (intptr_t i = 0; i < capacity_; i++) {
-    new_stats_table[i] = class_heap_stats_table_[i];
-  }
-  free(class_heap_stats_table_);
+  auto new_stats_table =
+      static_cast<uint8_t*>(realloc(trace_allocation_table_,
+                                    new_capacity * sizeof(uint8_t)));  // NOLINT
 #endif
   for (intptr_t i = capacity_; i < new_capacity; i++) {
     new_table[i] = 0;
-    NOT_IN_PRODUCT(new_stats_table[i].Initialize());
+    NOT_IN_PRODUCT(new_stats_table[i] = 0);
   }
   capacity_ = new_capacity;
   old_tables_->Add(table_);
   table_ = new_table;  // TODO(koda): This should use atomics.
-  NOT_IN_PRODUCT(class_heap_stats_table_ = new_stats_table);
+  NOT_IN_PRODUCT(trace_allocation_table_ = new_stats_table);
 }
 
 void ClassTable::Unregister(intptr_t index) {
@@ -364,10 +361,6 @@
   table_[index] = raw_cls;
 }
 
-ClassAndSize::ClassAndSize(RawClass* clazz) : class_(clazz) {
-  size_ = clazz == NULL ? 0 : Class::instance_size(clazz);
-}
-
 #ifndef PRODUCT
 void ClassTable::PrintToJSONObject(JSONObject* object) {
   if (!FLAG_support_service) {
@@ -386,244 +379,14 @@
   }
 }
 
-void ClassHeapStats::Initialize() {
-  pre_gc.Reset();
-  post_gc.Reset();
-  recent.Reset();
-  accumulated.Reset();
-  last_reset.Reset();
-  promoted_count = 0;
-  promoted_size = 0;
-  state_ = 0;
-  USE(align_);
-}
-
-void ClassHeapStats::ResetAtNewGC() {
-  Verify();
-  pre_gc.new_count = post_gc.new_count + recent.new_count;
-  pre_gc.new_size = post_gc.new_size + recent.new_size;
-  pre_gc.new_external_size =
-      post_gc.new_external_size + recent.new_external_size;
-  pre_gc.old_external_size =
-      post_gc.old_external_size + recent.old_external_size;
-  // Accumulate allocations.
-  accumulated.new_count += recent.new_count - last_reset.new_count;
-  accumulated.new_size += recent.new_size - last_reset.new_size;
-  accumulated.new_external_size +=
-      recent.new_external_size - last_reset.new_external_size;
-  accumulated.old_external_size +=
-      recent.old_external_size - last_reset.old_external_size;
-  last_reset.ResetNew();
-  post_gc.ResetNew();
-  recent.ResetNew();
-  old_pre_new_gc_count_ = recent.old_count;
-  old_pre_new_gc_size_ = recent.old_size;
-}
-
-void ClassHeapStats::ResetAtOldGC() {
-  Verify();
-  pre_gc.old_count = post_gc.old_count + recent.old_count;
-  pre_gc.old_size = post_gc.old_size + recent.old_size;
-  pre_gc.old_external_size =
-      post_gc.old_external_size + recent.old_external_size;
-  pre_gc.new_external_size =
-      post_gc.new_external_size + recent.new_external_size;
-  // Accumulate allocations.
-  accumulated.old_count += recent.old_count - last_reset.old_count;
-  accumulated.old_size += recent.old_size - last_reset.old_size;
-  accumulated.old_external_size +=
-      recent.old_external_size - last_reset.old_external_size;
-  accumulated.new_external_size +=
-      recent.new_external_size - last_reset.new_external_size;
-  last_reset.ResetOld();
-  post_gc.ResetOld();
-  recent.ResetOld();
-}
-
-void ClassHeapStats::Verify() {
-  pre_gc.Verify();
-  post_gc.Verify();
-  recent.Verify();
-  accumulated.Verify();
-  last_reset.Verify();
-}
-
-void ClassHeapStats::UpdateSize(intptr_t instance_size) {
-  pre_gc.UpdateSize(instance_size);
-  post_gc.UpdateSize(instance_size);
-  recent.UpdateSize(instance_size);
-  accumulated.UpdateSize(instance_size);
-  last_reset.UpdateSize(instance_size);
-  promoted_size = promoted_count * instance_size;
-  old_pre_new_gc_size_ = old_pre_new_gc_count_ * instance_size;
-}
-
-void ClassHeapStats::ResetAccumulator() {
-  // Remember how much was allocated so we can subtract this from the result
-  // when printing.
-  last_reset.new_count = recent.new_count;
-  last_reset.new_size = recent.new_size;
-  last_reset.new_external_size = recent.new_external_size;
-  last_reset.old_count = recent.old_count;
-  last_reset.old_size = recent.old_size;
-  last_reset.old_external_size = recent.old_external_size;
-  accumulated.Reset();
-}
-
-void ClassHeapStats::UpdatePromotedAfterNewGC() {
-  promoted_count = recent.old_count - old_pre_new_gc_count_;
-  promoted_size = recent.old_size - old_pre_new_gc_size_;
-}
-
-void ClassHeapStats::PrintToJSONObject(const Class& cls,
-                                       JSONObject* obj,
-                                       bool internal) const {
-  if (!FLAG_support_service) {
-    return;
-  }
-  obj->AddProperty("type", "ClassHeapStats");
-  obj->AddProperty("class", cls);
-  int64_t accumulated_new =
-      accumulated.new_count + recent.new_count - last_reset.new_count;
-  int64_t accumulated_old =
-      accumulated.old_count + recent.old_count - last_reset.old_count;
-  int64_t accumulated_new_size =
-      accumulated.new_size + accumulated.new_external_size + recent.new_size +
-      recent.new_external_size - last_reset.new_size -
-      last_reset.new_external_size;
-  int64_t accumulated_old_size =
-      accumulated.old_size + accumulated.old_external_size + recent.old_size +
-      recent.old_external_size - last_reset.old_size -
-      last_reset.old_external_size;
-  int64_t instances_new = post_gc.new_count + recent.new_count;
-  int64_t instances_old = post_gc.old_count + recent.old_count;
-  int64_t live_after_gc_size_new = post_gc.new_size + post_gc.new_external_size;
-  int64_t live_after_gc_size_old = post_gc.old_size + post_gc.old_external_size;
-  int64_t allocated_since_gc_size_new =
-      recent.new_size + recent.new_external_size;
-  int64_t allocated_since_gc_size_old =
-      recent.old_size + recent.old_external_size;
-  int64_t bytes_current = live_after_gc_size_new + live_after_gc_size_old +
-                          allocated_since_gc_size_new +
-                          allocated_since_gc_size_old;
-  if (internal) {
-    {
-      JSONArray new_stats(obj, "_new");
-      new_stats.AddValue(pre_gc.new_count);
-      new_stats.AddValue(pre_gc.new_size + pre_gc.new_external_size);
-      new_stats.AddValue(post_gc.new_count);
-      new_stats.AddValue64(live_after_gc_size_new);
-      new_stats.AddValue(recent.new_count);
-      new_stats.AddValue64(allocated_since_gc_size_new);
-      new_stats.AddValue64(accumulated_new);
-      new_stats.AddValue64(accumulated_new_size);
-    }
-    {
-      JSONArray old_stats(obj, "_old");
-      old_stats.AddValue(pre_gc.old_count);
-      old_stats.AddValue(pre_gc.old_size + pre_gc.old_external_size);
-      old_stats.AddValue(post_gc.old_count);
-      old_stats.AddValue64(live_after_gc_size_old);
-      old_stats.AddValue(recent.old_count);
-      old_stats.AddValue64(allocated_since_gc_size_old);
-      old_stats.AddValue64(accumulated_old);
-      old_stats.AddValue64(accumulated_old_size);
-    }
-    obj->AddProperty("_promotedInstances", promoted_count);
-    obj->AddProperty("_promotedBytes", promoted_size);
-  }
-  obj->AddProperty64("instancesAccumulated", accumulated_new + accumulated_old);
-  obj->AddProperty64("accumulatedSize",
-                     accumulated_new_size + accumulated_old_size);
-  obj->AddProperty64("instancesCurrent", instances_new + instances_old);
-  obj->AddProperty64("bytesCurrent", bytes_current);
-}
-
-void SharedClassTable::UpdateAllocatedOldGC(intptr_t cid, intptr_t size) {
-  ClassHeapStats* stats = PreliminaryStatsAt(cid);
-  ASSERT(stats != NULL);
-  ASSERT(size != 0);
-  stats->recent.AddOldGC(size);
-}
-
-void SharedClassTable::UpdateAllocatedExternalNew(intptr_t cid, intptr_t size) {
-  ClassHeapStats* stats = PreliminaryStatsAt(cid);
-  ASSERT(stats != NULL);
-  stats->recent.AddNewExternal(size);
-}
-
-void SharedClassTable::UpdateAllocatedExternalOld(intptr_t cid, intptr_t size) {
-  ClassHeapStats* stats = PreliminaryStatsAt(cid);
-  ASSERT(stats != NULL);
-  stats->recent.AddOldExternal(size);
-}
-
 bool SharedClassTable::ShouldUpdateSizeForClassId(intptr_t cid) {
   return !RawObject::IsVariableSizeClassId(cid);
 }
 
-ClassHeapStats* ClassTable::StatsWithUpdatedSize(intptr_t cid) {
-  if (!HasValidClassAt(cid) || cid == kFreeListElement ||
-      cid == kForwardingCorpse || cid == kSmiCid) {
-    return NULL;
-  }
-  Class& cls = Class::Handle(At(cid));
-  if (!(cls.is_finalized() || cls.is_prefinalized())) {
-    // Not finalized.
-    return NULL;
-  }
-  return shared_class_table_->StatsWithUpdatedSize(cid, cls.instance_size());
-}
-
-ClassHeapStats* SharedClassTable::StatsWithUpdatedSize(intptr_t cid,
-                                                       intptr_t size) {
-  ClassHeapStats* stats = PreliminaryStatsAt(cid);
-  if (ShouldUpdateSizeForClassId(cid)) {
-    stats->UpdateSize(size);
-  }
-  stats->Verify();
-  return stats;
-}
-
-void SharedClassTable::ResetCountersOld() {
-  for (intptr_t i = 0; i < top_; i++) {
-    class_heap_stats_table_[i].ResetAtOldGC();
-  }
-}
-
-void SharedClassTable::ResetCountersNew() {
-  for (intptr_t i = 0; i < top_; i++) {
-    class_heap_stats_table_[i].ResetAtNewGC();
-  }
-}
-
-void SharedClassTable::UpdatePromoted() {
-  for (intptr_t i = 0; i < top_; i++) {
-    class_heap_stats_table_[i].UpdatePromotedAfterNewGC();
-  }
-}
-
 intptr_t SharedClassTable::ClassOffsetFor(intptr_t cid) {
-  return cid * sizeof(ClassHeapStats);  // NOLINT
+  return cid * sizeof(uint8_t);  // NOLINT
 }
 
-intptr_t SharedClassTable::NewSpaceCounterOffsetFor(intptr_t cid) {
-  const intptr_t class_offset = ClassOffsetFor(cid);
-  const intptr_t count_field_offset =
-      ClassHeapStats::allocated_since_gc_new_space_offset();
-  return class_offset + count_field_offset;
-}
-
-intptr_t SharedClassTable::StateOffsetFor(intptr_t cid) {
-  return ClassOffsetFor(cid) + ClassHeapStats::state_offset();
-}
-
-intptr_t SharedClassTable::NewSpaceSizeOffsetFor(intptr_t cid) {
-  const uword class_offset = ClassOffsetFor(cid);
-  const uword size_field_offset =
-      ClassHeapStats::allocated_size_since_gc_new_space_offset();
-  return class_offset + size_field_offset;
-}
 
 void ClassTable::AllocationProfilePrintJSON(JSONStream* stream, bool internal) {
   if (!FLAG_support_service) {
@@ -656,69 +419,50 @@
     { heap->PrintMemoryUsageJSON(&memory); }
   }
 
+  Thread* thread = Thread::Current();
+  CountObjectsVisitor visitor(thread, NumCids());
+  {
+    HeapIterationScope iter(thread);
+    iter.IterateObjects(&visitor);
+    isolate->VisitWeakPersistentHandles(&visitor);
+  }
+
   {
     JSONArray arr(&obj, "members");
     Class& cls = Class::Handle();
-    for (intptr_t i = 1; i < top_; i++) {
-      const ClassHeapStats* stats = StatsWithUpdatedSize(i);
-      if (stats != NULL) {
-        JSONObject obj(&arr);
-        cls = At(i);
-        stats->PrintToJSONObject(cls, &obj, internal);
+    for (intptr_t i = 3; i < top_; i++) {
+      if (!HasValidClassAt(i)) continue;
+
+      cls = At(i);
+      if (cls.IsNull()) continue;
+
+      JSONObject obj(&arr);
+      obj.AddProperty("type", "ClassHeapStats");
+      obj.AddProperty("class", cls);
+      intptr_t count = visitor.new_count_[i] + visitor.old_count_[i];
+      intptr_t size = visitor.new_size_[i] + visitor.old_size_[i];
+      obj.AddProperty64("instancesAccumulated", count);
+      obj.AddProperty64("accumulatedSize", size);
+      obj.AddProperty64("instancesCurrent", count);
+      obj.AddProperty64("bytesCurrent", size);
+
+      if (internal) {
+        {
+          JSONArray new_stats(&obj, "_new");
+          new_stats.AddValue(visitor.new_count_[i]);
+          new_stats.AddValue(visitor.new_size_[i]);
+          new_stats.AddValue(visitor.new_external_size_[i]);
+        }
+        {
+          JSONArray old_stats(&obj, "_old");
+          old_stats.AddValue(visitor.old_count_[i]);
+          old_stats.AddValue(visitor.old_size_[i]);
+          old_stats.AddValue(visitor.old_external_size_[i]);
+        }
       }
     }
   }
 }
-
-void SharedClassTable::ResetAllocationAccumulators() {
-  for (intptr_t i = 1; i < top_; i++) {
-    if (HasValidClassAt(i)) {
-      const intptr_t size = table_[i];
-      ClassHeapStats* stats = StatsWithUpdatedSize(i, size);
-      if (stats != NULL) {
-        stats->ResetAccumulator();
-      }
-    }
-  }
-}
-
-void SharedClassTable::UpdateLiveOld(intptr_t cid,
-                                     intptr_t size,
-                                     intptr_t count) {
-  ClassHeapStats* stats = PreliminaryStatsAt(cid);
-  ASSERT(stats != NULL);
-  ASSERT(size >= 0);
-  ASSERT(count >= 0);
-  stats->post_gc.AddOld(size, count);
-}
-
-void SharedClassTable::UpdateLiveNew(intptr_t cid, intptr_t size) {
-  ClassHeapStats* stats = PreliminaryStatsAt(cid);
-  ASSERT(stats != NULL);
-  ASSERT(size >= 0);
-  stats->post_gc.AddNew(size);
-}
-
-void SharedClassTable::UpdateLiveNewGC(intptr_t cid, intptr_t size) {
-  ClassHeapStats* stats = PreliminaryStatsAt(cid);
-  ASSERT(stats != NULL);
-  ASSERT(size >= 0);
-  stats->post_gc.AddNewGC(size);
-}
-
-void SharedClassTable::UpdateLiveOldExternal(intptr_t cid, intptr_t size) {
-  ClassHeapStats* stats = PreliminaryStatsAt(cid);
-  ASSERT(stats != NULL);
-  ASSERT(size >= 0);
-  stats->post_gc.AddOldExternal(size);
-}
-
-void SharedClassTable::UpdateLiveNewExternal(intptr_t cid, intptr_t size) {
-  ClassHeapStats* stats = PreliminaryStatsAt(cid);
-  ASSERT(stats != NULL);
-  ASSERT(size >= 0);
-  stats->post_gc.AddNewExternal(size);
-}
 #endif  // !PRODUCT
 
 }  // namespace dart
diff --git a/runtime/vm/class_table.h b/runtime/vm/class_table.h
index 5edf9c4..fb13d2e 100644
--- a/runtime/vm/class_table.h
+++ b/runtime/vm/class_table.h
@@ -15,10 +15,11 @@
 namespace dart {
 
 class Class;
-class ClassStats;
 class ClassTable;
 class Isolate;
 class IsolateGroup;
+class IsolateGroupReloadContext;
+class IsolateReloadContext;
 class JSONArray;
 class JSONObject;
 class JSONStream;
@@ -27,164 +28,6 @@
 class ObjectPointerVisitor;
 class RawClass;
 
-class ClassAndSize {
- public:
-  ClassAndSize() : class_(NULL), size_(0) {}
-  explicit ClassAndSize(RawClass* clazz);
-  ClassAndSize(RawClass* clazz, intptr_t size) : class_(clazz), size_(size) {}
-  RawClass* get_raw_class() const { return class_; }
-  intptr_t size() const { return size_; }
-
- private:
-  RawClass* class_;
-  intptr_t size_;
-
-  friend class ClassTable;
-  friend class IsolateReloadContext;  // For VisitObjectPointers.
-};
-
-#ifndef PRODUCT
-template <typename T>
-class AllocStats {
- public:
-  RelaxedAtomic<T> new_count;
-  RelaxedAtomic<T> new_size;
-  RelaxedAtomic<T> new_external_size;
-  RelaxedAtomic<T> old_count;
-  RelaxedAtomic<T> old_size;
-  RelaxedAtomic<T> old_external_size;
-
-  void ResetNew() {
-    new_count = 0;
-    new_size = 0;
-    new_external_size = 0;
-    old_external_size = 0;
-  }
-
-  void AddNew(T size) {
-    new_count.fetch_add(1);
-    new_size.fetch_add(size);
-  }
-
-  void AddNewGC(T size) {
-    new_count.fetch_add(1);
-    new_size.fetch_add(size);
-  }
-
-  void AddNewExternal(T size) { new_external_size.fetch_add(size); }
-
-  void ResetOld() {
-    old_count = 0;
-    old_size = 0;
-    old_external_size = 0;
-    new_external_size = 0;
-  }
-
-  void AddOld(T size, T count = 1) {
-    old_count.fetch_add(count);
-    old_size.fetch_add(size);
-  }
-
-  void AddOldGC(T size, T count = 1) {
-    old_count.fetch_add(count);
-    old_size.fetch_add(size);
-  }
-
-  void AddOldExternal(T size) { old_external_size.fetch_add(size); }
-
-  void Reset() {
-    ResetNew();
-    ResetOld();
-  }
-
-  // For classes with fixed instance size we do not emit code to update
-  // the size statistics. Update them by calling this method.
-  void UpdateSize(intptr_t instance_size) {
-    ASSERT(instance_size > 0);
-    old_size = old_count * instance_size;
-    new_size = new_count * instance_size;
-  }
-
-  void Verify() {
-    ASSERT(new_count >= 0);
-    ASSERT(new_size >= 0);
-    ASSERT(new_external_size >= 0);
-    ASSERT(old_count >= 0);
-    ASSERT(old_size >= 0);
-    ASSERT(old_external_size >= 0);
-  }
-};
-
-class ClassHeapStats {
- public:
-  // Snapshot before GC.
-  AllocStats<intptr_t> pre_gc;
-  // Live after GC.
-  AllocStats<intptr_t> post_gc;
-  // Allocations since the last GC.
-  AllocStats<intptr_t> recent;
-  // Accumulated (across GC) allocations .
-  AllocStats<int64_t> accumulated;
-  // Snapshot of recent at the time of the last reset.
-  AllocStats<intptr_t> last_reset;
-  // Promoted from new to old by last new GC.
-  intptr_t promoted_count;
-  intptr_t promoted_size;
-
-  static intptr_t allocated_since_gc_new_space_offset() {
-    return OFFSET_OF(ClassHeapStats, recent) +
-           OFFSET_OF(AllocStats<intptr_t>, new_count);
-  }
-  static intptr_t allocated_since_gc_old_space_offset() {
-    return OFFSET_OF(ClassHeapStats, recent) +
-           OFFSET_OF(AllocStats<intptr_t>, old_count);
-  }
-  static intptr_t allocated_size_since_gc_new_space_offset() {
-    return OFFSET_OF(ClassHeapStats, recent) +
-           OFFSET_OF(AllocStats<intptr_t>, new_size);
-  }
-  static intptr_t allocated_size_since_gc_old_space_offset() {
-    return OFFSET_OF(ClassHeapStats, recent) +
-           OFFSET_OF(AllocStats<intptr_t>, old_size);
-  }
-  static intptr_t state_offset() { return OFFSET_OF(ClassHeapStats, state_); }
-  static intptr_t TraceAllocationMask() { return (1 << kTraceAllocationBit); }
-
-  void Initialize();
-  void ResetAtNewGC();
-  void ResetAtOldGC();
-  void ResetAccumulator();
-  void UpdatePromotedAfterNewGC();
-  void UpdateSize(intptr_t instance_size);
-#ifndef PRODUCT
-  void PrintToJSONObject(const Class& cls,
-                         JSONObject* obj,
-                         bool internal) const;
-#endif
-  void Verify();
-
-  bool trace_allocation() const { return TraceAllocationBit::decode(state_); }
-
-  void set_trace_allocation(bool trace_allocation) {
-    state_ = TraceAllocationBit::update(trace_allocation, state_);
-  }
-
- private:
-  enum StateBits {
-    kTraceAllocationBit = 0,
-  };
-
-  class TraceAllocationBit
-      : public BitField<intptr_t, bool, kTraceAllocationBit, 1> {};
-
-  // Recent old at start of last new GC (used to compute promoted_*).
-  intptr_t old_pre_new_gc_count_;
-  intptr_t old_pre_new_gc_size_;
-  intptr_t state_;
-  intptr_t align_;  // Make SIMARM and ARM agree on the size of ClassHeapStats.
-};
-#endif  // !PRODUCT
-
 // Registry of all known classes and their sizes.
 //
 // The GC will only need the information in this shared class table to scan
@@ -225,44 +68,60 @@
     top_ = num_cids;
   }
 
-  // Called whenever a old GC occurs.
-  void ResetCountersOld();
-  // Called whenever a new GC occurs.
-  void ResetCountersNew();
-  // Called immediately after a new GC.
-  void UpdatePromoted();
-
 #if !defined(PRODUCT)
-  // Called whenever a class is allocated in the runtime.
-  void UpdateAllocatedNew(intptr_t cid, intptr_t size) {
-    ClassHeapStats* stats = PreliminaryStatsAt(cid);
-    ASSERT(stats != NULL);
-    ASSERT(size != 0);
-    stats->recent.AddNew(size);
-  }
-  void UpdateAllocatedOld(intptr_t cid, intptr_t size) {
-    ClassHeapStats* stats = PreliminaryStatsAt(cid);
-    ASSERT(stats != NULL);
-    ASSERT(size != 0);
-    stats->recent.AddOld(size);
-  }
-  void UpdateAllocatedOldGC(intptr_t cid, intptr_t size);
-  void UpdateAllocatedExternalNew(intptr_t cid, intptr_t size);
-  void UpdateAllocatedExternalOld(intptr_t cid, intptr_t size);
-
-  void ResetAllocationAccumulators();
-
   void SetTraceAllocationFor(intptr_t cid, bool trace) {
-    ClassHeapStats* stats = PreliminaryStatsAt(cid);
-    stats->set_trace_allocation(trace);
+    ASSERT(cid > 0);
+    ASSERT(cid < top_);
+    trace_allocation_table_[cid] = trace ? 1 : 0;
   }
   bool TraceAllocationFor(intptr_t cid) {
-    ClassHeapStats* stats = PreliminaryStatsAt(cid);
-    return stats->trace_allocation();
+    ASSERT(cid > 0);
+    ASSERT(cid < top_);
+    return trace_allocation_table_[cid] != 0;
+  }
+#endif  // !defined(PRODUCT)
+
+  void CopyBeforeHotReload(intptr_t** copy, intptr_t* copy_num_cids) {
+    // The [IsolateGroupReloadContext] will need to maintain a copy of the old
+    // class table until instances have been morphed.
+    const intptr_t num_cids = NumCids();
+    const intptr_t bytes = sizeof(intptr_t) * num_cids;
+    auto size_table = static_cast<intptr_t*>(malloc(bytes));
+    memmove(size_table, table_, sizeof(intptr_t) * num_cids);
+    *copy_num_cids = num_cids;
+    *copy = size_table;
   }
 
-  ClassHeapStats* StatsWithUpdatedSize(intptr_t cid, intptr_t size);
-#endif  // !defined(PRODUCT)
+  void ResetBeforeHotReload() {
+    // The [IsolateReloadContext] is now source-of-truth for GC.
+    memset(table_, 0, sizeof(intptr_t) * top_);
+  }
+
+  void ResetAfterHotReload(intptr_t* old_table,
+                           intptr_t num_old_cids,
+                           bool is_rollback) {
+    // The [IsolateReloadContext] is no longer source-of-truth for GC after we
+    // return, so we restore size information for all classes.
+    if (is_rollback) {
+      SetNumCids(num_old_cids);
+      memmove(table_, old_table, sizeof(intptr_t) * num_old_cids);
+    }
+
+    // Can't free this table immediately as another thread (e.g., concurrent
+    // marker or sweeper) may be between loading the table pointer and loading
+    // the table element. The table will be freed at the next major GC or
+    // isolate shutdown.
+    AddOldTable(old_table);
+  }
+
+  // Deallocates table copies. Do not call during concurrent access to table.
+  void FreeOldTables();
+
+#if !defined(DART_PRECOMPILED_RUNTIME)
+  bool IsReloading() const { return reload_context_ != nullptr; }
+
+  IsolateGroupReloadContext* reload_context() { return reload_context_; }
+#endif  // !defined(DART_PRECOMPILED_RUNTIME)
 
   // Returns the newly allocated cid.
   //
@@ -273,27 +132,16 @@
 
   void Remap(intptr_t* old_to_new_cids);
 
-  void FreeOldTables();
-
   // Used by the generated code.
 #ifndef PRODUCT
   static intptr_t class_heap_stats_table_offset() {
-    return OFFSET_OF(SharedClassTable, class_heap_stats_table_);
+    return OFFSET_OF(SharedClassTable, trace_allocation_table_);
   }
 #endif
 
   // Used by the generated code.
   static intptr_t ClassOffsetFor(intptr_t cid);
 
-  // Used by the generated code.
-  static intptr_t NewSpaceCounterOffsetFor(intptr_t cid);
-
-  // Used by the generated code.
-  static intptr_t StateOffsetFor(intptr_t cid);
-
-  // Used by the generated code.
-  static intptr_t NewSpaceSizeOffsetFor(intptr_t cid);
-
   static const int kInitialCapacity = 512;
   static const int kCapacityIncrement = 256;
 
@@ -303,27 +151,15 @@
   friend class MarkingWeakVisitor;
   friend class Scavenger;
   friend class ScavengerWeakVisitor;
-  friend class ClassHeapStatsTestHelper;
-  friend class HeapTestsHelper;
 
   static bool ShouldUpdateSizeForClassId(intptr_t cid);
 
 #ifndef PRODUCT
-  // May not have updated size for variable size classes.
-  ClassHeapStats* PreliminaryStatsAt(intptr_t cid) {
-    ASSERT(cid > 0);
-    ASSERT(cid < top_);
-    return &class_heap_stats_table_[cid];
-  }
-  void UpdateLiveOld(intptr_t cid, intptr_t size, intptr_t count = 1);
-  void UpdateLiveNew(intptr_t cid, intptr_t size);
-  void UpdateLiveNewGC(intptr_t cid, intptr_t size);
-  void UpdateLiveOldExternal(intptr_t cid, intptr_t size);
-  void UpdateLiveNewExternal(intptr_t cid, intptr_t size);
-
-  ClassHeapStats* class_heap_stats_table_ = nullptr;
+  uint8_t* trace_allocation_table_ = nullptr;
 #endif  // !PRODUCT
 
+  void AddOldTable(intptr_t* old_table);
+
   void Grow(intptr_t new_capacity);
 
   intptr_t top_;
@@ -333,6 +169,8 @@
   intptr_t* table_;  // Maps the cid to the instance size.
   MallocGrowableArray<intptr_t*>* old_tables_;
 
+  IsolateGroupReloadContext* reload_context_ = nullptr;
+
   DISALLOW_COPY_AND_ASSIGN(SharedClassTable);
 };
 
@@ -347,44 +185,33 @@
 
   SharedClassTable* shared_class_table() const { return shared_class_table_; }
 
-  void CopyBeforeHotReload(ClassAndSize** copy, intptr_t* copy_num_cids) {
+  void CopyBeforeHotReload(RawClass*** copy, intptr_t* copy_num_cids) {
     // The [IsolateReloadContext] will need to maintain a copy of the old class
     // table until instances have been morphed.
     const intptr_t num_cids = NumCids();
-    const intptr_t bytes = sizeof(ClassAndSize) * num_cids;
-    auto class_and_size = static_cast<ClassAndSize*>(malloc(bytes));
-    for (intptr_t i = 0; i < num_cids; ++i) {
-      class_and_size[i] =
-          ClassAndSize(table_[i], shared_class_table_->table_[i]);
-    }
+    const intptr_t bytes = sizeof(RawClass*) * num_cids;
+    auto class_table = static_cast<RawClass**>(malloc(bytes));
+    memmove(class_table, table_, sizeof(RawClass*) * num_cids);
     *copy_num_cids = num_cids;
-    *copy = class_and_size;
+    *copy = class_table;
   }
 
   void ResetBeforeHotReload() {
-    // The [IsolateReloadContext] is now source-of-truth for GC.
-    //
-    // Though we cannot clear out the class pointers, because a hot-reload
+    // We cannot clear out the class pointers, because a hot-reload
     // contains only a diff: If e.g. a class included in the hot-reload has a
     // super class not included in the diff, it will look up in this class table
     // to find the super class (e.g. `cls.SuperClass` will cause us to come
     // here).
-    for (intptr_t i = 0; i < top_; ++i) {
-      shared_class_table_->table_[i] = 0;
-    }
   }
 
-  void ResetAfterHotReload(ClassAndSize* old_table,
+  void ResetAfterHotReload(RawClass** old_table,
                            intptr_t num_old_cids,
                            bool is_rollback) {
     // The [IsolateReloadContext] is no longer source-of-truth for GC after we
     // return, so we restore size information for all classes.
     if (is_rollback) {
       SetNumCids(num_old_cids);
-      for (intptr_t i = 0; i < num_old_cids; ++i) {
-        shared_class_table_->table_[i] = old_table[i].size_;
-        table_[i] = old_table[i].class_;
-      }
+      memmove(table_, old_table, sizeof(RawClass*) * num_old_cids);
     } else {
       CopySizesFromClassObjects();
     }
@@ -458,20 +285,17 @@
   struct ArrayLayout {
     static intptr_t elements_start_offset() { return 0; }
 
-    static constexpr intptr_t kElementSize = sizeof(ClassHeapStats);
+    static constexpr intptr_t kElementSize = sizeof(uint8_t);
   };
 #endif
 
 #ifndef PRODUCT
 
-  ClassHeapStats* StatsWithUpdatedSize(intptr_t cid);
-
   void AllocationProfilePrintJSON(JSONStream* stream, bool internal);
 
   void PrintToJSONObject(JSONObject* object);
 #endif  // !PRODUCT
 
-  void AddOldTable(ClassAndSize* old_table);
   // Deallocates table copies. Do not call during concurrent access to table.
   void FreeOldTables();
 
@@ -480,19 +304,19 @@
   friend class MarkingWeakVisitor;
   friend class Scavenger;
   friend class ScavengerWeakVisitor;
-  friend class ClassHeapStatsTestHelper;
-  friend class HeapTestsHelper;
   static const int kInitialCapacity = SharedClassTable::kInitialCapacity;
   static const int kCapacityIncrement = SharedClassTable::kCapacityIncrement;
 
+  void AddOldTable(RawClass** old_table);
+
   void Grow(intptr_t index);
 
   intptr_t top_;
   intptr_t capacity_;
 
-  // Copy-on-write is used for table_, with old copies stored in old_tables_.
+  // Copy-on-write is used for table_, with old copies stored in
+  // old_class_tables_.
   RawClass** table_;
-  MallocGrowableArray<ClassAndSize*>* old_tables_;
   MallocGrowableArray<RawClass**>* old_class_tables_;
   SharedClassTable* shared_class_table_;
 
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index 6796fb5..1027fe6 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -9,9 +9,12 @@
 #include "vm/bss_relocs.h"
 #include "vm/class_id.h"
 #include "vm/code_observers.h"
+#include "vm/compiler/assembler/disassembler.h"
 #include "vm/compiler/backend/code_statistics.h"
+#include "vm/compiler/backend/il_printer.h"
 #include "vm/compiler/relocation.h"
 #include "vm/dart.h"
+#include "vm/flag_list.h"
 #include "vm/heap/heap.h"
 #include "vm/image_snapshot.h"
 #include "vm/native_entry.h"
@@ -1373,11 +1376,7 @@
     s->Push(code->ptr()->owner_);
     s->Push(code->ptr()->exception_handlers_);
     s->Push(code->ptr()->pc_descriptors_);
-#if defined(DART_PRECOMPILED_RUNTIME) || defined(DART_PRECOMPILER)
-    s->Push(code->ptr()->catch_entry_.catch_entry_moves_maps_);
-#else
-    s->Push(code->ptr()->catch_entry_.variables_);
-#endif
+    s->Push(code->ptr()->catch_entry_);
     s->Push(code->ptr()->compressed_stackmaps_);
     if (!FLAG_dwarf_stack_traces) {
       s->Push(code->ptr()->inlined_id_to_function_);
@@ -1387,7 +1386,12 @@
       s->Push(code->ptr()->deopt_info_array_);
       s->Push(code->ptr()->static_calls_target_table_);
     }
-    NOT_IN_PRODUCT(s->Push(code->ptr()->return_address_metadata_));
+#if !defined(PRODUCT)
+    s->Push(code->ptr()->return_address_metadata_);
+    if (FLAG_code_comments) {
+      s->Push(code->ptr()->comments_);
+    }
+#endif
   }
 
   void WriteAlloc(Serializer* s) {
@@ -1431,11 +1435,7 @@
       WriteField(code, owner_);
       WriteField(code, exception_handlers_);
       WriteField(code, pc_descriptors_);
-#if defined(DART_PRECOMPILED_RUNTIME) || defined(DART_PRECOMPILER)
-      WriteField(code, catch_entry_.catch_entry_moves_maps_);
-#else
-      WriteField(code, catch_entry_.variables_);
-#endif
+      WriteField(code, catch_entry_);
       WriteField(code, compressed_stackmaps_);
       if (FLAG_dwarf_stack_traces) {
         WriteFieldValue(inlined_id_to_function_, Array::null());
@@ -1448,8 +1448,12 @@
         WriteField(code, deopt_info_array_);
         WriteField(code, static_calls_target_table_);
       }
-      NOT_IN_PRODUCT(WriteField(code, return_address_metadata_));
-
+#if !defined(PRODUCT)
+      WriteField(code, return_address_metadata_);
+      if (FLAG_code_comments) {
+        WriteField(code, comments_);
+      }
+#endif
       s->Write<int32_t>(code->ptr()->state_bits_);
     }
   }
@@ -1510,13 +1514,7 @@
 
       RawInstructions* instr = d->ReadInstructions();
 
-      code->ptr()->entry_point_ = Instructions::EntryPoint(instr);
-      code->ptr()->monomorphic_entry_point_ =
-          Instructions::MonomorphicEntryPoint(instr);
-      code->ptr()->unchecked_entry_point_ =
-          Instructions::UncheckedEntryPoint(instr);
-      code->ptr()->monomorphic_unchecked_entry_point_ =
-          Instructions::MonomorphicUncheckedEntryPoint(instr);
+      Code::InitializeCachedEntryPointsFrom(code, instr);
       NOT_IN_PRECOMPILED(code->ptr()->active_instructions_ = instr);
       code->ptr()->instructions_ = instr;
 
@@ -1524,11 +1522,7 @@
       if (d->kind() == Snapshot::kFullJIT) {
         RawInstructions* instr = d->ReadInstructions();
         code->ptr()->active_instructions_ = instr;
-        code->ptr()->entry_point_ = Instructions::EntryPoint(instr);
-        code->ptr()->monomorphic_entry_point_ =
-            Instructions::MonomorphicEntryPoint(instr);
-        code->ptr()->unchecked_entry_point_ =
-            Instructions::UncheckedEntryPoint(instr);
+        Code::InitializeCachedEntryPointsFrom(code, instr);
       }
 #endif  // !DART_PRECOMPILED_RUNTIME
 
@@ -1539,13 +1533,7 @@
           reinterpret_cast<RawExceptionHandlers*>(d->ReadRef());
       code->ptr()->pc_descriptors_ =
           reinterpret_cast<RawPcDescriptors*>(d->ReadRef());
-#if defined(DART_PRECOMPILED_RUNTIME) || defined(DART_PRECOMPILER)
-      code->ptr()->catch_entry_.catch_entry_moves_maps_ =
-          reinterpret_cast<RawTypedData*>(d->ReadRef());
-#else
-      code->ptr()->catch_entry_.variables_ =
-          reinterpret_cast<RawSmi*>(d->ReadRef());
-#endif
+      code->ptr()->catch_entry_ = d->ReadRef();
       code->ptr()->compressed_stackmaps_ =
           reinterpret_cast<RawCompressedStackMaps*>(d->ReadRef());
       code->ptr()->inlined_id_to_function_ =
@@ -1565,7 +1553,9 @@
 #if !defined(PRODUCT)
       code->ptr()->return_address_metadata_ = d->ReadRef();
       code->ptr()->var_descriptors_ = LocalVarDescriptors::null();
-      code->ptr()->comments_ = Array::null();
+      code->ptr()->comments_ = FLAG_code_comments
+                                   ? reinterpret_cast<RawArray*>(d->ReadRef())
+                                   : Array::null();
       code->ptr()->compile_timestamp_ = 0;
 #endif
 
@@ -1573,13 +1563,31 @@
     }
   }
 
-#if !(defined(DART_PRECOMPILED_RUNTIME) || defined(PRODUCT))
+#if !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER)
   void PostLoad(const Array& refs, Snapshot::Kind kind, Zone* zone) {
-    if (!CodeObservers::AreActive()) return;
+#if !defined(PRODUCT)
+    if (!CodeObservers::AreActive() && !FLAG_support_disassembler) return;
+#endif
     Code& code = Code::Handle(zone);
+    Object& owner = Object::Handle(zone);
     for (intptr_t id = start_index_; id < stop_index_; id++) {
       code ^= refs.At(id);
-      Code::NotifyCodeObservers(code, code.is_optimized());
+#if !defined(DART_PRECOMPILED_RUNTIME) && !defined(PRODUCT)
+      if (CodeObservers::AreActive()) {
+        Code::NotifyCodeObservers(code, code.is_optimized());
+      }
+#endif
+      owner = code.owner();
+      if (owner.IsFunction()) {
+        if ((FLAG_disassemble ||
+             (code.is_optimized() && FLAG_disassemble_optimized)) &&
+            FlowGraphPrinter::ShouldPrint(Function::Cast(owner))) {
+          Disassembler::DisassembleCode(Function::Cast(owner), code,
+                                        code.is_optimized());
+        }
+      } else if (FLAG_disassemble_stubs) {
+        Disassembler::DisassembleStub(code.Name(), code);
+      }
     }
   }
 #endif  // !DART_PRECOMPILED_RUNTIME
diff --git a/runtime/vm/code_comments.cc b/runtime/vm/code_comments.cc
index b4a8e03..74f8458 100644
--- a/runtime/vm/code_comments.cc
+++ b/runtime/vm/code_comments.cc
@@ -6,7 +6,9 @@
 
 namespace dart {
 
-#if !defined(DART_PRECOMPILED_RUNTIME) && !defined(PRODUCT)
+#if !defined(DART_PRECOMPILED_RUNTIME) &&                                      \
+    (!defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER))
+
 const Code::Comments& CreateCommentsFrom(compiler::Assembler* assembler) {
   const auto& comments = assembler->comments();
   Code::Comments& result = Code::Comments::New(comments.length());
@@ -18,6 +20,8 @@
 
   return result;
 }
-#endif  // !defined(DART_PRECOMPILED_RUNTIME) && !defined(PRODUCT)
+
+#endif  // !defined(DART_PRECOMPILED_RUNTIME) &&                               \
+        // (!defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER))
 
 }  // namespace dart
diff --git a/runtime/vm/code_comments.h b/runtime/vm/code_comments.h
index d7d1480..9c86524 100644
--- a/runtime/vm/code_comments.h
+++ b/runtime/vm/code_comments.h
@@ -11,7 +11,8 @@
 
 namespace dart {
 
-#if !defined(DART_PRECOMPILED_RUNTIME) && !defined(PRODUCT)
+#if !defined(DART_PRECOMPILED_RUNTIME) &&                                      \
+    (!defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER))
 
 class CodeCommentsWrapper final : public CodeComments {
  public:
@@ -36,7 +37,8 @@
 
 const Code::Comments& CreateCommentsFrom(compiler::Assembler* assembler);
 
-#endif  // !defined(DART_PRECOMPILED_RUNTIME) && !defined(PRODUCT)
+#endif  // !defined(DART_PRECOMPILED_RUNTIME) &&                               \
+        // (!defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER))
 
 }  // namespace dart
 
diff --git a/runtime/vm/code_descriptors.cc b/runtime/vm/code_descriptors.cc
index ee5662a..2ec7c2e 100644
--- a/runtime/vm/code_descriptors.cc
+++ b/runtime/vm/code_descriptors.cc
@@ -13,19 +13,26 @@
                                    intptr_t pc_offset,
                                    intptr_t deopt_id,
                                    TokenPosition token_pos,
-                                   intptr_t try_index) {
+                                   intptr_t try_index,
+                                   intptr_t yield_index) {
+  // yield index 0 is reserved for normal entry.
+  RELEASE_ASSERT(yield_index != 0);
+
   ASSERT((kind == RawPcDescriptors::kRuntimeCall) ||
          (kind == RawPcDescriptors::kBSSRelocation) ||
-         (kind == RawPcDescriptors::kOther) || (deopt_id != DeoptId::kNone));
+         (kind == RawPcDescriptors::kOther) ||
+         (yield_index != RawPcDescriptors::kInvalidYieldIndex) ||
+         (deopt_id != DeoptId::kNone));
 
-  // When precompiling, we only use pc descriptors for exceptions and
-  // relocations.
+  // When precompiling, we only use pc descriptors for exceptions,
+  // relocations and yield indices.
   if (!FLAG_precompiled_mode || try_index != -1 ||
+      yield_index != RawPcDescriptors::kInvalidYieldIndex ||
       kind == RawPcDescriptors::kBSSRelocation) {
-    int32_t merged_kind_try =
-        RawPcDescriptors::MergedKindTry::Encode(kind, try_index);
+    const int32_t kind_and_metadata =
+        RawPcDescriptors::KindAndMetadata::Encode(kind, try_index, yield_index);
 
-    PcDescriptors::EncodeInteger(&encoded_data_, merged_kind_try);
+    PcDescriptors::EncodeInteger(&encoded_data_, kind_and_metadata);
     PcDescriptors::EncodeInteger(&encoded_data_, pc_offset - prev_pc_offset);
     prev_pc_offset = pc_offset;
 
@@ -47,7 +54,8 @@
 }
 
 // Encode unsigned integer |value| in LEB128 format and store into |data|.
-static void EncodeLEB128(GrowableArray<uint8_t>* data, uintptr_t value) {
+void CompressedStackMapsBuilder::EncodeLEB128(GrowableArray<uint8_t>* data,
+                                              uintptr_t value) {
   while (true) {
     uint8_t part = value & 0x7f;
     value >>= 7;
@@ -74,19 +82,20 @@
 
 RawCompressedStackMaps* CompressedStackMapsBuilder::Finalize() const {
   if (encoded_bytes_.length() == 0) return CompressedStackMaps::null();
-  return CompressedStackMaps::New(encoded_bytes_);
+  return CompressedStackMaps::NewInlined(encoded_bytes_);
 }
 
-// Decode unsigned integer in LEB128 format from |data| and update |byte_index|.
-static uintptr_t DecodeLEB128(const uint8_t* data,
-                              const intptr_t data_length,
-                              intptr_t* byte_index) {
-  ASSERT(*byte_index < data_length);
+// Decode unsigned integer in LEB128 format from the payload of |maps| and
+// update |byte_index|.
+uintptr_t CompressedStackMapsIterator::DecodeLEB128(
+    const CompressedStackMaps& maps,
+    uintptr_t* byte_index) {
   uword shift = 0;
   uintptr_t value = 0;
   uint8_t part = 0;
   do {
-    part = data[(*byte_index)++];
+    ASSERT(*byte_index < maps.payload_size());
+    part = maps.PayloadByte((*byte_index)++);
     value |= static_cast<uintptr_t>(part & 0x7f) << shift;
     shift += 7;
   } while ((part & 0x80) != 0);
@@ -97,51 +106,85 @@
 bool CompressedStackMapsIterator::MoveNext() {
   // Empty CompressedStackMaps are represented as null values.
   if (maps_.IsNull() || next_offset_ >= maps_.payload_size()) return false;
-  intptr_t offset = next_offset_;
+  uintptr_t offset = next_offset_;
 
-  // We decode three LEB128 encoded integers after this, so there should be
-  // at least three bytes remaining in the payload.
-  ASSERT(offset <= maps_.payload_size() - 3);
-  auto const pc_delta =
-      DecodeLEB128(maps_.Payload(), maps_.payload_size(), &offset);
-  ASSERT(pc_delta <= kIntptrMax);
-
-  ASSERT(offset <= maps_.payload_size() - 2);
-  auto const spill_slot_bit_count =
-      DecodeLEB128(maps_.Payload(), maps_.payload_size(), &offset);
-  ASSERT(spill_slot_bit_count <= kIntptrMax);
-
-  ASSERT(offset <= maps_.payload_size() - 1);
-  auto const non_spill_slot_bit_count =
-      DecodeLEB128(maps_.Payload(), maps_.payload_size(), &offset);
-  ASSERT(non_spill_slot_bit_count <= kIntptrMax);
-
-  const auto stackmap_bits = spill_slot_bit_count + non_spill_slot_bit_count;
-  const intptr_t stackmap_size =
-      Utils::RoundUp(stackmap_bits, kBitsPerByte) >> kBitsPerByteLog2;
-  const intptr_t space_remaining = maps_.payload_size() - offset;
-  if (stackmap_size > space_remaining) return false;
-
-  // Now that the current entry has been completely decoded without errors, set
-  // the fields appropriately.
+  auto const pc_delta = DecodeLEB128(maps_, &offset);
   ASSERT(pc_delta <= (kMaxUint32 - current_pc_offset_));
   current_pc_offset_ += pc_delta;
-  current_spill_slot_bit_count_ = spill_slot_bit_count;
-  current_non_spill_slot_bit_count_ = non_spill_slot_bit_count;
-  current_bits_offset_ = offset;
-  next_offset_ = offset + stackmap_size;
 
+  // Table-using CSMs have a table offset after the PC offset delta, whereas
+  // the post-delta part of inlined entries has the same information as
+  // global table entries.
+  if (maps_.UsesGlobalTable()) {
+    current_global_table_offset_ = DecodeLEB128(maps_, &offset);
+    ASSERT(current_global_table_offset_ < bits_container_.payload_size());
+
+    // Since generally we only use entries in the GC and the GC only needs
+    // the rest of the entry information if the PC offset matches, we lazily
+    // load and cache the information stored in the global object when it is
+    // actually requested.
+    current_spill_slot_bit_count_ = -1;
+    current_non_spill_slot_bit_count_ = -1;
+    current_bits_offset_ = -1;
+  } else {
+    current_spill_slot_bit_count_ = DecodeLEB128(maps_, &offset);
+    ASSERT(current_spill_slot_bit_count_ >= 0);
+
+    current_non_spill_slot_bit_count_ = DecodeLEB128(maps_, &offset);
+    ASSERT(current_non_spill_slot_bit_count_ >= 0);
+
+    const auto stackmap_bits =
+        current_spill_slot_bit_count_ + current_non_spill_slot_bit_count_;
+    const uintptr_t stackmap_size =
+        Utils::RoundUp(stackmap_bits, kBitsPerByte) >> kBitsPerByteLog2;
+    ASSERT(stackmap_size <= (maps_.payload_size() - offset));
+
+    current_bits_offset_ = offset;
+    offset += stackmap_size;
+  }
+
+  next_offset_ = offset;
   return true;
 }
 
-bool CompressedStackMapsIterator::IsObject(intptr_t bit_index) const {
-  ASSERT(HasLoadedEntry());
-  ASSERT(bit_index >= 0 && bit_index < length());
+intptr_t CompressedStackMapsIterator::Length() {
+  EnsureFullyLoadedEntry();
+  return current_spill_slot_bit_count_ + current_non_spill_slot_bit_count_;
+}
+intptr_t CompressedStackMapsIterator::SpillSlotBitCount() {
+  EnsureFullyLoadedEntry();
+  return current_spill_slot_bit_count_;
+}
+
+bool CompressedStackMapsIterator::IsObject(intptr_t bit_index) {
+  EnsureFullyLoadedEntry();
+  ASSERT(!bits_container_.IsNull());
+  ASSERT(bit_index >= 0 && bit_index < Length());
   const intptr_t byte_index = bit_index >> kBitsPerByteLog2;
   const intptr_t bit_remainder = bit_index & (kBitsPerByte - 1);
   uint8_t byte_mask = 1U << bit_remainder;
-  uint8_t byte = maps_.Payload()[current_bits_offset_ + byte_index];
-  return (byte & byte_mask) != 0;
+  const intptr_t byte_offset = current_bits_offset_ + byte_index;
+  return (bits_container_.PayloadByte(byte_offset) & byte_mask) != 0;
+}
+
+void CompressedStackMapsIterator::LazyLoadGlobalTableEntry() {
+  ASSERT(maps_.UsesGlobalTable() && bits_container_.IsGlobalTable());
+  ASSERT(HasLoadedEntry());
+  ASSERT(current_global_table_offset_ < bits_container_.payload_size());
+
+  uintptr_t offset = current_global_table_offset_;
+  current_spill_slot_bit_count_ = DecodeLEB128(bits_container_, &offset);
+  ASSERT(current_spill_slot_bit_count_ >= 0);
+
+  current_non_spill_slot_bit_count_ = DecodeLEB128(bits_container_, &offset);
+  ASSERT(current_non_spill_slot_bit_count_ >= 0);
+
+  const auto stackmap_bits = Length();
+  const uintptr_t stackmap_size =
+      Utils::RoundUp(stackmap_bits, kBitsPerByte) >> kBitsPerByteLog2;
+  ASSERT(stackmap_size <= (bits_container_.payload_size() - offset));
+
+  current_bits_offset_ = offset;
 }
 
 RawExceptionHandlers* ExceptionHandlerList::FinalizeExceptionHandlers(
diff --git a/runtime/vm/code_descriptors.h b/runtime/vm/code_descriptors.h
index 0706189..31aa55c 100644
--- a/runtime/vm/code_descriptors.h
+++ b/runtime/vm/code_descriptors.h
@@ -30,7 +30,8 @@
                      intptr_t pc_offset,
                      intptr_t deopt_id,
                      TokenPosition token_pos,
-                     intptr_t try_index);
+                     intptr_t try_index,
+                     intptr_t yield_index);
 
   RawPcDescriptors* FinalizePcDescriptors(uword entry_point);
 
@@ -48,6 +49,8 @@
  public:
   CompressedStackMapsBuilder() : encoded_bytes_() {}
 
+  static void EncodeLEB128(GrowableArray<uint8_t>* data, uintptr_t value);
+
   void AddEntry(intptr_t pc_offset,
                 BitmapBuilder* bitmap,
                 intptr_t spill_slot_bit_count);
@@ -64,8 +67,16 @@
  public:
   // We use the null value to represent CompressedStackMaps with no
   // entries, so the constructor allows them.
+  CompressedStackMapsIterator(const CompressedStackMaps& maps,
+                              const CompressedStackMaps& global_table)
+      : maps_(maps),
+        bits_container_(maps_.UsesGlobalTable() ? global_table : maps_) {
+    ASSERT(!maps_.IsGlobalTable());
+    ASSERT(!maps_.UsesGlobalTable() || bits_container_.IsGlobalTable());
+  }
+
   explicit CompressedStackMapsIterator(const CompressedStackMaps& maps)
-      : maps_(maps) {}
+      : CompressedStackMapsIterator(maps, CompressedStackMaps::Handle()) {}
 
   // Loads the next entry from [maps_], if any. If [maps_] is the null
   // value, this always returns false.
@@ -91,25 +102,38 @@
     ASSERT(HasLoadedEntry());
     return current_pc_offset_;
   }
-  intptr_t length() const {
+  // We lazily load and cache information from the global table if the
+  // CSM uses it, so these methods cannot be const.
+  intptr_t Length();
+  intptr_t SpillSlotBitCount();
+  bool IsObject(intptr_t bit_offset);
+
+  void EnsureFullyLoadedEntry() {
     ASSERT(HasLoadedEntry());
-    return current_spill_slot_bit_count_ + current_non_spill_slot_bit_count_;
+    if (current_spill_slot_bit_count_ < 0) {
+      LazyLoadGlobalTableEntry();
+    }
+    ASSERT(current_spill_slot_bit_count_ >= 0);
   }
-  intptr_t spill_slot_bit_count() const {
-    ASSERT(HasLoadedEntry());
-    return current_spill_slot_bit_count_;
-  }
-  bool IsObject(intptr_t bit_offset) const;
 
  private:
+  static uintptr_t DecodeLEB128(const CompressedStackMaps& data,
+                                uintptr_t* byte_index);
   bool HasLoadedEntry() const { return next_offset_ > 0; }
+  void LazyLoadGlobalTableEntry();
 
   const CompressedStackMaps& maps_;
-  intptr_t next_offset_ = 0;
+  const CompressedStackMaps& bits_container_;
+
+  uintptr_t next_offset_ = 0;
   uint32_t current_pc_offset_ = 0;
+  // Only used when looking up non-PC information in the global table.
+  uintptr_t current_global_table_offset_ = 0;
   intptr_t current_spill_slot_bit_count_ = -1;
   intptr_t current_non_spill_slot_bit_count_ = -1;
   intptr_t current_bits_offset_ = -1;
+
+  friend class StackMapEntry;
 };
 
 class ExceptionHandlerList : public ZoneAllocated {
diff --git a/runtime/vm/code_descriptors_test.cc b/runtime/vm/code_descriptors_test.cc
index d959adff..8d5a376 100644
--- a/runtime/vm/code_descriptors_test.cc
+++ b/runtime/vm/code_descriptors_test.cc
@@ -143,7 +143,7 @@
 
   for (intptr_t i = 0; i < num_token_positions; i++) {
     descriptors->AddDescriptor(RawPcDescriptors::kRuntimeCall, 0, 0,
-                               TokenPosition(token_positions[i]), 0);
+                               TokenPosition(token_positions[i]), 0, 1);
   }
 
   const PcDescriptors& finalized_descriptors =
diff --git a/runtime/vm/code_observers.h b/runtime/vm/code_observers.h
index 5494b58..c76f5f5 100644
--- a/runtime/vm/code_observers.h
+++ b/runtime/vm/code_observers.h
@@ -12,9 +12,7 @@
 
 namespace dart {
 
-#ifndef PRODUCT
-
-class Mutex;
+#if !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER)
 
 // An abstract representation of comments associated with the given code
 // object. We assume that comments are sorted by PCOffset.
@@ -28,6 +26,10 @@
   virtual const char* CommentAt(intptr_t index) const = 0;
 };
 
+#endif  // !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER)
+
+#if !defined(PRODUCT)
+
 // Object observing code creation events. Used by external profilers and
 // debuggers to map address ranges to function names.
 class CodeObserver {
@@ -53,6 +55,8 @@
   DISALLOW_COPY_AND_ASSIGN(CodeObserver);
 };
 
+class Mutex;
+
 class CodeObservers : public AllStatic {
  public:
   static void Init();
@@ -82,7 +86,7 @@
   static CodeObserver** observers_;
 };
 
-#endif  // !PRODUCT
+#endif  // !defined(PRODUCT)
 
 }  // namespace dart
 
diff --git a/runtime/vm/compiler/aot/aot_call_specializer.cc b/runtime/vm/compiler/aot/aot_call_specializer.cc
index 65afe80..adb3aa1 100644
--- a/runtime/vm/compiler/aot/aot_call_specializer.cc
+++ b/runtime/vm/compiler/aot/aot_call_specializer.cc
@@ -828,8 +828,7 @@
     // Check if the single target is a polymorphic target, if it is,
     // we don't have one target.
     const Function& target = targets.FirstTarget();
-    const bool polymorphic_target = MethodRecognizer::PolymorphicTarget(target);
-    has_one_target = !polymorphic_target;
+    has_one_target = !target.is_polymorphic_target();
   }
 
   if (has_one_target) {
diff --git a/runtime/vm/compiler/aot/precompiler.cc b/runtime/vm/compiler/aot/precompiler.cc
index ef81ad9f..109732d 100644
--- a/runtime/vm/compiler/aot/precompiler.cc
+++ b/runtime/vm/compiler/aot/precompiler.cc
@@ -1842,7 +1842,6 @@
         script.set_compile_time_constants(Array::null_array());
         script.set_line_starts(null_typed_data);
         script.set_debug_positions(Array::null_array());
-        script.set_yield_positions(Array::null_array());
         script.set_kernel_program_info(null_info);
         script.set_source(String::null_string());
       }
@@ -1895,16 +1894,6 @@
     constants = cls.constants();
     ASSERT(constants.Length() == 0);
 
-#if !defined(PRODUCT)
-    intptr_t instances =
-        class_table->StatsWithUpdatedSize(cid)->post_gc.new_count +
-        class_table->StatsWithUpdatedSize(cid)->post_gc.old_count;
-    if (instances != 0) {
-      FATAL2("Want to drop class %s, but it has %" Pd " instances\n",
-             cls.ToCString(), instances);
-    }
-#endif
-
     dropped_class_count_++;
     if (FLAG_trace_precompiler) {
       THR_Print("Dropping class %" Pd " %s\n", cid, cls.ToCString());
diff --git a/runtime/vm/compiler/asm_intrinsifier_arm.cc b/runtime/vm/compiler/asm_intrinsifier_arm.cc
index b83a772..51b28bd 100644
--- a/runtime/vm/compiler/asm_intrinsifier_arm.cc
+++ b/runtime/vm/compiler/asm_intrinsifier_arm.cc
@@ -120,16 +120,12 @@
   __ cmp(R1, Operand(IP));                                                     \
   __ b(normal_ir_body, CS);                                                    \
                                                                                \
-  /* Successfully allocated the object(s), now update top to point to */       \
-  /* next object start and initialize the object. */                           \
-  NOT_IN_PRODUCT(__ LoadAllocationStatsAddress(R4, cid));                      \
   __ str(R1, Address(THR, target::Thread::top_offset()));                      \
   __ AddImmediate(R0, kHeapObjectTag);                                         \
   /* Initialize the tags. */                                                   \
   /* R0: new object start as a tagged pointer. */                              \
   /* R1: new object end address. */                                            \
   /* R2: allocation size. */                                                   \
-  /* R4: allocation stats address */                                           \
   {                                                                            \
     __ CompareImmediate(R2, target::RawObject::kSizeTagMaxSizeTag);            \
     __ mov(R3,                                                                 \
@@ -150,7 +146,6 @@
   /* R0: new object start as a tagged pointer. */                              \
   /* R1: new object end address. */                                            \
   /* R2: allocation size. */                                                   \
-  /* R4: allocation stats address. */                                          \
   __ ldr(R3, Address(SP, kArrayLengthStackOffset)); /* Array length. */        \
   __ StoreIntoObjectNoBarrier(                                                 \
       R0, FieldAddress(R0, target::TypedDataBase::length_offset()), R3);       \
@@ -159,7 +154,6 @@
   /* R1: new object end address. */                                            \
   /* R2: allocation size. */                                                   \
   /* R3: iterator which initially points to the start of the variable */       \
-  /* R4: allocation stats address */                                           \
   /* R8, R9: zero. */                                                          \
   /* data area to be initialized. */                                           \
   __ LoadImmediate(R8, 0);                                                     \
@@ -175,7 +169,6 @@
   __ b(&init_loop, CC);                                                        \
   __ str(R8, Address(R3, -2 * target::kWordSize), HI);                         \
                                                                                \
-  NOT_IN_PRODUCT(__ IncrementAllocationStatsWithSize(R4, R2));                 \
   __ Ret();                                                                    \
   __ Bind(normal_ir_body);
 
@@ -1977,7 +1970,6 @@
 
   // Successfully allocated the object(s), now update top to point to
   // next object start and initialize the object.
-  NOT_IN_PRODUCT(__ LoadAllocationStatsAddress(R4, cid));
   __ str(R1, Address(THR, target::Thread::top_offset()));
   __ AddImmediate(R0, kHeapObjectTag);
 
@@ -1985,7 +1977,6 @@
   // R0: new object start as a tagged pointer.
   // R1: new object end address.
   // R2: allocation size.
-  // R4: allocation stats address.
   {
     const intptr_t shift = target::RawObject::kTagBitsSizeTagPos -
                            target::ObjectAlignment::kObjectAlignmentLog2;
@@ -2011,7 +2002,6 @@
   __ StoreIntoObjectNoBarrier(
       R0, FieldAddress(R0, target::String::hash_offset()), TMP);
 
-  NOT_IN_PRODUCT(__ IncrementAllocationStatsWithSize(R4, R2));
   __ b(ok);
 }
 
diff --git a/runtime/vm/compiler/asm_intrinsifier_arm64.cc b/runtime/vm/compiler/asm_intrinsifier_arm64.cc
index 2ae8fb3..e8d13e7 100644
--- a/runtime/vm/compiler/asm_intrinsifier_arm64.cc
+++ b/runtime/vm/compiler/asm_intrinsifier_arm64.cc
@@ -144,7 +144,6 @@
   /* next object start and initialize the object. */                           \
   __ str(R1, Address(THR, target::Thread::top_offset()));                      \
   __ AddImmediate(R0, kHeapObjectTag);                                         \
-  NOT_IN_PRODUCT(__ UpdateAllocationStatsWithSize(cid, R2));                   \
   /* Initialize the tags. */                                                   \
   /* R0: new object start as a tagged pointer. */                              \
   /* R1: new object end address. */                                            \
@@ -2047,7 +2046,6 @@
   // next object start and initialize the object.
   __ str(R1, Address(THR, target::Thread::top_offset()));
   __ AddImmediate(R0, kHeapObjectTag);
-  NOT_IN_PRODUCT(__ UpdateAllocationStatsWithSize(cid, R2));
 
   // Initialize the tags.
   // R0: new object start as a tagged pointer.
diff --git a/runtime/vm/compiler/asm_intrinsifier_ia32.cc b/runtime/vm/compiler/asm_intrinsifier_ia32.cc
index d53462a..b681720 100644
--- a/runtime/vm/compiler/asm_intrinsifier_ia32.cc
+++ b/runtime/vm/compiler/asm_intrinsifier_ia32.cc
@@ -128,7 +128,6 @@
   /* next object start and initialize the object. */                           \
   __ movl(Address(THR, target::Thread::top_offset()), EBX);                    \
   __ addl(EAX, Immediate(kHeapObjectTag));                                     \
-  NOT_IN_PRODUCT(__ UpdateAllocationStatsWithSize(cid, EDI, ECX));             \
                                                                                \
   /* Initialize the tags. */                                                   \
   /* EAX: new object start as a tagged pointer. */                             \
@@ -1999,8 +1998,6 @@
   __ movl(Address(THR, target::Thread::top_offset()), EBX);
   __ addl(EAX, Immediate(kHeapObjectTag));
 
-  NOT_IN_PRODUCT(__ UpdateAllocationStatsWithSize(cid, EDI, ECX));
-
   // Initialize the tags.
   // EAX: new object start as a tagged pointer.
   // EBX: new object end address.
diff --git a/runtime/vm/compiler/asm_intrinsifier_x64.cc b/runtime/vm/compiler/asm_intrinsifier_x64.cc
index 02ec2c2..d8586e1 100644
--- a/runtime/vm/compiler/asm_intrinsifier_x64.cc
+++ b/runtime/vm/compiler/asm_intrinsifier_x64.cc
@@ -130,7 +130,6 @@
   /* next object start and initialize the object. */                           \
   __ movq(Address(THR, target::Thread::top_offset()), RCX);                    \
   __ addq(RAX, Immediate(kHeapObjectTag));                                     \
-  NOT_IN_PRODUCT(__ UpdateAllocationStatsWithSize(cid, RDI));                  \
   /* Initialize the tags. */                                                   \
   /* RAX: new object start as a tagged pointer. */                             \
   /* RCX: new object end address. */                                           \
@@ -2029,7 +2028,6 @@
   // next object start and initialize the object.
   __ movq(Address(THR, target::Thread::top_offset()), RCX);
   __ addq(RAX, Immediate(kHeapObjectTag));
-  NOT_IN_PRODUCT(__ UpdateAllocationStatsWithSize(cid, RDI));
 
   // Initialize the tags.
   // RAX: new object start as a tagged pointer.
diff --git a/runtime/vm/compiler/assembler/assembler.cc b/runtime/vm/compiler/assembler/assembler.cc
index 6cc1a58..9dfdf2e 100644
--- a/runtime/vm/compiler/assembler/assembler.cc
+++ b/runtime/vm/compiler/assembler/assembler.cc
@@ -20,10 +20,6 @@
             false,
             "Verify instructions offset in code object."
             "NOTE: This breaks the profiler.");
-DEFINE_FLAG(bool,
-            code_comments,
-            false,
-            "Include comments into code and disassembly");
 #if defined(TARGET_ARCH_ARM)
 DEFINE_FLAG(bool, use_far_branches, false, "Enable far branches for ARM.");
 #endif
diff --git a/runtime/vm/compiler/assembler/assembler_arm.cc b/runtime/vm/compiler/assembler/assembler_arm.cc
index b573250..1a5ee3c 100644
--- a/runtime/vm/compiler/assembler/assembler_arm.cc
+++ b/runtime/vm/compiler/assembler/assembler_arm.cc
@@ -3497,9 +3497,8 @@
 void Assembler::MaybeTraceAllocation(Register stats_addr_reg, Label* trace) {
   ASSERT(stats_addr_reg != kNoRegister);
   ASSERT(stats_addr_reg != TMP);
-  const uword state_offset = target::ClassHeapStats::state_offset();
-  ldr(TMP, Address(stats_addr_reg, state_offset));
-  tst(TMP, Operand(target::ClassHeapStats::TraceAllocationMask()));
+  ldrb(TMP, Address(stats_addr_reg, 0));
+  cmp(TMP, Operand(0));
   b(trace, NE);
 }
 
@@ -3520,37 +3519,6 @@
   ldr(dest, Address(dest, table_offset));
   AddImmediate(dest, class_offset);
 }
-
-void Assembler::IncrementAllocationStats(Register stats_addr_reg,
-                                         intptr_t cid) {
-  ASSERT(stats_addr_reg != kNoRegister);
-  ASSERT(stats_addr_reg != TMP);
-  ASSERT(cid > 0);
-  const uword count_field_offset =
-      target::ClassHeapStats::allocated_since_gc_new_space_offset();
-  const Address& count_address = Address(stats_addr_reg, count_field_offset);
-  ldr(TMP, count_address);
-  AddImmediate(TMP, 1);
-  str(TMP, count_address);
-}
-
-void Assembler::IncrementAllocationStatsWithSize(Register stats_addr_reg,
-                                                 Register size_reg) {
-  ASSERT(stats_addr_reg != kNoRegister);
-  ASSERT(stats_addr_reg != TMP);
-  const uword count_field_offset =
-      target::ClassHeapStats::allocated_since_gc_new_space_offset();
-  const uword size_field_offset =
-      target::ClassHeapStats::allocated_size_since_gc_new_space_offset();
-  const Address& count_address = Address(stats_addr_reg, count_field_offset);
-  const Address& size_address = Address(stats_addr_reg, size_field_offset);
-  ldr(TMP, count_address);
-  AddImmediate(TMP, 1);
-  str(TMP, count_address);
-  ldr(TMP, size_address);
-  add(TMP, TMP, Operand(size_reg));
-  str(TMP, size_address);
-}
 #endif  // !PRODUCT
 
 void Assembler::TryAllocate(const Class& cls,
@@ -3592,8 +3560,6 @@
         target::MakeTagWordForNewSpaceObject(cid, instance_size);
     LoadImmediate(IP, tags);
     str(IP, FieldAddress(instance_reg, target::Object::tags_offset()));
-
-    NOT_IN_PRODUCT(IncrementAllocationStats(temp_reg, cid));
   } else {
     b(failure);
   }
@@ -3638,9 +3604,6 @@
     LoadImmediate(temp2, tags);
     str(temp2,
         FieldAddress(instance, target::Object::tags_offset()));  // Store tags.
-
-    NOT_IN_PRODUCT(LoadImmediate(temp2, instance_size));
-    NOT_IN_PRODUCT(IncrementAllocationStatsWithSize(temp1, temp2));
   } else {
     b(failure);
   }
diff --git a/runtime/vm/compiler/assembler/assembler_arm.h b/runtime/vm/compiler/assembler/assembler_arm.h
index cd26332..2e9f016 100644
--- a/runtime/vm/compiler/assembler/assembler_arm.h
+++ b/runtime/vm/compiler/assembler/assembler_arm.h
@@ -1092,9 +1092,6 @@
   // allocation stats. These are separate assembler macros so we can
   // avoid a dependent load too nearby the load of the table address.
   void LoadAllocationStatsAddress(Register dest, intptr_t cid);
-  void IncrementAllocationStats(Register stats_addr, intptr_t cid);
-  void IncrementAllocationStatsWithSize(Register stats_addr_reg,
-                                        Register size_reg);
 
   Address ElementAddressForIntIndex(bool is_load,
                                     bool is_external,
diff --git a/runtime/vm/compiler/assembler/assembler_arm64.cc b/runtime/vm/compiler/assembler/assembler_arm64.cc
index e8de187..eeaab46 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64.cc
+++ b/runtime/vm/compiler/assembler/assembler_arm64.cc
@@ -475,7 +475,9 @@
                                  bool is_unique) {
   ASSERT(IsOriginalObject(object));
   word offset = 0;
-  if (target::CanLoadFromThread(object, &offset)) {
+  if (IsSameObject(compiler::NullObject(), object)) {
+    mov(dst, NULL_REG);
+  } else if (target::CanLoadFromThread(object, &offset)) {
     ldr(dst, Address(THR, offset));
   } else if (CanLoadFromObjectPool(object)) {
     const int32_t offset = target::ObjectPool::element_offset(
@@ -499,7 +501,9 @@
 void Assembler::CompareObject(Register reg, const Object& object) {
   ASSERT(IsOriginalObject(object));
   word offset = 0;
-  if (target::CanLoadFromThread(object, &offset)) {
+  if (IsSameObject(compiler::NullObject(), object)) {
+    CompareRegisters(reg, NULL_REG);
+  } else if (target::CanLoadFromThread(object, &offset)) {
     ldr(TMP, Address(THR, offset));
     CompareRegisters(reg, TMP);
   } else if (CanLoadFromObjectPool(object)) {
@@ -1083,8 +1087,12 @@
   ASSERT(IsOriginalObject(value));
   ASSERT(IsNotTemporaryScopedHandle(value));
   // No store buffer update.
-  LoadObject(TMP2, value);
-  str(TMP2, dest);
+  if (IsSameObject(compiler::NullObject(), value)) {
+    str(NULL_REG, dest);
+  } else {
+    LoadObject(TMP2, value);
+    str(TMP2, dest);
+  }
 }
 
 void Assembler::StoreIntoObjectOffsetNoBarrier(Register object,
@@ -1182,6 +1190,12 @@
   CheckCodePointer();
 }
 
+void Assembler::RestorePinnedRegisters() {
+  ldr(BARRIER_MASK,
+      compiler::Address(THR, target::Thread::write_barrier_mask_offset()));
+  ldr(NULL_REG, compiler::Address(THR, target::Thread::object_null_offset()));
+}
+
 void Assembler::CheckCodePointer() {
 #ifdef DEBUG
   if (!FLAG_check_code_pointer) {
@@ -1572,62 +1586,14 @@
       target::ClassTable::shared_class_table_offset();
   const intptr_t table_offset =
       target::SharedClassTable::class_heap_stats_table_offset();
-  const intptr_t state_offset = target::ClassTable::StateOffsetFor(cid);
+  const intptr_t class_offset = target::ClassTable::ClassOffsetFor(cid);
 
   LoadIsolate(temp_reg);
   ldr(temp_reg, Address(temp_reg, shared_table_offset));
   ldr(temp_reg, Address(temp_reg, table_offset));
-  AddImmediate(temp_reg, state_offset);
-  ldr(temp_reg, Address(temp_reg, 0));
-  tsti(temp_reg, Immediate(target::ClassHeapStats::TraceAllocationMask()));
-  b(trace, NE);
-}
-
-void Assembler::UpdateAllocationStats(intptr_t cid) {
-  ASSERT(cid > 0);
-
-  const intptr_t shared_table_offset =
-      target::Isolate::class_table_offset() +
-      target::ClassTable::shared_class_table_offset();
-  const intptr_t table_offset =
-      target::SharedClassTable::class_heap_stats_table_offset();
-  const intptr_t counter_offset =
-      target::ClassTable::NewSpaceCounterOffsetFor(cid);
-
-  LoadIsolate(TMP2);
-  ldr(TMP2, Address(TMP2, shared_table_offset));
-  ldr(TMP, Address(TMP2, table_offset));
-  AddImmediate(TMP2, TMP, counter_offset);
-  ldr(TMP, Address(TMP2, 0));
-  AddImmediate(TMP, 1);
-  str(TMP, Address(TMP2, 0));
-}
-
-void Assembler::UpdateAllocationStatsWithSize(intptr_t cid, Register size_reg) {
-  ASSERT(cid > 0);
-
-  const intptr_t shared_table_offset =
-      target::Isolate::class_table_offset() +
-      target::ClassTable::shared_class_table_offset();
-  const intptr_t table_offset =
-      target::SharedClassTable::class_heap_stats_table_offset();
-
-  const uword class_offset = target::ClassTable::ClassOffsetFor(cid);
-  const uword count_field_offset =
-      target::ClassHeapStats::allocated_since_gc_new_space_offset();
-  const uword size_field_offset =
-      target::ClassHeapStats::allocated_size_since_gc_new_space_offset();
-
-  LoadIsolate(TMP2);
-  ldr(TMP2, Address(TMP2, shared_table_offset));
-  ldr(TMP, Address(TMP2, table_offset));
-  AddImmediate(TMP2, TMP, class_offset);
-  ldr(TMP, Address(TMP2, count_field_offset));
-  AddImmediate(TMP, 1);
-  str(TMP, Address(TMP2, count_field_offset));
-  ldr(TMP, Address(TMP2, size_field_offset));
-  add(TMP, TMP, Operand(size_reg));
-  str(TMP, Address(TMP2, size_field_offset));
+  AddImmediate(temp_reg, class_offset);
+  ldr(temp_reg, Address(temp_reg, 0), kUnsignedByte);
+  cbnz(trace, temp_reg);
 }
 #endif  // !PRODUCT
 
@@ -1663,8 +1629,6 @@
     // next object start and store the class in the class field of object.
     str(top_reg, Address(THR, target::Thread::top_offset()));
 
-    NOT_IN_PRODUCT(UpdateAllocationStats(cid));
-
     const uint32_t tags =
         target::MakeTagWordForNewSpaceObject(cid, instance_size);
     // Extends the 32 bit tags with zeros, which is the uninitialized
@@ -1710,7 +1674,6 @@
     str(end_address, Address(THR, target::Thread::top_offset()));
     add(instance, instance, Operand(kHeapObjectTag));
     NOT_IN_PRODUCT(LoadImmediate(temp2, instance_size));
-    NOT_IN_PRODUCT(UpdateAllocationStatsWithSize(cid, temp2));
 
     // Initialize the tags.
     // instance: new object start as a tagged pointer.
diff --git a/runtime/vm/compiler/assembler/assembler_arm64.h b/runtime/vm/compiler/assembler/assembler_arm64.h
index 6b1805c..719b520 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64.h
+++ b/runtime/vm/compiler/assembler/assembler_arm64.h
@@ -1515,8 +1515,12 @@
                                     uint32_t offset);
 
   void PushObject(const Object& object) {
-    LoadObject(TMP, object);
-    Push(TMP);
+    if (IsSameObject(compiler::NullObject(), object)) {
+      Push(NULL_REG);
+    } else {
+      LoadObject(TMP, object);
+      Push(TMP);
+    }
   }
   void PushImmediate(int64_t immediate) {
     LoadImmediate(TMP, immediate);
@@ -1556,6 +1560,10 @@
   void CheckCodePointer();
   void RestoreCodePointer();
 
+  // Restores the values of the registers that are blocked to cache some values
+  // e.g. BARRIER_MASK and NULL_REG.
+  void RestorePinnedRegisters();
+
   void EnterDartFrame(intptr_t frame_size, Register new_pp = kNoRegister);
   void EnterOsrFrame(intptr_t extra_size, Register new_pp = kNoRegister);
   void LeaveDartFrame(RestorePP restore_pp = kRestoreCallerPP);
@@ -1573,10 +1581,6 @@
   void MonomorphicCheckedEntryAOT();
   void BranchOnMonomorphicCheckedEntryJIT(Label* label);
 
-  void UpdateAllocationStats(intptr_t cid);
-
-  void UpdateAllocationStatsWithSize(intptr_t cid, Register size_reg);
-
   // If allocation tracing for |cid| is enabled, will jump to |trace| label,
   // which will allocate in the runtime where tracing occurs.
   void MaybeTraceAllocation(intptr_t cid, Register temp_reg, Label* trace);
diff --git a/runtime/vm/compiler/assembler/assembler_arm64_test.cc b/runtime/vm/compiler/assembler/assembler_arm64_test.cc
index 13a69a8..310e20e 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64_test.cc
+++ b/runtime/vm/compiler/assembler/assembler_arm64_test.cc
@@ -2398,15 +2398,18 @@
   __ Push(CODE_REG);
   __ Push(THR);
   __ Push(BARRIER_MASK);
+  __ Push(NULL_REG);
   __ TagAndPushPP();
   __ ldr(CODE_REG, Address(R0, VMHandles::kOffsetOfRawPtrInHandle));
   __ mov(THR, R1);
   __ ldr(BARRIER_MASK, Address(THR, Thread::write_barrier_mask_offset()));
+  __ ldr(NULL_REG, Address(THR, Thread::object_null_offset()));
   __ LoadPoolPointer(PP);
 }
 
 static void LeaveTestFrame(Assembler* assembler) {
   __ PopAndUntagPP();
+  __ Pop(NULL_REG);
   __ Pop(BARRIER_MASK);
   __ Pop(THR);
   __ Pop(CODE_REG);
@@ -2481,6 +2484,39 @@
   EXPECT_EQ(Object::null(), test->InvokeWithCodeAndThread<RawObject*>());
 }
 
+// PushObject null.
+ASSEMBLER_TEST_GENERATE(PushObjectNull, assembler) {
+  __ SetupDartSP();
+  EnterTestFrame(assembler);
+  __ PushObject(Object::null_object());
+  __ Pop(R0);
+  LeaveTestFrame(assembler);
+  __ RestoreCSP();
+  __ ret();
+}
+
+ASSEMBLER_TEST_RUN(PushObjectNull, test) {
+  EXPECT_EQ(Object::null(), test->InvokeWithCodeAndThread<RawObject*>());
+}
+
+// CompareObject null.
+ASSEMBLER_TEST_GENERATE(CompareObjectNull, assembler) {
+  __ SetupDartSP();
+  EnterTestFrame(assembler);
+  __ LoadObject(R0, Object::bool_true());
+  __ LoadObject(R1, Object::bool_false());
+  __ ldr(R2, Address(THR, Thread::object_null_offset()));
+  __ CompareObject(R2, Object::null_object());
+  __ csel(R0, R0, R1, EQ);
+  LeaveTestFrame(assembler);
+  __ RestoreCSP();
+  __ ret();
+}
+
+ASSEMBLER_TEST_RUN(CompareObjectNull, test) {
+  EXPECT_EQ(Bool::True().raw(), test->InvokeWithCodeAndThread<RawObject*>());
+}
+
 ASSEMBLER_TEST_GENERATE(LoadObjectTrue, assembler) {
   __ SetupDartSP();
   EnterTestFrame(assembler);
diff --git a/runtime/vm/compiler/assembler/assembler_ia32.cc b/runtime/vm/compiler/assembler/assembler_ia32.cc
index 63cab25..0dcc1d4 100644
--- a/runtime/vm/compiler/assembler/assembler_ia32.cc
+++ b/runtime/vm/compiler/assembler/assembler_ia32.cc
@@ -2409,56 +2409,17 @@
       target::ClassTable::shared_class_table_offset();
   const intptr_t table_offset =
       target::SharedClassTable::class_heap_stats_table_offset();
-  const intptr_t state_offset = target::ClassTable::StateOffsetFor(cid);
+  const intptr_t class_offset = target::ClassTable::ClassOffsetFor(cid);
 
   ASSERT(temp_reg != kNoRegister);
   LoadIsolate(temp_reg);
   movl(temp_reg, Address(temp_reg, shared_table_offset));
   movl(temp_reg, Address(temp_reg, table_offset));
-  state_address = Address(temp_reg, state_offset);
-  testb(state_address,
-        Immediate(target::ClassHeapStats::TraceAllocationMask()));
+  cmpb(Address(temp_reg, class_offset), Immediate(0));
   // We are tracing for this class, jump to the trace label which will use
   // the allocation stub.
   j(NOT_ZERO, trace, near_jump);
 }
-
-void Assembler::UpdateAllocationStats(intptr_t cid, Register temp_reg) {
-  ASSERT(cid > 0);
-  const intptr_t shared_table_offset =
-      target::Isolate::class_table_offset() +
-      target::ClassTable::shared_class_table_offset();
-  const intptr_t table_offset =
-      target::SharedClassTable::class_heap_stats_table_offset();
-  const intptr_t counter_offset =
-      target::ClassTable::NewSpaceCounterOffsetFor(cid);
-
-  ASSERT(temp_reg != kNoRegister);
-  LoadIsolate(temp_reg);
-  movl(temp_reg, Address(temp_reg, shared_table_offset));
-  movl(temp_reg, Address(temp_reg, table_offset));
-  incl(Address(temp_reg, counter_offset));
-}
-
-void Assembler::UpdateAllocationStatsWithSize(intptr_t cid,
-                                              Register size_reg,
-                                              Register temp_reg) {
-  ASSERT(cid > 0);
-  ASSERT(cid < kNumPredefinedCids);
-  UpdateAllocationStats(cid, temp_reg);
-  intptr_t size_offset = target::ClassTable::NewSpaceSizeOffsetFor(cid);
-  addl(Address(temp_reg, size_offset), size_reg);
-}
-
-void Assembler::UpdateAllocationStatsWithSize(intptr_t cid,
-                                              intptr_t size_in_bytes,
-                                              Register temp_reg) {
-  ASSERT(cid > 0);
-  ASSERT(cid < kNumPredefinedCids);
-  UpdateAllocationStats(cid, temp_reg);
-  intptr_t size_offset = target::ClassTable::NewSpaceSizeOffsetFor(cid);
-  addl(Address(temp_reg, size_offset), Immediate(size_in_bytes));
-}
 #endif  // !PRODUCT
 
 void Assembler::TryAllocate(const Class& cls,
@@ -2484,7 +2445,6 @@
     // Successfully allocated the object, now update top to point to
     // next object start and store the class in the class field of object.
     movl(Address(THR, target::Thread::top_offset()), instance_reg);
-    NOT_IN_PRODUCT(UpdateAllocationStats(cid, temp_reg));
     ASSERT(instance_size >= kHeapObjectTag);
     subl(instance_reg, Immediate(instance_size - kHeapObjectTag));
     const uint32_t tags =
@@ -2527,7 +2487,6 @@
     // next object start and initialize the object.
     movl(Address(THR, target::Thread::top_offset()), end_address);
     addl(instance, Immediate(kHeapObjectTag));
-    NOT_IN_PRODUCT(UpdateAllocationStatsWithSize(cid, instance_size, temp_reg));
 
     // Initialize the tags.
     const uint32_t tags =
diff --git a/runtime/vm/compiler/assembler/assembler_ia32.h b/runtime/vm/compiler/assembler/assembler_ia32.h
index e4e86c1..d8fca975 100644
--- a/runtime/vm/compiler/assembler/assembler_ia32.h
+++ b/runtime/vm/compiler/assembler/assembler_ia32.h
@@ -810,15 +810,6 @@
                             Label* trace,
                             bool near_jump);
 
-  void UpdateAllocationStats(intptr_t cid, Register temp_reg);
-
-  void UpdateAllocationStatsWithSize(intptr_t cid,
-                                     Register size_reg,
-                                     Register temp_reg);
-  void UpdateAllocationStatsWithSize(intptr_t cid,
-                                     intptr_t instance_size,
-                                     Register temp_reg);
-
   // Inlined allocation of an instance of class 'cls', code has no runtime
   // calls. Jump to 'failure' if the instance cannot be allocated here.
   // Allocated instance is returned in 'instance_reg'.
diff --git a/runtime/vm/compiler/assembler/assembler_x64.cc b/runtime/vm/compiler/assembler/assembler_x64.cc
index c9e1299..9556a10 100644
--- a/runtime/vm/compiler/assembler/assembler_x64.cc
+++ b/runtime/vm/compiler/assembler/assembler_x64.cc
@@ -1873,54 +1873,17 @@
       target::ClassTable::shared_class_table_offset();
   const intptr_t table_offset =
       target::SharedClassTable::class_heap_stats_table_offset();
-  const intptr_t state_offset = target::ClassTable::StateOffsetFor(cid);
+  const intptr_t class_offset = target::ClassTable::ClassOffsetFor(cid);
 
   Register temp_reg = TMP;
   LoadIsolate(temp_reg);
   movq(temp_reg, Address(temp_reg, shared_table_offset));
   movq(temp_reg, Address(temp_reg, table_offset));
-  testb(Address(temp_reg, state_offset),
-        Immediate(target::ClassHeapStats::TraceAllocationMask()));
+  cmpb(Address(temp_reg, class_offset), Immediate(0));
   // We are tracing for this class, jump to the trace label which will use
   // the allocation stub.
   j(NOT_ZERO, trace, near_jump);
 }
-
-void Assembler::UpdateAllocationStats(intptr_t cid) {
-  ASSERT(cid > 0);
-  const intptr_t shared_table_offset =
-      target::Isolate::class_table_offset() +
-      target::ClassTable::shared_class_table_offset();
-  const intptr_t table_offset =
-      target::SharedClassTable::class_heap_stats_table_offset();
-  const intptr_t counter_offset =
-      target::ClassTable::NewSpaceCounterOffsetFor(cid);
-
-  Register temp_reg = TMP;
-  LoadIsolate(temp_reg);
-  movq(temp_reg, Address(temp_reg, shared_table_offset));
-  movq(temp_reg, Address(temp_reg, table_offset));
-  incq(Address(temp_reg, counter_offset));
-}
-
-void Assembler::UpdateAllocationStatsWithSize(intptr_t cid, Register size_reg) {
-  ASSERT(cid > 0);
-  ASSERT(cid < kNumPredefinedCids);
-  UpdateAllocationStats(cid);
-  Register temp_reg = TMP;
-  intptr_t size_offset = target::ClassTable::NewSpaceSizeOffsetFor(cid);
-  addq(Address(temp_reg, size_offset), size_reg);
-}
-
-void Assembler::UpdateAllocationStatsWithSize(intptr_t cid,
-                                              intptr_t size_in_bytes) {
-  ASSERT(cid > 0);
-  ASSERT(cid < kNumPredefinedCids);
-  UpdateAllocationStats(cid);
-  Register temp_reg = TMP;
-  intptr_t size_offset = target::ClassTable::NewSpaceSizeOffsetFor(cid);
-  addq(Address(temp_reg, size_offset), Immediate(size_in_bytes));
-}
 #endif  // !PRODUCT
 
 void Assembler::TryAllocate(const Class& cls,
@@ -1945,7 +1908,6 @@
     // Successfully allocated the object, now update top to point to
     // next object start and store the class in the class field of object.
     movq(Address(THR, target::Thread::top_offset()), instance_reg);
-    NOT_IN_PRODUCT(UpdateAllocationStats(cid));
     ASSERT(instance_size >= kHeapObjectTag);
     AddImmediate(instance_reg, Immediate(kHeapObjectTag - instance_size));
     const uint32_t tags =
@@ -1989,7 +1951,6 @@
     // next object start and initialize the object.
     movq(Address(THR, target::Thread::top_offset()), end_address);
     addq(instance, Immediate(kHeapObjectTag));
-    NOT_IN_PRODUCT(UpdateAllocationStatsWithSize(cid, instance_size));
 
     // Initialize the tags.
     // instance: new object start as a tagged pointer.
diff --git a/runtime/vm/compiler/assembler/assembler_x64.h b/runtime/vm/compiler/assembler/assembler_x64.h
index 0c4a5e6..af51403 100644
--- a/runtime/vm/compiler/assembler/assembler_x64.h
+++ b/runtime/vm/compiler/assembler/assembler_x64.h
@@ -894,11 +894,6 @@
   void MonomorphicCheckedEntryAOT();
   void BranchOnMonomorphicCheckedEntryJIT(Label* label);
 
-  void UpdateAllocationStats(intptr_t cid);
-
-  void UpdateAllocationStatsWithSize(intptr_t cid, Register size_reg);
-  void UpdateAllocationStatsWithSize(intptr_t cid, intptr_t instance_size);
-
   // If allocation tracing for |cid| is enabled, will jump to |trace| label,
   // which will allocate in the runtime where tracing occurs.
   void MaybeTraceAllocation(intptr_t cid, Label* trace, bool near_jump);
diff --git a/runtime/vm/compiler/assembler/disassembler.cc b/runtime/vm/compiler/assembler/disassembler.cc
index b74310c..1c68c6d 100644
--- a/runtime/vm/compiler/assembler/disassembler.cc
+++ b/runtime/vm/compiler/assembler/disassembler.cc
@@ -240,12 +240,18 @@
   ASSERT(code.pointer_offsets_length() == 0);
 #endif
 
-  const ObjectPool& object_pool =
-      ObjectPool::Handle(zone, code.GetObjectPool());
-  if (!object_pool.IsNull()) {
-    object_pool.DebugPrint();
+  if (FLAG_use_bare_instructions) {
+    THR_Print("(No object pool for bare instructions.)\n");
+  } else {
+    const ObjectPool& object_pool =
+        ObjectPool::Handle(zone, code.GetObjectPool());
+    if (!object_pool.IsNull()) {
+      object_pool.DebugPrint();
+    }
   }
 
+  code.DumpSourcePositions(/*relative_addresses=*/FLAG_disassemble_relative);
+
   THR_Print("PC Descriptors for function '%s' {\n", function_fullname);
   PcDescriptors::PrintHeaderString();
   const PcDescriptors& descriptors =
@@ -258,23 +264,25 @@
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
   const Array& deopt_table = Array::Handle(zone, code.deopt_info_array());
-  intptr_t deopt_table_length = DeoptTable::GetLength(deopt_table);
-  if (deopt_table_length > 0) {
-    THR_Print("DeoptInfo: {\n");
-    Smi& offset = Smi::Handle(zone);
-    TypedData& info = TypedData::Handle(zone);
-    Smi& reason_and_flags = Smi::Handle(zone);
-    for (intptr_t i = 0; i < deopt_table_length; ++i) {
-      DeoptTable::GetEntry(deopt_table, i, &offset, &info, &reason_and_flags);
-      const intptr_t reason =
-          DeoptTable::ReasonField::decode(reason_and_flags.Value());
-      ASSERT((0 <= reason) && (reason < ICData::kDeoptNumReasons));
-      THR_Print(
-          "%4" Pd ": 0x%" Px "  %s  (%s)\n", i, base + offset.Value(),
-          DeoptInfo::ToCString(deopt_table, info),
-          DeoptReasonToCString(static_cast<ICData::DeoptReasonId>(reason)));
+  if (!deopt_table.IsNull()) {
+    intptr_t deopt_table_length = DeoptTable::GetLength(deopt_table);
+    if (deopt_table_length > 0) {
+      THR_Print("DeoptInfo: {\n");
+      Smi& offset = Smi::Handle(zone);
+      TypedData& info = TypedData::Handle(zone);
+      Smi& reason_and_flags = Smi::Handle(zone);
+      for (intptr_t i = 0; i < deopt_table_length; ++i) {
+        DeoptTable::GetEntry(deopt_table, i, &offset, &info, &reason_and_flags);
+        const intptr_t reason =
+            DeoptTable::ReasonField::decode(reason_and_flags.Value());
+        ASSERT((0 <= reason) && (reason < ICData::kDeoptNumReasons));
+        THR_Print(
+            "%4" Pd ": 0x%" Px "  %s  (%s)\n", i, base + offset.Value(),
+            DeoptInfo::ToCString(deopt_table, info),
+            DeoptReasonToCString(static_cast<ICData::DeoptReasonId>(reason)));
+      }
+      THR_Print("}\n");
     }
-    THR_Print("}\n");
   }
 #endif  // !defined(DART_PRECOMPILED_RUNTIME)
 
@@ -343,6 +351,9 @@
     THR_Print("}\n");
   }
 
+#if defined(DART_PRECOMPILED_RUNTIME)
+  THR_Print("(Cannot show static call target functions in AOT runtime.)\n");
+#else
   {
     THR_Print("Static call target functions {\n");
     const auto& table = Array::Handle(zone, code.static_calls_target_table());
@@ -393,8 +404,9 @@
         }
       }
     }
+    THR_Print("}\n");
   }
-  THR_Print("}\n");
+#endif  // defined(DART_PRECOMPILED_RUNTIME)
 
   if (optimized && FLAG_trace_inlining_intervals) {
     code.DumpInlineIntervals();
@@ -411,6 +423,20 @@
   DisassembleCodeHelper(function_fullname, code, optimized);
 }
 
+void Disassembler::DisassembleStub(const char* name, const Code& code) {
+  LogBlock lb;
+  THR_Print("Code for stub '%s': {\n", name);
+  DisassembleToStdout formatter;
+  code.Disassemble(&formatter);
+  THR_Print("}\n");
+  const ObjectPool& object_pool = ObjectPool::Handle(code.object_pool());
+  if (FLAG_use_bare_instructions) {
+    THR_Print("(No object pool for bare instructions.)\n");
+  } else if (!object_pool.IsNull()) {
+    object_pool.DebugPrint();
+  }
+}
+
 #else   // !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER)
 
 void Disassembler::DisassembleCode(const Function& function,
diff --git a/runtime/vm/compiler/assembler/disassembler.h b/runtime/vm/compiler/assembler/disassembler.h
index e210686..861051d 100644
--- a/runtime/vm/compiler/assembler/disassembler.h
+++ b/runtime/vm/compiler/assembler/disassembler.h
@@ -184,6 +184,8 @@
                               const Code& code,
                               bool optimized);
 
+  static void DisassembleStub(const char* name, const Code& code);
+
  private:
   static void DisassembleCodeHelper(const char* function_fullname,
                                     const Code& code,
diff --git a/runtime/vm/compiler/assembler/disassembler_arm64.cc b/runtime/vm/compiler/assembler/disassembler_arm64.cc
index 7ed5a44..0a75a17 100644
--- a/runtime/vm/compiler/assembler/disassembler_arm64.cc
+++ b/runtime/vm/compiler/assembler/disassembler_arm64.cc
@@ -86,7 +86,7 @@
 static const char* reg_names[kNumberOfCpuRegisters] = {
     "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",  "r8", "r9",  "r10",
     "r11", "r12", "r13", "r14", "r15", "ip0", "ip1", "r18", "sp", "r20", "r21",
-    "r22", "r23", "r24", "r25", "thr", "pp",  "ctx", "fp",  "lr", "r31",
+    "nr",  "r23", "r24", "r25", "thr", "pp",  "ctx", "fp",  "lr", "r31",
 };
 
 // Print the register name according to the active name converter.
diff --git a/runtime/vm/compiler/backend/bce_test.cc b/runtime/vm/compiler/backend/bce_test.cc
index 2bef2ba..44bc798 100644
--- a/runtime/vm/compiler/backend/bce_test.cc
+++ b/runtime/vm/compiler/backend/bce_test.cc
@@ -83,8 +83,7 @@
         return l[0];
       }
       main() {
-        var l = new Float64List(1);
-        foo(l);
+        foo(new Float64List(1));
       }
     )";
   TestScriptJIT(kScriptChars, 1, 1);
@@ -98,14 +97,13 @@
         return l[1] + l[0];
       }
       main() {
-        var l = new Float64List(2);
-        foo(l);
+        foo(new Float64List(2));
       }
     )";
   TestScriptJIT(kScriptChars, 2, 1);
 }
 
-ISOLATE_UNIT_TEST_CASE(BCESimpleLoop) {
+ISOLATE_UNIT_TEST_CASE(BCESimpleLoops) {
   const char* kScriptChars =
       R"(
       import 'dart:typed_data';
@@ -113,13 +111,34 @@
         for (int i = 0; i < l.length; i++) {
           l[i] = 0;
         }
+        for (int i = 10; i <= l.length - 5; i++) {
+          l[i] = 1;
+        }
       }
       main() {
-        var l = new Float64List(100);
-        foo(l);
+        foo(new Float64List(100));
       }
     )";
-  TestScriptJIT(kScriptChars, 1, 0);
+  TestScriptJIT(kScriptChars, 2, 0);
+}
+
+ISOLATE_UNIT_TEST_CASE(BCESimpleLoopsDown) {
+  const char* kScriptChars =
+      R"(
+      import 'dart:typed_data';
+      foo(Float64List l) {
+        for (int i = l.length - 1; i >= 0; i--) {
+          l[i] = 0;
+        }
+        for (int i = l.length - 5; i >= 10; i--) {
+          l[i] = 1;
+        }
+      }
+      main() {
+        foo(new Float64List(100));
+      }
+    )";
+  TestScriptJIT(kScriptChars, 2, 0);
 }
 
 ISOLATE_UNIT_TEST_CASE(BCEModulo) {
@@ -136,6 +155,143 @@
   TestScriptJIT(kScriptChars, 2, 0);
 }
 
-// TODO(ajcbik): add more tests
+ISOLATE_UNIT_TEST_CASE(BCELowerTriangular) {
+  const char* kScriptChars =
+      R"(
+      import 'dart:typed_data';
+      foo(Float64List l) {
+        for (int i = 0; i < l.length; i++) {
+          for (int j = 0; j <= i; j++) {
+            l[i] += l[j];
+          }
+        }
+      }
+      main() {
+        foo(new Float64List(100));
+      }
+    )";
+  TestScriptJIT(kScriptChars, 2, 0);
+}
+
+ISOLATE_UNIT_TEST_CASE(BCEUpperTriangular) {
+  const char* kScriptChars =
+      R"(
+      import 'dart:typed_data';
+      foo(Float64List l) {
+        for (int i = 0; i < l.length; i++) {
+          for (int j = i; j < l.length; j++) {
+            l[i] += l[j];
+          }
+        }
+      }
+      main() {
+        foo(new Float64List(100));
+      }
+    )";
+  TestScriptJIT(kScriptChars, 2, 0);
+}
+
+ISOLATE_UNIT_TEST_CASE(BCETriangularDown) {
+  const char* kScriptChars =
+      R"(
+      import 'dart:typed_data';
+      foo(Float64List l) {
+        for (int i = l.length - 1; i >= 0; i--) {
+          for (int j = i; j >= 0; j--) {
+            l[i] += l[j];
+          }
+        }
+      }
+      main() {
+        foo(new Float64List(100));
+      }
+    )";
+  TestScriptJIT(kScriptChars, 2, 0);
+}
+
+ISOLATE_UNIT_TEST_CASE(BCENamedLength) {
+  const char* kScriptChars =
+      R"(
+      import 'dart:typed_data';
+      Int8List foo(int count) {
+        var x = new Int8List(count);
+        for (int i = 0; i < count; i++) {
+          x[i] = 0;
+        }
+        return x;
+      }
+      main() {
+        foo(100);
+      }
+    )";
+  TestScriptJIT(kScriptChars, 1, 0);
+}
+
+ISOLATE_UNIT_TEST_CASE(BCEBubbleSort) {
+  const char* kScriptChars =
+      R"(
+      import 'dart:typed_data';
+      foo(Float64List a) {
+        int len = a.length;
+        for (int i = len - 2; i >= 0; i--) {
+          for (int j = 0; j <= i; j++) {
+            var c = a[j];
+            var n = a[j + 1];
+            if (c > n) {
+              a[j] = n;
+              a[j + 1] = c;
+            }
+          }
+        }
+      }
+      main() {
+        foo(new Float64List(100));
+      }
+    )";
+  TestScriptJIT(kScriptChars, 2, 0);
+}
+
+ISOLATE_UNIT_TEST_CASE(BCEArithmeticWrapAround) {
+  const char* kScriptChars =
+      R"(
+      import 'dart:typed_data';
+      const kMax = 0x7fffffffffffffff;
+      foo(Float64List a) {
+        for (int i = kMax - 10; i < kMax; i++) {
+          for (int j = i + 10; j < a.length; j++) {
+            // Don't be fooled: j in [-minint, len).
+            a[j] = 1;
+          }
+        }
+      }
+      main() {
+        try {
+          foo(new Float64List(100));
+        }  catch (e) {
+        }
+      }
+    )";
+  TestScriptJIT(kScriptChars, 1, 1);
+}
+
+ISOLATE_UNIT_TEST_CASE(BCEListNamedAndPlainLength) {
+  const char* kScriptChars =
+      R"(
+      List<int> foo(int count) {
+        var x = new List<int>(count);
+        for (int i = 0; i < count; i++) {
+          x[i] = 0;
+        }
+        for (int i = 0; i < x.length; i++) {
+          x[i] = 0;
+        }
+        return x;
+      }
+      main() {
+        foo(100);
+      }
+    )";
+  TestScriptJIT(kScriptChars, 2, 0);
+}
 
 }  // namespace dart
diff --git a/runtime/vm/compiler/backend/constant_propagator.cc b/runtime/vm/compiler/backend/constant_propagator.cc
index 0defd40..5459507 100644
--- a/runtime/vm/compiler/backend/constant_propagator.cc
+++ b/runtime/vm/compiler/backend/constant_propagator.cc
@@ -445,7 +445,7 @@
 }
 
 void ConstantPropagator::VisitStaticCall(StaticCallInstr* instr) {
-  const auto kind = MethodRecognizer::RecognizeKind(instr->function());
+  const auto kind = instr->function().recognized_kind();
   switch (kind) {
     case MethodRecognizer::kOneByteString_equality:
     case MethodRecognizer::kTwoByteString_equality: {
@@ -837,9 +837,9 @@
       const Instance& instance = Instance::Cast(value);
       if (instr->instantiator_type_arguments()->BindsToConstantNull() &&
           instr->function_type_arguments()->BindsToConstantNull()) {
-        bool is_instance =
-            instance.IsInstanceOf(checked_type, Object::null_type_arguments(),
-                                  Object::null_type_arguments());
+        bool is_instance = instance.IsInstanceOf(
+            NNBDMode::kLegacy, checked_type, Object::null_type_arguments(),
+            Object::null_type_arguments());
         SetValue(instr, Bool::Get(is_instance));
         return;
       }
diff --git a/runtime/vm/compiler/backend/flow_graph.cc b/runtime/vm/compiler/backend/flow_graph.cc
index 0c83b55..9f49f44 100644
--- a/runtime/vm/compiler/backend/flow_graph.cc
+++ b/runtime/vm/compiler/backend/flow_graph.cc
@@ -951,8 +951,6 @@
       }
     }
 
-    const intptr_t var_length =
-        IsCompiledForOsr() ? osr_variable_count() : variable_count();
     while (!worklist.is_empty()) {
       BlockEntryInstr* current = worklist.RemoveLast();
       // Ensure a phi for each block in the dominance frontier of current.
@@ -960,10 +958,10 @@
            !it.Done(); it.Advance()) {
         int index = it.Current();
         if (has_already[index] < var_index) {
-          BlockEntryInstr* block = preorder[index];
-          ASSERT(block->IsJoinEntry());
-          PhiInstr* phi =
-              block->AsJoinEntry()->InsertPhi(var_index, var_length);
+          JoinEntryInstr* join = preorder[index]->AsJoinEntry();
+          ASSERT(join != nullptr);
+          PhiInstr* phi = join->InsertPhi(
+              var_index, variable_count() + join->stack_depth());
           if (always_live) {
             phi->mark_alive();
             live_phis->Add(phi);
@@ -971,7 +969,7 @@
           has_already[index] = var_index;
           if (work[index] < var_index) {
             work[index] = var_index;
-            worklist.Add(block);
+            worklist.Add(join);
           }
         }
       }
@@ -984,6 +982,18 @@
   constant_dead_ = GetConstant(Symbols::OptimizedOut());
 }
 
+void FlowGraph::AddSyntheticPhis(BlockEntryInstr* block) {
+  ASSERT(IsCompiledForOsr());
+  if (auto join = block->AsJoinEntry()) {
+    const intptr_t local_phi_count = variable_count() + join->stack_depth();
+    for (intptr_t i = variable_count(); i < local_phi_count; ++i) {
+      if (join->phis() == nullptr || (*join->phis())[i] == nullptr) {
+        join->InsertPhi(i, local_phi_count)->mark_alive();
+      }
+    }
+  }
+}
+
 void FlowGraph::Rename(GrowableArray<PhiInstr*>* live_phis,
                        VariableLivenessAnalysis* variable_liveness,
                        ZoneGrowableArray<Definition*>* inlining_parameters) {
@@ -1007,17 +1017,14 @@
                                                : entry->SuccessorCount() == 1);
   }
 
-  // For OSR on a non-empty stack, insert synthetic phis on the joining entry.
+  // For OSR on a non-empty stack, insert synthetic phis on every joining entry.
   // These phis are synthetic since they are not driven by live variable
   // analysis, but merely serve the purpose of merging stack slots from
   // parameters and other predecessors at the block in which OSR occurred.
   if (IsCompiledForOsr()) {
-    JoinEntryInstr* join =
-        entry->osr_entry()->last_instruction()->SuccessorAt(0)->AsJoinEntry();
-    ASSERT(join != nullptr);
-    const intptr_t parameter_count = osr_variable_count();
-    for (intptr_t i = variable_count(); i < parameter_count; i++) {
-      join->InsertPhi(i, parameter_count)->mark_alive();
+    AddSyntheticPhis(entry->osr_entry()->last_instruction()->SuccessorAt(0));
+    for (intptr_t i = 0, n = entry->dominated_blocks().length(); i < n; ++i) {
+      AddSyntheticPhis(entry->dominated_blocks()[i]);
     }
   }
 
@@ -1168,10 +1175,9 @@
   // 1. Process phis first.
   if (auto join = block_entry->AsJoinEntry()) {
     if (join->phis() != nullptr) {
-      const intptr_t var_length =
-          IsCompiledForOsr() ? osr_variable_count() : variable_count();
-      ASSERT(join->phis()->length() == var_length);
-      for (intptr_t i = 0; i < var_length; ++i) {
+      const intptr_t local_phi_count = variable_count() + join->stack_depth();
+      ASSERT(join->phis()->length() == local_phi_count);
+      for (intptr_t i = 0; i < local_phi_count; ++i) {
         PhiInstr* phi = (*join->phis())[i];
         if (phi != nullptr) {
           (*env)[i] = phi;
diff --git a/runtime/vm/compiler/backend/flow_graph.h b/runtime/vm/compiler/backend/flow_graph.h
index bbba0f1..3622a5c 100644
--- a/runtime/vm/compiler/backend/flow_graph.h
+++ b/runtime/vm/compiler/backend/flow_graph.h
@@ -429,6 +429,8 @@
                     GrowableArray<intptr_t>* parent,
                     GrowableArray<intptr_t>* label);
 
+  void AddSyntheticPhis(BlockEntryInstr* block);
+
   void Rename(GrowableArray<PhiInstr*>* live_phis,
               VariableLivenessAnalysis* variable_liveness,
               ZoneGrowableArray<Definition*>* inlining_parameters);
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.cc b/runtime/vm/compiler/backend/flow_graph_compiler.cc
index e1bce80..68f33f5 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.cc
@@ -60,7 +60,6 @@
             "The scale of invocation count, by size of the function.");
 DEFINE_FLAG(bool, source_lines, false, "Emit source line as assembly comment.");
 
-DECLARE_FLAG(bool, code_comments);
 DECLARE_FLAG(charp, deoptimize_filter);
 DECLARE_FLAG(bool, intrinsify);
 DECLARE_FLAG(int, regexp_optimization_counter_threshold);
@@ -492,6 +491,12 @@
   }
 }
 
+void FlowGraphCompiler::EmitYieldPositionMetadata(TokenPosition token_pos,
+                                                  intptr_t yield_index) {
+  AddDescriptor(RawPcDescriptors::kOther, assembler()->CodeSize(),
+                DeoptId::kNone, token_pos, CurrentTryIndex(), yield_index);
+}
+
 void FlowGraphCompiler::EmitInstructionPrologue(Instruction* instr) {
   if (!is_optimizing()) {
     if (instr->CanBecomeDeoptimizationTarget() && !instr->IsGoto()) {
@@ -732,12 +737,13 @@
                                       intptr_t pc_offset,
                                       intptr_t deopt_id,
                                       TokenPosition token_pos,
-                                      intptr_t try_index) {
+                                      intptr_t try_index,
+                                      intptr_t yield_index) {
   code_source_map_builder_->NoteDescriptor(kind, pc_offset, token_pos);
   // Don't emit deopt-descriptors in AOT mode.
   if (FLAG_precompiled_mode && (kind == RawPcDescriptors::kDeopt)) return;
   pc_descriptors_list_->AddDescriptor(kind, pc_offset, deopt_id, token_pos,
-                                      try_index);
+                                      try_index, yield_index);
 }
 
 // Uses current pc position and try-index.
@@ -1117,12 +1123,14 @@
 
 void FlowGraphCompiler::FinalizeCatchEntryMovesMap(const Code& code) {
 #if defined(DART_PRECOMPILER)
-  TypedData& maps = TypedData::Handle(
-      catch_entry_moves_maps_builder_->FinalizeCatchEntryMovesMap());
-  code.set_catch_entry_moves_maps(maps);
-#else
-  code.set_variables(Smi::Handle(Smi::New(flow_graph().variable_count())));
+  if (FLAG_precompiled_mode) {
+    TypedData& maps = TypedData::Handle(
+        catch_entry_moves_maps_builder_->FinalizeCatchEntryMovesMap());
+    code.set_catch_entry_moves_maps(maps);
+    return;
+  }
 #endif
+  code.set_num_variables(flow_graph().variable_count());
 }
 
 void FlowGraphCompiler::FinalizeStaticCallTargetsTable(const Code& code) {
@@ -2262,7 +2270,7 @@
   // caller side!
   const Type& int_type = Type::Handle(zone(), Type::IntType());
   bool is_non_smi = false;
-  if (int_type.IsSubtypeOf(dst_type, Heap::kOld)) {
+  if (int_type.IsSubtypeOf(NNBDMode::kLegacy, dst_type, Heap::kOld)) {
     __ BranchIfSmi(instance_reg, done);
     is_non_smi = true;
   }
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.h b/runtime/vm/compiler/backend/flow_graph_compiler.h
index 86374da..13c0cfe 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.h
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.h
@@ -681,6 +681,8 @@
                             LocationSummary* locs,
                             Environment* env = nullptr);
 
+  void EmitYieldPositionMetadata(TokenPosition token_pos, intptr_t yield_index);
+
   void EmitComment(Instruction* instr);
 
   // Returns stack size (number of variables on stack for unoptimized
@@ -716,11 +718,13 @@
   void AddCurrentDescriptor(RawPcDescriptors::Kind kind,
                             intptr_t deopt_id,
                             TokenPosition token_pos);
-  void AddDescriptor(RawPcDescriptors::Kind kind,
-                     intptr_t pc_offset,
-                     intptr_t deopt_id,
-                     TokenPosition token_pos,
-                     intptr_t try_index);
+  void AddDescriptor(
+      RawPcDescriptors::Kind kind,
+      intptr_t pc_offset,
+      intptr_t deopt_id,
+      TokenPosition token_pos,
+      intptr_t try_index,
+      intptr_t yield_index = RawPcDescriptors::kInvalidYieldIndex);
 
   void AddNullCheck(intptr_t pc_offset,
                     TokenPosition token_pos,
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc b/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
index 7143db9..c681c1b 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
@@ -278,7 +278,8 @@
   ASSERT(type_class.NumTypeArguments() > 0);
   const Register kInstanceReg = R0;
   const Type& smi_type = Type::Handle(zone(), Type::SmiType());
-  const bool smi_is_ok = smi_type.IsSubtypeOf(type, Heap::kOld);
+  const bool smi_is_ok =
+      smi_type.IsSubtypeOf(NNBDMode::kLegacy, type, Heap::kOld);
   __ tst(kInstanceReg, compiler::Operand(kSmiTagMask));
   if (smi_is_ok) {
     // Fast case for type = FutureOr<int/num/top-type>.
@@ -314,7 +315,7 @@
       ASSERT(tp_argument.HasTypeClass());
       // Check if type argument is dynamic, Object, or void.
       const Type& object_type = Type::Handle(zone(), Type::ObjectType());
-      if (object_type.IsSubtypeOf(tp_argument, Heap::kOld)) {
+      if (object_type.IsSubtypeOf(NNBDMode::kLegacy, tp_argument, Heap::kOld)) {
         // Instance class test only necessary.
         return GenerateSubtype1TestCacheLookup(
             token_pos, type_class, is_instance_lbl, is_not_instance_lbl);
@@ -364,7 +365,8 @@
   __ tst(kInstanceReg, compiler::Operand(kSmiTagMask));
   // If instance is Smi, check directly.
   const Class& smi_class = Class::Handle(zone(), Smi::Class());
-  if (Class::IsSubtypeOf(smi_class, Object::null_type_arguments(), type_class,
+  if (Class::IsSubtypeOf(NNBDMode::kLegacy, smi_class,
+                         Object::null_type_arguments(), type_class,
                          Object::null_type_arguments(), Heap::kOld)) {
     // Fast case for type = int/num/top-type.
     __ b(is_instance_lbl, EQ);
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc b/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
index 980cc1e..f5b6813 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
@@ -269,7 +269,8 @@
   ASSERT(type_class.NumTypeArguments() > 0);
   const Register kInstanceReg = R0;
   const Type& smi_type = Type::Handle(zone(), Type::SmiType());
-  const bool smi_is_ok = smi_type.IsSubtypeOf(type, Heap::kOld);
+  const bool smi_is_ok =
+      smi_type.IsSubtypeOf(NNBDMode::kLegacy, type, Heap::kOld);
   // Fast case for type = FutureOr<int/num/top-type>.
   __ BranchIfSmi(kInstanceReg,
                  smi_is_ok ? is_instance_lbl : is_not_instance_lbl);
@@ -301,7 +302,7 @@
     if (tp_argument.IsType()) {
       // Check if type argument is dynamic, Object, or void.
       const Type& object_type = Type::Handle(zone(), Type::ObjectType());
-      if (object_type.IsSubtypeOf(tp_argument, Heap::kOld)) {
+      if (object_type.IsSubtypeOf(NNBDMode::kLegacy, tp_argument, Heap::kOld)) {
         // Instance class test only necessary.
         return GenerateSubtype1TestCacheLookup(
             token_pos, type_class, is_instance_lbl, is_not_instance_lbl);
@@ -349,7 +350,8 @@
   const Register kInstanceReg = R0;
   // If instance is Smi, check directly.
   const Class& smi_class = Class::Handle(zone(), Smi::Class());
-  if (Class::IsSubtypeOf(smi_class, Object::null_type_arguments(), type_class,
+  if (Class::IsSubtypeOf(NNBDMode::kLegacy, smi_class,
+                         Object::null_type_arguments(), type_class,
                          Object::null_type_arguments(), Heap::kOld)) {
     // Fast case for type = int/num/top-type.
     __ BranchIfSmi(kInstanceReg, is_instance_lbl);
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc b/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
index b73de08..ff849d8 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_ia32.cc
@@ -258,7 +258,8 @@
   ASSERT(type_class.NumTypeArguments() > 0);
   const Register kInstanceReg = EAX;
   const Type& smi_type = Type::Handle(zone(), Type::SmiType());
-  const bool smi_is_ok = smi_type.IsSubtypeOf(type, Heap::kOld);
+  const bool smi_is_ok =
+      smi_type.IsSubtypeOf(NNBDMode::kLegacy, type, Heap::kOld);
   __ testl(kInstanceReg, compiler::Immediate(kSmiTagMask));
   if (smi_is_ok) {
     // Fast case for type = FutureOr<int/num/top-type>.
@@ -293,7 +294,7 @@
     if (tp_argument.IsType()) {
       // Check if type argument is dynamic, Object, or void.
       const Type& object_type = Type::Handle(zone(), Type::ObjectType());
-      if (object_type.IsSubtypeOf(tp_argument, Heap::kOld)) {
+      if (object_type.IsSubtypeOf(NNBDMode::kLegacy, tp_argument, Heap::kOld)) {
         // Instance class test only necessary.
         return GenerateSubtype1TestCacheLookup(
             token_pos, type_class, is_instance_lbl, is_not_instance_lbl);
@@ -341,7 +342,8 @@
   __ testl(kInstanceReg, compiler::Immediate(kSmiTagMask));
   // If instance is Smi, check directly.
   const Class& smi_class = Class::Handle(zone(), Smi::Class());
-  if (Class::IsSubtypeOf(smi_class, Object::null_type_arguments(), type_class,
+  if (Class::IsSubtypeOf(NNBDMode::kLegacy, smi_class,
+                         Object::null_type_arguments(), type_class,
                          Object::null_type_arguments(), Heap::kOld)) {
     // Fast case for type = int/num/top-type.
     __ j(ZERO, is_instance_lbl);
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc b/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
index 59af52e..1937d593 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
@@ -274,7 +274,8 @@
   ASSERT(type_class.NumTypeArguments() > 0);
   const Register kInstanceReg = RAX;
   const Type& smi_type = Type::Handle(zone(), Type::SmiType());
-  const bool smi_is_ok = smi_type.IsSubtypeOf(type, Heap::kOld);
+  const bool smi_is_ok =
+      smi_type.IsSubtypeOf(NNBDMode::kLegacy, type, Heap::kOld);
   __ testq(kInstanceReg, compiler::Immediate(kSmiTagMask));
   if (smi_is_ok) {
     // Fast case for type = FutureOr<int/num/top-type>.
@@ -311,7 +312,7 @@
       ASSERT(tp_argument.HasTypeClass());
       // Check if type argument is dynamic, Object, or void.
       const Type& object_type = Type::Handle(zone(), Type::ObjectType());
-      if (object_type.IsSubtypeOf(tp_argument, Heap::kOld)) {
+      if (object_type.IsSubtypeOf(NNBDMode::kLegacy, tp_argument, Heap::kOld)) {
         // Instance class test only necessary.
         return GenerateSubtype1TestCacheLookup(
             token_pos, type_class, is_instance_lbl, is_not_instance_lbl);
@@ -364,7 +365,8 @@
   __ testq(kInstanceReg, compiler::Immediate(kSmiTagMask));
   // If instance is Smi, check directly.
   const Class& smi_class = Class::Handle(zone(), Smi::Class());
-  if (Class::IsSubtypeOf(smi_class, Object::null_type_arguments(), type_class,
+  if (Class::IsSubtypeOf(NNBDMode::kLegacy, smi_class,
+                         Object::null_type_arguments(), type_class,
                          Object::null_type_arguments(), Heap::kOld)) {
     // Fast case for type = int/num/top-type.
     __ j(ZERO, is_instance_lbl);
diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc
index 35c221b..06000ae 100644
--- a/runtime/vm/compiler/backend/il.cc
+++ b/runtime/vm/compiler/backend/il.cc
@@ -218,7 +218,8 @@
       test_succeeded = false;
     } else if (use_subtype_test) {
       cls_type = cls.RareType();
-      test_succeeded = cls_type.IsSubtypeOf(dst_type, Heap::kNew);
+      test_succeeded =
+          cls_type.IsSubtypeOf(NNBDMode::kLegacy, dst_type, Heap::kNew);
     } else {
       while (!cls.IsObjectClass()) {
         if (cls.raw() == klass.raw()) {
@@ -542,6 +543,16 @@
   }
 }
 
+bool Definition::IsArrayLength(Definition* def) {
+  if (def != nullptr) {
+    if (auto load = def->OriginalDefinitionIgnoreBoxingAndConstraints()
+                        ->AsLoadField()) {
+      return load->IsImmutableLengthLoad();
+    }
+  }
+  return false;
+}
+
 const ICData* Instruction::GetICData(
     const ZoneGrowableArray<const ICData*>& ic_data_array) const {
   // The deopt_id can be outside the range of the IC data array for
@@ -1004,9 +1015,9 @@
 
     AbstractType& sub_type = AbstractType::Handle(Z, sub_type_.raw());
     AbstractType& super_type = AbstractType::Handle(Z, super_type_.raw());
-    if (AbstractType::InstantiateAndTestSubtype(&sub_type, &super_type,
-                                                instantiator_type_args,
-                                                function_type_args)) {
+    if (AbstractType::InstantiateAndTestSubtype(
+            NNBDMode::kLegacy, &sub_type, &super_type, instantiator_type_args,
+            function_type_args)) {
       return NULL;
     }
   }
@@ -2645,7 +2656,7 @@
 }
 
 bool LoadFieldInstr::IsTypedDataViewFactory(const Function& function) {
-  auto kind = MethodRecognizer::RecognizeKind(function);
+  auto kind = function.recognized_kind();
   switch (kind) {
     case MethodRecognizer::kTypedData_ByteDataView_factory:
     case MethodRecognizer::kTypedData_Int8ArrayView_factory:
@@ -2930,9 +2941,9 @@
 
   if ((instantiator_type_args != nullptr) && (function_type_args != nullptr)) {
     AbstractType& new_dst_type = AbstractType::Handle(
-        Z,
-        dst_type().InstantiateFrom(*instantiator_type_args, *function_type_args,
-                                   kAllFree, nullptr, Heap::kOld));
+        Z, dst_type().InstantiateFrom(
+               NNBDMode::kLegacy, *instantiator_type_args, *function_type_args,
+               kAllFree, nullptr, Heap::kOld));
     if (new_dst_type.IsNull()) {
       // Failed instantiation in dead code.
       return this;
@@ -3242,7 +3253,8 @@
   }
   // Note that type 'Number' is a subtype of itself.
   return compile_type.IsTopType() || compile_type.IsTypeParameter() ||
-         compile_type.IsSubtypeOf(Type::Handle(Type::Number()), Heap::kOld);
+         compile_type.IsSubtypeOf(NNBDMode::kLegacy,
+                                  Type::Handle(Type::Number()), Heap::kOld);
 }
 
 // Returns a replacement for a strict comparison and signals if the result has
@@ -3734,7 +3746,7 @@
     int lower_limit_cid = (idx == 0) ? -1 : targets[idx - 1].cid_end;
     auto target_info = targets.TargetAt(idx);
     const Function& target = *target_info->target;
-    if (MethodRecognizer::PolymorphicTarget(target)) continue;
+    if (target.is_polymorphic_target()) continue;
     for (int i = target_info->cid_start - 1; i > lower_limit_cid; i--) {
       bool class_is_abstract = false;
       if (FlowGraphCompiler::LookupMethodFor(i, name, args_desc, &fn,
@@ -3758,7 +3770,7 @@
         (idx == length - 1) ? max_cid : targets[idx + 1].cid_start;
     auto target_info = targets.TargetAt(idx);
     const Function& target = *target_info->target;
-    if (MethodRecognizer::PolymorphicTarget(target)) continue;
+    if (target.is_polymorphic_target()) continue;
     // The code below makes attempt to avoid spreading class-id range
     // into a suffix that consists purely of abstract classes to
     // shorten the range.
@@ -3809,7 +3821,7 @@
     const Function& target = *TargetAt(dest)->target;
     if (TargetAt(dest)->cid_end + 1 >= TargetAt(src)->cid_start &&
         target.raw() == TargetAt(src)->target->raw() &&
-        !MethodRecognizer::PolymorphicTarget(target)) {
+        !target.is_polymorphic_target()) {
       TargetAt(dest)->cid_end = TargetAt(src)->cid_end;
       TargetAt(dest)->count += TargetAt(src)->count;
       TargetAt(dest)->exactness = StaticTypeExactnessState::NotTracking();
@@ -4384,8 +4396,7 @@
 
 bool CallTargets::HasSingleRecognizedTarget() const {
   if (!HasSingleTarget()) return false;
-  return MethodRecognizer::RecognizeKind(FirstTarget()) !=
-         MethodRecognizer::kUnknown;
+  return FirstTarget().recognized_kind() != MethodRecognizer::kUnknown;
 }
 
 bool CallTargets::HasSingleTarget() const {
diff --git a/runtime/vm/compiler/backend/il.h b/runtime/vm/compiler/backend/il.h
index fc95490..b2d8e7c 100644
--- a/runtime/vm/compiler/backend/il.h
+++ b/runtime/vm/compiler/backend/il.h
@@ -2225,6 +2225,9 @@
   // boxing/unboxing and constraint instructions.
   Definition* OriginalDefinitionIgnoreBoxingAndConstraints();
 
+  // Helper method to determine if definition denotes an array length.
+  static bool IsArrayLength(Definition* def);
+
   virtual Definition* AsDefinition() { return this; }
   virtual const Definition* AsDefinition() const { return this; }
 
@@ -2677,8 +2680,15 @@
 
 class ReturnInstr : public TemplateInstruction<1, NoThrow> {
  public:
-  ReturnInstr(TokenPosition token_pos, Value* value, intptr_t deopt_id)
-      : TemplateInstruction(deopt_id), token_pos_(token_pos) {
+  // The [yield_index], if provided, will cause the instruction to emit extra
+  // yield_index -> pc offset into the [PcDescriptors].
+  ReturnInstr(TokenPosition token_pos,
+              Value* value,
+              intptr_t deopt_id,
+              intptr_t yield_index = RawPcDescriptors::kInvalidYieldIndex)
+      : TemplateInstruction(deopt_id),
+        token_pos_(token_pos),
+        yield_index_(yield_index) {
     SetInputAt(0, value);
   }
 
@@ -2686,6 +2696,7 @@
 
   virtual TokenPosition token_pos() const { return token_pos_; }
   Value* value() const { return inputs_[0]; }
+  intptr_t yield_index() const { return yield_index_; }
 
   virtual bool CanBecomeDeoptimizationTarget() const {
     // Return instruction might turn into a Goto instruction after inlining.
@@ -2697,8 +2708,17 @@
 
   virtual bool HasUnknownSideEffects() const { return false; }
 
+  virtual bool AttributesEqual(Instruction* other) const {
+    auto other_return = other->AsReturn();
+    return token_pos() == other_return->token_pos() &&
+           yield_index() == other_return->yield_index();
+  }
+
+  PRINT_OPERANDS_TO_SUPPORT
+
  private:
   const TokenPosition token_pos_;
+  const intptr_t yield_index_;
 
   DISALLOW_COPY_AND_ASSIGN(ReturnInstr);
 };
@@ -7899,7 +7919,7 @@
 
   // Returns true if the bounds check can be eliminated without
   // changing the semantics (viz. 0 <= index < length).
-  bool IsRedundant();
+  bool IsRedundant(bool use_loops = false);
 
   // Give a name to the location/input indices.
   enum { kLengthPos = 0, kIndexPos = 1 };
diff --git a/runtime/vm/compiler/backend/il_arm.cc b/runtime/vm/compiler/backend/il_arm.cc
index 9515797..a21248b 100644
--- a/runtime/vm/compiler/backend/il_arm.cc
+++ b/runtime/vm/compiler/backend/il_arm.cc
@@ -139,6 +139,9 @@
   __ Bind(&stack_ok);
 #endif
   ASSERT(__ constant_pool_allowed());
+  if (yield_index() != RawPcDescriptors::kInvalidYieldIndex) {
+    compiler->EmitYieldPositionMetadata(token_pos(), yield_index());
+  }
   __ LeaveDartFrameAndReturn();  // Disallows constant pool use.
   // This ReturnInstr may be emitted out of order by the optimizer. The next
   // block may be a target expecting a properly set constant pool pointer.
@@ -963,19 +966,9 @@
     entry = reinterpret_cast<uword>(native_c_function());
     if (is_bootstrap_native()) {
       stub = &StubCode::CallBootstrapNative();
-#if defined(USING_SIMULATOR)
-      entry = Simulator::RedirectExternalReference(
-          entry, Simulator::kBootstrapNativeCall, NativeEntry::kNumArguments);
-#endif
     } else if (is_auto_scope()) {
-      // In the case of non bootstrap native methods the CallNativeCFunction
-      // stub generates the redirection address when running under the simulator
-      // and hence we do not change 'entry' here.
       stub = &StubCode::CallAutoScopeNative();
     } else {
-      // In the case of non bootstrap native methods the CallNativeCFunction
-      // stub generates the redirection address when running under the simulator
-      // and hence we do not change 'entry' here.
       stub = &StubCode::CallNoScopeNative();
     }
   }
diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc
index b83bf31..5f4adbd 100644
--- a/runtime/vm/compiler/backend/il_arm64.cc
+++ b/runtime/vm/compiler/backend/il_arm64.cc
@@ -138,6 +138,9 @@
   __ Bind(&stack_ok);
 #endif
   ASSERT(__ constant_pool_allowed());
+  if (yield_index() != RawPcDescriptors::kInvalidYieldIndex) {
+    compiler->EmitYieldPositionMetadata(token_pos(), yield_index());
+  }
   __ LeaveDartFrame();  // Disallows constant pool use.
   __ ret();
   // This ReturnInstr may be emitted out of order by the optimizer. The next
@@ -842,19 +845,9 @@
     entry = reinterpret_cast<uword>(native_c_function());
     if (is_bootstrap_native()) {
       stub = &StubCode::CallBootstrapNative();
-#if defined(USING_SIMULATOR)
-      entry = Simulator::RedirectExternalReference(
-          entry, Simulator::kBootstrapNativeCall, NativeEntry::kNumArguments);
-#endif
     } else if (is_auto_scope()) {
-      // In the case of non bootstrap native methods the CallNativeCFunction
-      // stub generates the redirection address when running under the simulator
-      // and hence we do not change 'entry' here.
       stub = &StubCode::CallAutoScopeNative();
     } else {
-      // In the case of non bootstrap native methods the CallNativeCFunction
-      // stub generates the redirection address when running under the simulator
-      // and hence we do not change 'entry' here.
       stub = &StubCode::CallNoScopeNative();
     }
   }
@@ -947,10 +940,8 @@
     __ blr(TMP);
   }
 
-  // Refresh write barrier mask.
-  __ ldr(BARRIER_MASK,
-         compiler::Address(
-             THR, compiler::target::Thread::write_barrier_mask_offset()));
+  // Refresh pinned registers values (inc. write barrier mask and null object).
+  __ RestorePinnedRegisters();
 
   // Although PP is a callee-saved register, it may have been moved by the GC.
   __ LeaveDartFrame(compiler::kRestoreCallerPP);
@@ -1109,10 +1100,8 @@
   // Now that we have THR, we can set CSP.
   __ SetupCSPFromThread(THR);
 
-  // Refresh write barrier mask.
-  __ ldr(BARRIER_MASK,
-         compiler::Address(
-             THR, compiler::target::Thread::write_barrier_mask_offset()));
+  // Refresh pinned registers values (inc. write barrier mask and null object).
+  __ RestorePinnedRegisters();
 
   // Save the current VMTag on the stack.
   __ LoadFromOffset(R0, THR, compiler::target::Thread::vm_tag_offset());
diff --git a/runtime/vm/compiler/backend/il_deserializer.cc b/runtime/vm/compiler/backend/il_deserializer.cc
index 47d515a..c035dd6 100644
--- a/runtime/vm/compiler/backend/il_deserializer.cc
+++ b/runtime/vm/compiler/backend/il_deserializer.cc
@@ -1848,7 +1848,9 @@
   }
   // Guaranteed not to re-enter ParseType.
   if (!ParseClass(cls_sexp, &type_class_)) return false;
-  *out = Type::New(type_class_, *type_args_ptr, token_pos, Heap::kOld);
+  const Nullability nullability =
+      type_class_.IsNullClass() ? Nullability::kNullable : Nullability::kLegacy;
+  *out = Type::New(type_class_, *type_args_ptr, token_pos, nullability);
   auto& type = Type::Cast(*out);
   if (auto const sig_sexp = list->ExtraLookupValue("signature")) {
     auto& function = Function::Handle(zone());
diff --git a/runtime/vm/compiler/backend/il_ia32.cc b/runtime/vm/compiler/backend/il_ia32.cc
index 7af91ad..43cc2c5 100644
--- a/runtime/vm/compiler/backend/il_ia32.cc
+++ b/runtime/vm/compiler/backend/il_ia32.cc
@@ -133,6 +133,9 @@
   __ int3();
   __ Bind(&done);
 #endif
+  if (yield_index() != RawPcDescriptors::kInvalidYieldIndex) {
+    compiler->EmitYieldPositionMetadata(token_pos(), yield_index());
+  }
   __ LeaveFrame();
   __ ret();
 }
diff --git a/runtime/vm/compiler/backend/il_printer.cc b/runtime/vm/compiler/backend/il_printer.cc
index 527cc9e..e2153dc 100644
--- a/runtime/vm/compiler/backend/il_printer.cc
+++ b/runtime/vm/compiler/backend/il_printer.cc
@@ -2,8 +2,6 @@
 // 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.
 
-#if !defined(DART_PRECOMPILED_RUNTIME)
-
 #include "vm/compiler/backend/il_printer.h"
 
 #include "vm/compiler/backend/il.h"
@@ -15,18 +13,11 @@
 
 #if !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER)
 
-DEFINE_FLAG(bool,
-            display_sorted_ic_data,
-            false,
-            "Calls display a unary, sorted-by count form of ICData");
-DEFINE_FLAG(bool, print_environments, false, "Print SSA environments.");
 DEFINE_FLAG(charp,
             print_flow_graph_filter,
             NULL,
             "Print only IR of functions with matching names");
 
-DECLARE_FLAG(bool, trace_inlining_intervals);
-
 // Checks whether function's name matches the given filter, which is
 // a comma-separated list of strings.
 bool FlowGraphPrinter::PassesFilter(const char* filter,
@@ -74,6 +65,16 @@
   return PassesFilter(FLAG_print_flow_graph_filter, function);
 }
 
+#if !defined(DART_PRECOMPILED_RUNTIME)
+
+DEFINE_FLAG(bool,
+            display_sorted_ic_data,
+            false,
+            "Calls display a unary, sorted-by count form of ICData");
+DEFINE_FLAG(bool, print_environments, false, "Print SSA environments.");
+
+DECLARE_FLAG(bool, trace_inlining_intervals);
+
 void FlowGraphPrinter::PrintGraph(const char* phase, FlowGraph* flow_graph) {
   LogBlock lb;
   THR_Print("*** BEGIN CFG\n%s\n", phase);
@@ -1060,6 +1061,13 @@
   BlockEntryWithInitialDefs::PrintInitialDefinitionsTo(f);
 }
 
+void ReturnInstr::PrintOperandsTo(BufferFormatter* f) const {
+  Instruction::PrintOperandsTo(f);
+  if (yield_index() != RawPcDescriptors::kInvalidYieldIndex) {
+    f->Print(", yield_index = %" Pd "", yield_index());
+  }
+}
+
 void NativeReturnInstr::PrintOperandsTo(BufferFormatter* f) const {
   value()->PrintTo(f);
 }
@@ -1181,8 +1189,12 @@
   return Thread::Current()->zone()->MakeCopyOfString(buffer);
 }
 
+#endif  // !defined(DART_PRECOMPILED_RUNTIME)
+
 #else  // !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER)
 
+#if !defined(DART_PRECOMPILED_RUNTIME)
+
 const char* Instruction::ToCString() const {
   return DebugName();
 }
@@ -1219,8 +1231,8 @@
   return false;
 }
 
+#endif  // !defined(DART_PRECOMPILED_RUNTIME)
+
 #endif  // !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER)
 
 }  // namespace dart
-
-#endif  // !defined(DART_PRECOMPILED_RUNTIME)
diff --git a/runtime/vm/compiler/backend/il_x64.cc b/runtime/vm/compiler/backend/il_x64.cc
index b736c05..a0b64fb 100644
--- a/runtime/vm/compiler/backend/il_x64.cc
+++ b/runtime/vm/compiler/backend/il_x64.cc
@@ -134,6 +134,9 @@
   __ Bind(&done);
 #endif
   ASSERT(__ constant_pool_allowed());
+  if (yield_index() != RawPcDescriptors::kInvalidYieldIndex) {
+    compiler->EmitYieldPositionMetadata(token_pos(), yield_index());
+  }
   __ LeaveDartFrame();  // Disallows constant pool use.
   __ ret();
   // This ReturnInstr may be emitted out of order by the optimizer. The next
diff --git a/runtime/vm/compiler/backend/inliner.cc b/runtime/vm/compiler/backend/inliner.cc
index 52e3cac..d06b9a1 100644
--- a/runtime/vm/compiler/backend/inliner.cc
+++ b/runtime/vm/compiler/backend/inliner.cc
@@ -1673,7 +1673,7 @@
 bool PolymorphicInliner::CheckInlinedDuplicate(const Function& target) {
   for (intptr_t i = 0; i < inlined_variants_.length(); ++i) {
     if ((target.raw() == inlined_variants_.TargetAt(i)->target->raw()) &&
-        !MethodRecognizer::PolymorphicTarget(target)) {
+        !target.is_polymorphic_target()) {
       // The call target is shared with a previous inlined variant.  Share
       // the graph.  This requires a join block at the entry, and edge-split
       // form requires a target for each branch.
@@ -1805,8 +1805,7 @@
     // The empty Object constructor is the only case where the inlined body is
     // empty and there is no result.
     ASSERT((last != nullptr && result != nullptr) ||
-           MethodRecognizer::RecognizeKind(target) ==
-               MethodRecognizer::kObjectConstructor);
+           (target.recognized_kind() == MethodRecognizer::kObjectConstructor));
     graph_entry->set_normal_entry(entry);
     // Create a graph fragment.
     redefinition->InsertAfter(entry);
@@ -3321,11 +3320,10 @@
     // The empty Object constructor is the only case where the inlined body is
     // empty and there is no result.
     ASSERT((last != nullptr && result != nullptr) ||
-           MethodRecognizer::RecognizeKind(target) ==
-               MethodRecognizer::kObjectConstructor);
+           (target.recognized_kind() == MethodRecognizer::kObjectConstructor));
     // Determine if inlining instance methods needs a check.
     FlowGraph::ToCheck check = FlowGraph::ToCheck::kNoCheck;
-    if (MethodRecognizer::PolymorphicTarget(target)) {
+    if (target.is_polymorphic_target()) {
       check = FlowGraph::ToCheck::kCheckCid;
     } else {
       check = flow_graph->CheckForInstanceCall(call, target.kind());
@@ -3409,8 +3407,8 @@
     // The empty Object constructor is the only case where the inlined body is
     // empty and there is no result.
     ASSERT((last != nullptr && result != nullptr) ||
-           MethodRecognizer::RecognizeKind(call->function()) ==
-               MethodRecognizer::kObjectConstructor);
+           (call->function().recognized_kind() ==
+            MethodRecognizer::kObjectConstructor));
     // Remove the original push arguments.
     for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
       PushArgumentInstr* push = call->PushArgumentAt(i);
@@ -3687,7 +3685,7 @@
     FlowGraphInliner::ExactnessInfo* exactness) {
   const bool can_speculate = policy->IsAllowedForInlining(call->deopt_id());
 
-  const MethodRecognizer::Kind kind = MethodRecognizer::RecognizeKind(target);
+  const MethodRecognizer::Kind kind = target.recognized_kind();
   switch (kind) {
     // Recognized [] operators.
     case MethodRecognizer::kImmutableArrayGetIndexed:
diff --git a/runtime/vm/compiler/backend/loops.cc b/runtime/vm/compiler/backend/loops.cc
index 8c046a6..b8edbc0 100644
--- a/runtime/vm/compiler/backend/loops.cc
+++ b/runtime/vm/compiler/backend/loops.cc
@@ -69,6 +69,7 @@
   // Transfer methods. Compute how induction of the operands, if any,
   // tranfers over the operation performed by the given definition.
   InductionVar* TransferPhi(LoopInfo* loop, Definition* def, intptr_t idx = -1);
+  InductionVar* TransferDef(LoopInfo* loop, Definition* def);
   InductionVar* TransferBinary(LoopInfo* loop, Definition* def);
   InductionVar* TransferUnary(LoopInfo* loop, Definition* def);
 
@@ -132,6 +133,81 @@
   return false;
 }
 
+// Helper method to determine if a non-strict (inclusive) bound on
+// a unit stride linear induction can be made strict (exclusive)
+// without arithmetic wrap-around complications.
+static bool CanBeMadeExclusive(LoopInfo* loop,
+                               InductionVar* x,
+                               Instruction* branch,
+                               bool is_lower) {
+  InductionVar* min = nullptr;
+  InductionVar* max = nullptr;
+  if (x->CanComputeBounds(loop, branch, &min, &max)) {
+    int64_t end = 0;
+    if (is_lower) {
+      if (InductionVar::IsConstant(min, &end)) {
+        return kMinInt64 < end;
+      }
+    } else if (InductionVar::IsConstant(max, &end)) {
+      return end < kMaxInt64;
+    } else if (InductionVar::IsInvariant(max) && max->mult() == 1 &&
+               Definition::IsArrayLength(max->def())) {
+      return max->offset() < 0;  // a.length - C, C > 0
+    }
+  }
+  return false;
+}
+
+// Helper method to adjust a range [lower_bound,upper_bound] into the
+// range [lower_bound+lower_bound_offset,upper_bound+upper_bound+offset]
+// without arithmetic wrap-around complications. On entry, we know that
+// lower_bound <= upper_bound is enforced by an actual comparison in the
+// code (so that even if lower_bound > upper_bound, the loop is not taken).
+// This method ensures the resulting range has the same property by
+// very conservatively testing if everything stays between constants
+// or a properly offset array length.
+static bool SafelyAdjust(Zone* zone,
+                         InductionVar* lower_bound,
+                         int64_t lower_bound_offset,
+                         InductionVar* upper_bound,
+                         int64_t upper_bound_offset,
+                         InductionVar** min,
+                         InductionVar** max) {
+  bool success = false;
+  int64_t lval = 0;
+  int64_t uval = 0;
+  if (InductionVar::IsConstant(lower_bound, &lval)) {
+    const int64_t l = lval + lower_bound_offset;
+    if (InductionVar::IsConstant(upper_bound, &uval)) {
+      // Make sure a proper new range [l,u] results. Even if bounds
+      // were subject to arithmetic wrap-around, we preserve the
+      // property that the minimum is in l and the maximum in u.
+      const int64_t u = uval + upper_bound_offset;
+      success = (l <= u);
+    } else if (InductionVar::IsInvariant(upper_bound) &&
+               upper_bound->mult() == 1 &&
+               Definition::IsArrayLength(upper_bound->def())) {
+      // No arithmetic wrap-around on the lower bound, and a properly
+      // non-positive offset on an array length, which is always >= 0.
+      const int64_t c = upper_bound->offset() + upper_bound_offset;
+      success = ((lower_bound_offset >= 0 && lval <= l) ||
+                 (lower_bound_offset < 0 && lval > l)) &&
+                (c <= 0);
+    }
+  }
+  if (success) {
+    *min = (lower_bound_offset == 0)
+               ? lower_bound
+               : new (zone) InductionVar(lval + lower_bound_offset);
+    *max = (upper_bound_offset == 0)
+               ? upper_bound
+               : new (zone)
+                     InductionVar(upper_bound->offset() + upper_bound_offset,
+                                  upper_bound->mult(), upper_bound->def());
+  }
+  return success;
+}
+
 void InductionVarAnalysis::VisitHierarchy(LoopInfo* loop) {
   for (; loop != nullptr; loop = loop->next_) {
     VisitLoop(loop);
@@ -252,15 +328,8 @@
     }
   } else if (def->IsPhi()) {
     induc = TransferPhi(loop, def);
-  } else if (def->IsBinaryIntegerOp()) {
-    induc = TransferBinary(loop, def);
-  } else if (def->IsUnaryIntegerOp()) {
-    induc = TransferUnary(loop, def);
   } else {
-    Definition* orig = def->OriginalDefinitionIgnoreBoxingAndConstraints();
-    if (orig != def) {
-      induc = Lookup(loop, orig);  // pass-through
-    }
+    induc = TransferDef(loop, def);
   }
   // Successfully classified?
   if (induc != nullptr) {
@@ -373,15 +442,12 @@
     } else {
       continue;
     }
-    // Safe, strict comparison for looping condition? Note that
-    // we reject symbolic bounds in non-strict looping conditions
-    // like i <= U as upperbound or i >= L as lowerbound since this
-    // could loop forever when U is kMaxInt64 or L is kMinInt64 under
-    // Dart's 64-bit wrap-around arithmetic. Non-unit strides could
-    // overshoot the bound with a wrap-around.
-    //
-    // TODO(ajcbik): accept more conditions when safe
-    //
+    // Can we find a strict (exclusive) comparison for the looping condition?
+    // Note that we reject symbolic bounds in non-strict (inclusive) looping
+    // conditions like i <= U as upperbound or i >= L as lowerbound since this
+    // could loop forever when U is kMaxInt64 or L is kMinInt64 under Dart's
+    // 64-bit arithmetic wrap-around. Non-unit strides could overshoot the
+    // bound due to aritmetic wrap-around.
     switch (cmp) {
       case Token::kLT:
         // Accept i < U (i++).
@@ -392,21 +458,21 @@
         if (stride == -1) break;
         continue;
       case Token::kLTE: {
-        // Accept i <= C (i++) as i < C + 1.
-        int64_t end = 0;
-        if (stride == 1 && InductionVar::IsConstant(y, &end) &&
-            end < kMaxInt64) {
-          y = new (zone_) InductionVar(end + 1);
+        // Accept i <= U (i++) as i < U + 1
+        // only when U != MaxInt is certain.
+        if (stride == 1 &&
+            CanBeMadeExclusive(loop, y, branch, /*is_lower=*/false)) {
+          y = Add(y, new (zone_) InductionVar(1));
           break;
         }
         continue;
       }
       case Token::kGTE: {
-        // Accept i >= C (i--) as i > C - 1.
-        int64_t end = 0;
-        if (stride == -1 && InductionVar::IsConstant(y, &end) &&
-            kMinInt64 < end) {
-          y = new (zone_) InductionVar(end - 1);
+        // Accept i >= L (i--) as i > L - 1
+        // only when L != MinInt is certain.
+        if (stride == -1 &&
+            CanBeMadeExclusive(loop, y, branch, /*is_lower=*/true)) {
+          y = Sub(y, new (zone_) InductionVar(1));
           break;
         }
         continue;
@@ -427,9 +493,10 @@
       default:
         continue;
     }
-    // We found a safe limit on the induction variable. Note that depending
-    // on the intended use of this information, clients should still test
-    // dominance on the test and the initial value of the induction variable.
+    // We found a strict upper or lower bound on a unit stride linear
+    // induction. Note that depending on the intended use of this
+    // information, clients should still test dominance on the test
+    // and the initial value of the induction variable.
     x->bounds_.Add(InductionVar::Bound(branch, y));
     // Record control induction.
     if (branch == loop->header_->last_instruction()) {
@@ -457,6 +524,33 @@
   return induc;
 }
 
+InductionVar* InductionVarAnalysis::TransferDef(LoopInfo* loop,
+                                                Definition* def) {
+  if (def->IsBinaryIntegerOp()) {
+    return TransferBinary(loop, def);
+  } else if (def->IsUnaryIntegerOp()) {
+    return TransferUnary(loop, def);
+  } else {
+    // Note that induction analysis does not really need the second
+    // argument of a bound check, since it will just pass-through the
+    // index. However, we do a lookup on the, most likely loop-invariant,
+    // length anyway, to make sure it is stored in the induction
+    // environment for later lookup during BCE.
+    if (auto check = def->AsCheckBoundBase()) {
+      Definition* len = check->length()
+                            ->definition()
+                            ->OriginalDefinitionIgnoreBoxingAndConstraints();
+      Lookup(loop, len);  // pre-store likely invariant length
+    }
+    // Proceed with regular pass-through.
+    Definition* orig = def->OriginalDefinitionIgnoreBoxingAndConstraints();
+    if (orig != def) {
+      return Lookup(loop, orig);  // pass-through
+    }
+  }
+  return nullptr;
+}
+
 InductionVar* InductionVarAnalysis::TransferBinary(LoopInfo* loop,
                                                    Definition* def) {
   InductionVar* x = Lookup(loop, def->InputAt(0)->definition());
@@ -605,7 +699,12 @@
       induc = new (zone_) InductionVar(val);
       loop->AddInduction(def, induc);
     } else if (!loop->Contains(def->GetBlock())) {
-      induc = new (zone_) InductionVar(0, 1, def);
+      // Look "under the hood" of invariant definitions to expose
+      // more details on common constructs like "length - 1".
+      induc = TransferDef(loop, def);
+      if (induc == nullptr) {
+        induc = new (zone_) InductionVar(0, 1, def);
+      }
       loop->AddInduction(def, induc);
     }
   }
@@ -734,6 +833,116 @@
   return nullptr;
 }
 
+bool InductionVar::CanComputeDifferenceWith(const InductionVar* other,
+                                            int64_t* diff) const {
+  if (IsInvariant(this) && IsInvariant(other)) {
+    if (def_ == other->def_ && mult_ == other->mult_) {
+      *diff = other->offset_ - offset_;
+      return true;
+    }
+  } else if (IsLinear(this) && IsLinear(other)) {
+    return next_->IsEqual(other->next_) &&
+           initial_->CanComputeDifferenceWith(other->initial_, diff);
+  }
+  // TODO(ajcbik): examine other induction kinds too?
+  return false;
+}
+
+bool InductionVar::CanComputeBoundsImpl(LoopInfo* loop,
+                                        Instruction* pos,
+                                        InductionVar** min,
+                                        InductionVar** max) {
+  // Refine symbolic part of an invariant with outward induction.
+  if (IsInvariant(this)) {
+    if (mult_ == 1 && def_ != nullptr) {
+      for (loop = loop->outer(); loop != nullptr; loop = loop->outer()) {
+        InductionVar* induc = loop->LookupInduction(def_);
+        InductionVar* i_min = nullptr;
+        InductionVar* i_max = nullptr;
+        // Accept i+C with i in [L,U] as [L+C,U+C] when this adjustment
+        // does not have arithmetic wrap-around complications.
+        if (IsInduction(induc) &&
+            induc->CanComputeBounds(loop, pos, &i_min, &i_max)) {
+          Zone* z = Thread::Current()->zone();
+          return SafelyAdjust(z, i_min, offset_, i_max, offset_, min, max);
+        }
+      }
+    }
+    // Otherwise invariant itself suffices.
+    *min = *max = this;
+    return true;
+  }
+  // Refine unit stride induction with lower and upper bound.
+  //    for (int i = L; i < U; i++)
+  //       j = i+C in [L+C,U+C-1]
+  int64_t stride = 0;
+  int64_t off = 0;
+  if (IsLinear(this, &stride) && Utils::Abs(stride) == 1 &&
+      CanComputeDifferenceWith(loop->control(), &off)) {
+    // Find ranges on both L and U first (and not just minimum
+    // of L and maximum of U) to avoid arithmetic wrap-around
+    // complications such as the one shown below.
+    //   for (int i = 0; i < maxint - 10; i++)
+    //     for (int j = i + 20; j < 100; j++)
+    //       j in [minint, 99] and not in [20, 100]
+    InductionVar* l_min = nullptr;
+    InductionVar* l_max = nullptr;
+    if (initial_->CanComputeBounds(loop, pos, &l_min, &l_max)) {
+      // Find extreme using a control bound for which the branch dominates
+      // the given position (to make sure it really is under its control).
+      // Then refine with anything that dominates that branch.
+      for (auto bound : loop->control()->bounds()) {
+        if (pos->IsDominatedBy(bound.branch_)) {
+          InductionVar* u_min = nullptr;
+          InductionVar* u_max = nullptr;
+          if (bound.limit_->CanComputeBounds(loop, bound.branch_, &u_min,
+                                             &u_max)) {
+            Zone* z = Thread::Current()->zone();
+            return stride > 0 ? SafelyAdjust(z, l_min, 0, u_max, -stride - off,
+                                             min, max)
+                              : SafelyAdjust(z, u_min, -stride - off, l_max, 0,
+                                             min, max);
+          }
+        }
+      }
+    }
+  }
+  // Failure. TODO(ajcbik): examine other kinds of induction too?
+  return false;
+}
+
+// Driver method to compute bounds with per-loop memoization.
+bool InductionVar::CanComputeBounds(LoopInfo* loop,
+                                    Instruction* pos,
+                                    InductionVar** min,
+                                    InductionVar** max) {
+  // Consult cache first.
+  LoopInfo::MemoKV::Pair* pair1 = loop->memo_cache_.Lookup(this);
+  if (pair1 != nullptr) {
+    LoopInfo::MemoVal::PosKV::Pair* pair2 = pair1->value->memo_.Lookup(pos);
+    if (pair2 != nullptr) {
+      *min = pair2->value.first;
+      *max = pair2->value.second;
+      return true;
+    }
+  }
+  // Compute and cache.
+  if (CanComputeBoundsImpl(loop, pos, min, max)) {
+    ASSERT(*min != nullptr && *max != nullptr);
+    LoopInfo::MemoVal* memo = nullptr;
+    if (pair1 != nullptr) {
+      memo = pair1->value;
+    } else {
+      memo = new LoopInfo::MemoVal();
+      loop->memo_cache_.Insert(LoopInfo::MemoKV::Pair(this, memo));
+    }
+    memo->memo_.Insert(
+        LoopInfo::MemoVal::PosKV::Pair(pos, std::make_pair(*min, *max)));
+    return true;
+  }
+  return false;
+}
+
 const char* InductionVar::ToCString() const {
   char buffer[1024];
   BufferFormatter f(buffer, sizeof(buffer));
@@ -765,6 +974,7 @@
       blocks_(blocks),
       back_edges_(),
       induction_(),
+      memo_cache_(),
       limit_(nullptr),
       control_(nullptr),
       outer_(nullptr),
@@ -850,6 +1060,7 @@
 
 void LoopInfo::ResetInduction() {
   induction_.Clear();
+  memo_cache_.Clear();
 }
 
 void LoopInfo::AddInduction(Definition* def, InductionVar* induc) {
@@ -866,6 +1077,43 @@
   return nullptr;
 }
 
+// Checks if an index is in range of a given length:
+//   for (int i = initial; i <= length - C; i++) {
+//     .... a[i] ....  // initial >= 0 and C > 0:
+//   }
+bool LoopInfo::IsInRange(Instruction* pos, Value* index, Value* length) {
+  InductionVar* induc = LookupInduction(
+      index->definition()->OriginalDefinitionIgnoreBoxingAndConstraints());
+  InductionVar* len = LookupInduction(
+      length->definition()->OriginalDefinitionIgnoreBoxingAndConstraints());
+  if (induc != nullptr && len != nullptr) {
+    // First, try the most common case. A simple induction directly
+    // bounded by [c>=0,length-C>=0) for the length we are looking for.
+    int64_t stride = 0;
+    int64_t val = 0;
+    int64_t diff = 0;
+    if (InductionVar::IsLinear(induc, &stride) && stride == 1 &&
+        InductionVar::IsConstant(induc->initial(), &val) && 0 <= val) {
+      for (auto bound : induc->bounds()) {
+        if (pos->IsDominatedBy(bound.branch_) &&
+            len->CanComputeDifferenceWith(bound.limit_, &diff) && diff <= 0) {
+          return true;
+        }
+      }
+    }
+    // If that fails, try to compute bounds using more outer loops.
+    // Since array lengths >= 0, the conditions used during this
+    // process avoid arithmetic wrap-around complications.
+    InductionVar* min = nullptr;
+    InductionVar* max = nullptr;
+    if (induc->CanComputeBounds(this, pos, &min, &max)) {
+      return InductionVar::IsConstant(min, &val) && 0 <= val &&
+             len->CanComputeDifferenceWith(max, &diff) && diff < 0;
+    }
+  }
+  return false;
+}
+
 const char* LoopInfo::ToCString() const {
   char buffer[1024];
   BufferFormatter f(buffer, sizeof(buffer));
@@ -928,7 +1176,7 @@
   }
 }
 
-void LoopHierarchy::Print(LoopInfo* loop) {
+void LoopHierarchy::Print(LoopInfo* loop) const {
   for (; loop != nullptr; loop = loop->next_) {
     THR_Print("%s {", loop->ToCString());
     for (BitVector::Iterator it(loop->blocks_); !it.Done(); it.Advance()) {
diff --git a/runtime/vm/compiler/backend/loops.h b/runtime/vm/compiler/backend/loops.h
index 215d26f..79f0e90 100644
--- a/runtime/vm/compiler/backend/loops.h
+++ b/runtime/vm/compiler/backend/loops.h
@@ -5,6 +5,8 @@
 #ifndef RUNTIME_VM_COMPILER_BACKEND_LOOPS_H_
 #define RUNTIME_VM_COMPILER_BACKEND_LOOPS_H_
 
+#include <utility>
+
 #include "vm/allocation.h"
 #include "vm/compiler/backend/il.h"
 
@@ -31,7 +33,7 @@
     kPeriodic,
   };
 
-  // Strict bound on unit stride linear induction:
+  // Strict (exclusive) upper or lower bound on unit stride linear induction:
   //   i < U (i++)
   //   i > L (i--)
   struct Bound {
@@ -42,14 +44,14 @@
 
   // Constructor for an invariant.
   InductionVar(int64_t offset, int64_t mult, Definition* def)
-      : kind_(kInvariant), offset_(offset), mult_(mult), def_(def) {}
+      : kind_(kInvariant), offset_(offset), mult_(mult), def_(def), bounds_() {}
 
   // Constructor for a constant.
   explicit InductionVar(int64_t offset) : InductionVar(offset, 0, nullptr) {}
 
   // Constructor for an induction.
   InductionVar(Kind kind, InductionVar* initial, InductionVar* next)
-      : kind_(kind), initial_(initial), next_(next) {
+      : kind_(kind), initial_(initial), next_(next), bounds_() {
     ASSERT(IsInvariant(initial));
     switch (kind) {
       case kLinear:
@@ -65,7 +67,7 @@
   }
 
   // Returns true if the other induction is structually equivalent.
-  bool IsEqual(InductionVar* other) const {
+  bool IsEqual(const InductionVar* other) const {
     ASSERT(other != nullptr);
     if (kind_ == other->kind_) {
       switch (kind_) {
@@ -82,6 +84,19 @@
     return false;
   }
 
+  // Returns true if a fixed difference between this and the other induction
+  // can be computed. Sets the output parameter diff on success.
+  bool CanComputeDifferenceWith(const InductionVar* other, int64_t* diff) const;
+
+  // Returns true if this induction in the given loop can be bounded as
+  // min <= this <= max by using bounds of more outer loops. On success
+  // the output parameters min and max are set, which are always loop
+  // invariant expressions inside the given loop.
+  bool CanComputeBounds(LoopInfo* loop,
+                        Instruction* pos,
+                        InductionVar** min,
+                        InductionVar** max);
+
   // Getters.
   Kind kind() const { return kind_; }
   int64_t offset() const {
@@ -110,17 +125,17 @@
   const char* ToCString() const;
 
   // Returns true if x is invariant.
-  static bool IsInvariant(InductionVar* x) {
+  static bool IsInvariant(const InductionVar* x) {
     return x != nullptr && x->kind_ == kInvariant;
   }
 
   // Returns true if x is a constant (and invariant).
-  static bool IsConstant(InductionVar* x) {
+  static bool IsConstant(const InductionVar* x) {
     return x != nullptr && x->kind_ == kInvariant && x->mult_ == 0;
   }
 
   // Returns true if x is a constant. Sets the value.
-  static bool IsConstant(InductionVar* x, int64_t* c) {
+  static bool IsConstant(const InductionVar* x, int64_t* c) {
     if (IsConstant(x)) {
       *c = x->offset_;
       return true;
@@ -129,12 +144,12 @@
   }
 
   // Returns true if x is linear.
-  static bool IsLinear(InductionVar* x) {
+  static bool IsLinear(const InductionVar* x) {
     return x != nullptr && x->kind_ == kLinear;
   }
 
   // Returns true if x is linear with constant stride. Sets the stride.
-  static bool IsLinear(InductionVar* x, int64_t* s) {
+  static bool IsLinear(const InductionVar* x, int64_t* s) {
     if (IsLinear(x)) {
       return IsConstant(x->next_, s);
     }
@@ -142,17 +157,17 @@
   }
 
   // Returns true if x is wrap-around.
-  static bool IsWrapAround(InductionVar* x) {
+  static bool IsWrapAround(const InductionVar* x) {
     return x != nullptr && x->kind_ == kWrapAround;
   }
 
   // Returns true if x is periodic.
-  static bool IsPeriodic(InductionVar* x) {
+  static bool IsPeriodic(const InductionVar* x) {
     return x != nullptr && x->kind_ == kPeriodic;
   }
 
   // Returns true if x is any induction.
-  static bool IsInduction(InductionVar* x) {
+  static bool IsInduction(const InductionVar* x) {
     return x != nullptr && x->kind_ != kInvariant;
   }
 
@@ -173,6 +188,11 @@
     };
   };
 
+  bool CanComputeBoundsImpl(LoopInfo* loop,
+                            Instruction* pos,
+                            InductionVar** min,
+                            InductionVar** max);
+
   // Bounds on induction.
   GrowableArray<Bound> bounds_;
 
@@ -217,6 +237,9 @@
   // Looks up induction.
   InductionVar* LookupInduction(Definition* def) const;
 
+  // Tests if index stays in [0,length) range in this loop at given position.
+  bool IsInRange(Instruction* pos, Value* index, Value* length);
+
   // Getters.
   intptr_t id() const { return id_; }
   BlockEntryInstr* header() const { return header_; }
@@ -232,11 +255,24 @@
   const char* ToCString() const;
 
  private:
+  friend class InductionVar;
   friend class InductionVarAnalysis;
   friend class LoopHierarchy;
 
+  // Mapping from definition to induction.
   typedef RawPointerKeyValueTrait<Definition, InductionVar*> InductionKV;
 
+  // Mapping from induction to mapping from instruction to induction pair.
+  class MemoVal : public ZoneAllocated {
+   public:
+    typedef RawPointerKeyValueTrait<Instruction,
+                                    std::pair<InductionVar*, InductionVar*>>
+        PosKV;
+    MemoVal() : memo_() {}
+    DirectChainedHashMap<PosKV> memo_;
+  };
+  typedef RawPointerKeyValueTrait<InductionVar, MemoVal*> MemoKV;
+
   // Unique id of loop. We use its index in the
   // loop header array for this.
   const intptr_t id_;
@@ -254,6 +290,10 @@
   // Map definition -> induction for this loop.
   DirectChainedHashMap<InductionKV> induction_;
 
+  // A small, per-loop memoization cache, to avoid costly
+  // recomputations while traversing very deeply nested loops.
+  DirectChainedHashMap<MemoKV> memo_cache_;
+
   // Constraint on a header phi.
   // TODO(ajcbik): very specific to smi range analysis,
   //               should we really store it here?
@@ -290,7 +330,7 @@
 
  private:
   void Build();
-  void Print(LoopInfo* loop);
+  void Print(LoopInfo* loop) const;
 
   ZoneGrowableArray<BlockEntryInstr*>* headers_;
   const GrowableArray<BlockEntryInstr*>& preorder_;
diff --git a/runtime/vm/compiler/backend/range_analysis.cc b/runtime/vm/compiler/backend/range_analysis.cc
index 09d8b41..0178cbd 100644
--- a/runtime/vm/compiler/backend/range_analysis.cc
+++ b/runtime/vm/compiler/backend/range_analysis.cc
@@ -970,14 +970,22 @@
     return nullptr;
   }
 
-  // Reconstruct invariant (phi-init is always already in the graph).
+  // Reconstruct invariant.
   Definition* GenerateInvariant(InductionVar* induc) {
+    Definition* res = nullptr;
     if (induc->mult() == 0) {
-      return flow_graph_->GetConstant(
-          Smi::ZoneHandle(Smi::New(induc->offset())));
+      res =
+          flow_graph_->GetConstant(Smi::ZoneHandle(Smi::New(induc->offset())));
+    } else {
+      res = induc->def();
+      if (induc->mult() != 1) {
+        res = MakeBinaryOp(Token::kMUL, res, induc->mult());
+      }
+      if (induc->offset() != 0) {
+        res = MakeBinaryOp(Token::kADD, res, induc->offset());
+      }
     }
-    ASSERT(induc->offset() == 0 && induc->mult() == 1);
-    return induc->def();
+    return res;
   }
 
   // Construct symbolic bound for a value at the given point:
@@ -1337,7 +1345,7 @@
         !function.ProhibitsBoundsCheckGeneralization();
     BoundsCheckGeneralizer generalizer(this, flow_graph_);
     for (CheckBoundBase* check : bounds_checks_) {
-      if (check->IsRedundant()) {
+      if (check->IsRedundant(/*use_loops=*/true)) {
         check->ReplaceUsesWith(check->index()->definition());
         check->RemoveFromGraph();
       } else if (try_generalization) {
@@ -2215,14 +2223,6 @@
       RangeBoundary::FromConstant((static_cast<uint64_t>(1) << bitsize) - 1);
 }
 
-static bool IsArrayLength(Definition* defn) {
-  if (defn == NULL) {
-    return false;
-  }
-  LoadFieldInstr* load = UnwrapConstraint(defn)->AsLoadField();
-  return (load != NULL) && load->IsImmutableLengthLoad();
-}
-
 void Range::Add(const Range* left_range,
                 const Range* right_range,
                 RangeBoundary* result_min,
@@ -2233,11 +2233,11 @@
   ASSERT(result_min != NULL);
   ASSERT(result_max != NULL);
 
-  RangeBoundary left_min = IsArrayLength(left_defn)
+  RangeBoundary left_min = Definition::IsArrayLength(left_defn)
                                ? RangeBoundary::FromDefinition(left_defn)
                                : left_range->min();
 
-  RangeBoundary left_max = IsArrayLength(left_defn)
+  RangeBoundary left_max = Definition::IsArrayLength(left_defn)
                                ? RangeBoundary::FromDefinition(left_defn)
                                : left_range->max();
 
@@ -2263,11 +2263,11 @@
   ASSERT(result_min != NULL);
   ASSERT(result_max != NULL);
 
-  RangeBoundary left_min = IsArrayLength(left_defn)
+  RangeBoundary left_min = Definition::IsArrayLength(left_defn)
                                ? RangeBoundary::FromDefinition(left_defn)
                                : left_range->min();
 
-  RangeBoundary left_max = IsArrayLength(left_defn)
+  RangeBoundary left_max = Definition::IsArrayLength(left_defn)
                                ? RangeBoundary::FromDefinition(left_defn)
                                : left_range->max();
 
@@ -3015,59 +3015,17 @@
   return false;
 }
 
-// Check if range boundary and invariant limit are the same boundary.
-static bool IsSameBound(const RangeBoundary& a, InductionVar* b) {
-  ASSERT(InductionVar::IsInvariant(b));
-  if (a.IsSymbol()) {
-    // Check for exactly the same symbol as length.
-    return a.symbol() == b->def() && b->mult() == 1 &&
-           a.offset() == b->offset();
-  } else if (a.IsConstant()) {
-    // Check for constant in right range 0 < c <= length.
-    int64_t c = 0;
-    return InductionVar::IsConstant(b, &c) && 0 < c && c <= a.ConstantValue();
-  }
-  return false;
-}
-
-bool CheckBoundBase::IsRedundant() {
+bool CheckBoundBase::IsRedundant(bool use_loops) {
   // First, try to prove redundancy with the results of range analysis.
   if (IsRedundantBasedOnRangeInformation(index(), length())) {
     return true;
-  } else if (previous() == nullptr) {
-    return false;  // check is not in flow graph yet
+  } else if (!use_loops) {
+    return false;
   }
   // Next, try to prove redundancy with the results of induction analysis.
-  // Under 64-bit wrap-around arithmetic, it is always safe to remove the
-  // bounds check from the following loop, if initial >= 0 and the loop
-  // exit branch dominates the bounds check:
-  //
-  //   for (int i = initial; i < length; i++)
-  //     .... a[i] ....
-  //
   LoopInfo* loop = GetBlock()->loop_info();
   if (loop != nullptr) {
-    InductionVar* induc = loop->LookupInduction(index()->definition());
-    if (induc != nullptr) {
-      int64_t stride = 0;
-      int64_t initial = 0;
-      if (InductionVar::IsLinear(induc, &stride) &&
-          InductionVar::IsConstant(induc->initial(), &initial)) {
-        if (stride == 1 && initial >= 0) {
-          // Deeply trace back the range of the array length.
-          RangeBoundary deep_length = RangeBoundary::FromDefinition(
-              length()
-                  ->definition()
-                  ->OriginalDefinitionIgnoreBoxingAndConstraints());
-          for (auto bound : induc->bounds()) {
-            if (IsSameBound(deep_length, bound.limit_) &&
-                this->IsDominatedBy(bound.branch_)) {
-              return true;
-            }
-          }
-        }
-      }
-    }
+    return loop->IsInRange(this, index(), length());
   }
   return false;
 }
diff --git a/runtime/vm/compiler/backend/slot.cc b/runtime/vm/compiler/backend/slot.cc
index 8b14388..bd7d94b 100644
--- a/runtime/vm/compiler/backend/slot.cc
+++ b/runtime/vm/compiler/backend/slot.cc
@@ -212,13 +212,22 @@
     }
   }
 
-  const Slot& slot = SlotCache::Instance(thread).Canonicalize(
-      Slot(Kind::kDartField,
-           IsImmutableBit::encode(field.is_final() || field.is_const()) |
-               IsNullableBit::encode(is_nullable) |
-               IsGuardedBit::encode(used_guarded_state),
-           nullable_cid, compiler::target::Field::OffsetOf(field), &field,
-           &AbstractType::ZoneHandle(zone, field.type())));
+  AbstractType& type = AbstractType::ZoneHandle(zone, field.type());
+
+  if (field.needs_load_guard()) {
+    // Should be kept in sync with LoadStaticFieldInstr::ComputeType.
+    type = Type::DynamicType();
+    nullable_cid = kDynamicCid;
+    is_nullable = true;
+    used_guarded_state = false;
+  }
+
+  const Slot& slot = SlotCache::Instance(thread).Canonicalize(Slot(
+      Kind::kDartField,
+      IsImmutableBit::encode(field.is_final() || field.is_const()) |
+          IsNullableBit::encode(is_nullable) |
+          IsGuardedBit::encode(used_guarded_state),
+      nullable_cid, compiler::target::Field::OffsetOf(field), &field, &type));
 
   // If properties of this slot were based on the guarded state make sure
   // to add the field to the list of guarded fields. Note that during background
diff --git a/runtime/vm/compiler/backend/type_propagator.cc b/runtime/vm/compiler/backend/type_propagator.cc
index bbf2391..99460c1 100644
--- a/runtime/vm/compiler/backend/type_propagator.cc
+++ b/runtime/vm/compiler/backend/type_propagator.cc
@@ -554,10 +554,12 @@
   }
 
   const AbstractType* other_abstract_type = other->ToAbstractType();
-  if (abstract_type->IsSubtypeOf(*other_abstract_type, Heap::kOld)) {
+  if (abstract_type->IsSubtypeOf(NNBDMode::kLegacy, *other_abstract_type,
+                                 Heap::kOld)) {
     type_ = other_abstract_type;
     return;
-  } else if (other_abstract_type->IsSubtypeOf(*abstract_type, Heap::kOld)) {
+  } else if (other_abstract_type->IsSubtypeOf(NNBDMode::kLegacy, *abstract_type,
+                                              Heap::kOld)) {
     return;  // Nothing to do.
   }
 
@@ -567,7 +569,8 @@
     Class& cls = Class::Handle(abstract_type->type_class());
     for (; !cls.IsNull() && !cls.IsGeneric(); cls = cls.SuperClass()) {
       type_ = &AbstractType::ZoneHandle(cls.RareType());
-      if (other_abstract_type->IsSubtypeOf(*type_, Heap::kOld)) {
+      if (other_abstract_type->IsSubtypeOf(NNBDMode::kLegacy, *type_,
+                                           Heap::kOld)) {
         // Found suitable supertype: keep type_ only.
         cid_ = kDynamicCid;
         return;
@@ -607,7 +610,8 @@
   const AbstractType* new_abstract_type = new_type->ToAbstractType();
 
   CompileType* preferred_type;
-  if (old_abstract_type->IsSubtypeOf(*new_abstract_type, Heap::kOld)) {
+  if (old_abstract_type->IsSubtypeOf(NNBDMode::kLegacy, *new_abstract_type,
+                                     Heap::kOld)) {
     // Prefer old type, as it is clearly more specific.
     preferred_type = old_type;
   } else {
@@ -776,11 +780,7 @@
 
     Isolate* I = Isolate::Current();
     const Class& type_class = Class::Handle(I->class_table()->At(cid_));
-    if (type_class.NumTypeArguments() > 0) {
-      type_ = &AbstractType::ZoneHandle(type_class.RareType());
-    } else {
-      type_ = &Type::ZoneHandle(Type::NewNonParameterizedType(type_class));
-    }
+    type_ = &AbstractType::ZoneHandle(type_class.RareType());
   }
 
   return type_;
@@ -818,7 +818,7 @@
     return false;
   }
 
-  *is_instance = compile_type.IsSubtypeOf(type, Heap::kOld);
+  *is_instance = compile_type.IsSubtypeOf(NNBDMode::kLegacy, type, Heap::kOld);
   return *is_instance;
 }
 
@@ -827,7 +827,7 @@
     return false;
   }
 
-  return ToAbstractType()->IsSubtypeOf(other, Heap::kOld);
+  return ToAbstractType()->IsSubtypeOf(NNBDMode::kLegacy, other, Heap::kOld);
 }
 
 void CompileType::PrintTo(BufferFormatter* f) const {
@@ -1375,6 +1375,11 @@
     is_nullable = field.is_nullable();
     abstract_type = nullptr;  // Cid is known, calculate abstract type lazily.
   }
+  if (field.needs_load_guard()) {
+    // Should be kept in sync with Slot::Get.
+    DEBUG_ASSERT(Isolate::Current()->HasAttemptedReload());
+    return CompileType::Dynamic();
+  }
   return CompileType(is_nullable, cid, abstract_type);
 }
 
diff --git a/runtime/vm/compiler/backend/yield_position_test.cc b/runtime/vm/compiler/backend/yield_position_test.cc
new file mode 100644
index 0000000..7707468
--- /dev/null
+++ b/runtime/vm/compiler/backend/yield_position_test.cc
@@ -0,0 +1,132 @@
+// Copyright (c) 2019, 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.
+
+#include <utility>
+
+#include "vm/compiler/backend/il_test_helper.h"
+#include "vm/compiler/compiler_pass.h"
+#include "vm/object.h"
+#include "vm/unit_test.h"
+
+namespace dart {
+
+using Pair = std::pair<intptr_t, TokenPosition>;
+using YieldPoints = ZoneGrowableArray<Pair>;
+
+int LowestFirst(const Pair* a, const Pair* b) {
+  return a->first - b->first;
+}
+
+static YieldPoints* GetYieldPointsFromGraph(FlowGraph* flow_graph) {
+  auto array = new (flow_graph->zone()) YieldPoints();
+  const auto& blocks = flow_graph->reverse_postorder();
+  for (auto block : blocks) {
+    ForwardInstructionIterator it(block);
+    while (!it.Done()) {
+      if (auto return_instr = it.Current()->AsReturn()) {
+        if (return_instr->yield_index() !=
+            RawPcDescriptors::kInvalidYieldIndex) {
+          ASSERT(return_instr->yield_index() > 0);
+          array->Add(
+              Pair(return_instr->yield_index(), return_instr->token_pos()));
+        }
+      }
+      it.Advance();
+    }
+  }
+  array->Sort(LowestFirst);
+  return array;
+}
+
+static YieldPoints* GetYieldPointsFromCode(const Code& code) {
+  auto array = new YieldPoints();
+  const auto& pc_descriptor = PcDescriptors::Handle(code.pc_descriptors());
+  PcDescriptors::Iterator it(pc_descriptor, RawPcDescriptors::kOther);
+  while (it.MoveNext()) {
+    if (it.YieldIndex() != RawPcDescriptors::kInvalidYieldIndex) {
+      array->Add(Pair(it.YieldIndex(), it.TokenPos()));
+    }
+  }
+  array->Sort(LowestFirst);
+  return array;
+}
+
+void RunTestInMode(CompilerPass::PipelineMode mode) {
+  const char* kScript =
+      R"(
+      import 'dart:async';
+
+      Future foo() async {
+        print('pos-0');
+        await 0;
+        print('pos-1');
+        await 1;
+        print('pos-2');
+        await 2;
+      }
+      )";
+
+  SetupCoreLibrariesForUnitTest();
+
+  const auto& root_library = Library::Handle(LoadTestScript(kScript));
+  // Ensure the outer function was compiled once, ensuring we have a closure
+  // function for the inner closure.
+  Invoke(root_library, "foo");
+
+  const auto& outer_function =
+      Function::Handle(GetFunction(root_library, "foo"));
+
+  // Grab the inner, lazily created, closure from the object store.
+  const auto& closures = GrowableObjectArray::Handle(
+      Isolate::Current()->object_store()->closure_functions());
+  ASSERT(!closures.IsNull());
+  auto& closure = Object::Handle();
+  for (intptr_t i = 0; i < closures.Length(); ++i) {
+    closure = closures.At(i);
+    if (Function::Cast(closure).parent_function() == outer_function.raw()) {
+      break;
+    }
+    closure = Object::null();
+  }
+  RELEASE_ASSERT(closure.IsFunction());
+  const auto& function = Function::Cast(closure);
+
+  // Ensure we have 3 different return instructions with yield indices attached
+  // to them.
+  TestPipeline pipeline(function, mode);
+  FlowGraph* flow_graph = pipeline.RunPasses({
+      CompilerPass::kComputeSSA,
+  });
+
+  auto validate_indices = [](const YieldPoints& yield_points) {
+    EXPECT_EQ(3, yield_points.length());
+
+    EXPECT_EQ(1, yield_points[0].first);
+    EXPECT_EQ(88, yield_points[0].second.value());
+    EXPECT_EQ(2, yield_points[1].first);
+    EXPECT_EQ(129, yield_points[1].second.value());
+    EXPECT_EQ(3, yield_points[2].first);
+    EXPECT_EQ(170, yield_points[2].second.value());
+  };
+
+  validate_indices(*GetYieldPointsFromGraph(flow_graph));
+
+  // Ensure we have 3 different yield indices attached to the code via pc
+  // descriptors.
+  const auto& error = Error::Handle(
+      Compiler::EnsureUnoptimizedCode(Thread::Current(), function));
+  RELEASE_ASSERT(error.IsNull());
+  const auto& code = Code::Handle(function.CurrentCode());
+  validate_indices(*GetYieldPointsFromCode(code));
+}
+
+ISOLATE_UNIT_TEST_CASE(IRTest_YieldIndexAvailableJIT) {
+  RunTestInMode(CompilerPass::kJIT);
+}
+
+ISOLATE_UNIT_TEST_CASE(IRTest_YieldIndexAvailableAOT) {
+  RunTestInMode(CompilerPass::kAOT);
+}
+
+}  // namespace dart
diff --git a/runtime/vm/compiler/call_specializer.cc b/runtime/vm/compiler/call_specializer.cc
index 9fd7c9d..34c9bc0 100644
--- a/runtime/vm/compiler/call_specializer.cc
+++ b/runtime/vm/compiler/call_specializer.cc
@@ -988,8 +988,7 @@
 
   const Function& target = targets.FirstTarget();
   intptr_t receiver_cid = targets.MonomorphicReceiverCid();
-  MethodRecognizer::Kind recognized_kind =
-      MethodRecognizer::RecognizeKind(target);
+  MethodRecognizer::Kind recognized_kind = target.recognized_kind();
 
   if (CanUnboxDouble() &&
       (recognized_kind == MethodRecognizer::kIntegerToDouble)) {
@@ -1108,7 +1107,8 @@
         cls.IsNullClass()
             ? (type_class.IsNullClass() || type_class.IsObjectClass() ||
                type_class.IsDynamicClass())
-            : Class::IsSubtypeOf(cls, Object::null_type_arguments(), type_class,
+            : Class::IsSubtypeOf(NNBDMode::kLegacy, cls,
+                                 Object::null_type_arguments(), type_class,
                                  Object::null_type_arguments(), Heap::kOld);
     results->Add(cls.id());
     results->Add(static_cast<intptr_t>(is_subtype));
@@ -1308,8 +1308,7 @@
   if (speculative_policy_->IsAllowedForInlining(call->deopt_id())) {
     // Only if speculative inlining is enabled.
 
-    MethodRecognizer::Kind recognized_kind =
-        MethodRecognizer::RecognizeKind(call->function());
+    MethodRecognizer::Kind recognized_kind = call->function().recognized_kind();
     const CallTargets& targets = call->Targets();
     const BinaryFeedback& binary_feedback = call->BinaryFeedback();
 
@@ -1422,9 +1421,9 @@
   if ((*results)[0] != kSmiCid) {
     const Class& smi_class = Class::Handle(class_table.At(kSmiCid));
     const Class& type_class = Class::Handle(type.type_class());
-    const bool smi_is_subtype =
-        Class::IsSubtypeOf(smi_class, Object::null_type_arguments(), type_class,
-                           Object::null_type_arguments(), Heap::kOld);
+    const bool smi_is_subtype = Class::IsSubtypeOf(
+        NNBDMode::kLegacy, smi_class, Object::null_type_arguments(), type_class,
+        Object::null_type_arguments(), Heap::kOld);
     results->Add((*results)[results->length() - 2]);
     results->Add((*results)[results->length() - 2]);
     for (intptr_t i = results->length() - 3; i > 1; --i) {
diff --git a/runtime/vm/compiler/compiler_sources.gni b/runtime/vm/compiler/compiler_sources.gni
index 3324814..6f92238 100644
--- a/runtime/vm/compiler/compiler_sources.gni
+++ b/runtime/vm/compiler/compiler_sources.gni
@@ -169,5 +169,6 @@
   "backend/slot_test.cc",
   "backend/type_propagator_test.cc",
   "backend/typed_data_aot_test.cc",
+  "backend/yield_position_test.cc",
   "cha_test.cc",
 ]
diff --git a/runtime/vm/compiler/frontend/base_flow_graph_builder.cc b/runtime/vm/compiler/frontend/base_flow_graph_builder.cc
index 9b216a9..9425b5c 100644
--- a/runtime/vm/compiler/frontend/base_flow_graph_builder.cc
+++ b/runtime/vm/compiler/frontend/base_flow_graph_builder.cc
@@ -186,14 +186,15 @@
   return Fragment(branch).closed();
 }
 
-Fragment BaseFlowGraphBuilder::Return(TokenPosition position) {
+Fragment BaseFlowGraphBuilder::Return(TokenPosition position,
+                                      intptr_t yield_index) {
   Fragment instructions;
 
   Value* value = Pop();
   ASSERT(stack_ == nullptr);
 
   ReturnInstr* return_instr =
-      new (Z) ReturnInstr(position, value, GetNextDeoptId());
+      new (Z) ReturnInstr(position, value, GetNextDeoptId(), yield_index);
   if (exit_collector_ != nullptr) exit_collector_->AddExit(return_instr);
 
   instructions <<= return_instr;
diff --git a/runtime/vm/compiler/frontend/base_flow_graph_builder.h b/runtime/vm/compiler/frontend/base_flow_graph_builder.h
index dc8043b..fe89441 100644
--- a/runtime/vm/compiler/frontend/base_flow_graph_builder.h
+++ b/runtime/vm/compiler/frontend/base_flow_graph_builder.h
@@ -267,7 +267,8 @@
                          bool negate = false);
   Fragment BranchIfStrictEqual(TargetEntryInstr** then_entry,
                                TargetEntryInstr** otherwise_entry);
-  Fragment Return(TokenPosition position);
+  Fragment Return(TokenPosition position,
+                  intptr_t yield_index = RawPcDescriptors::kInvalidYieldIndex);
   Fragment CheckStackOverflow(TokenPosition position,
                               intptr_t stack_depth,
                               intptr_t loop_depth);
diff --git a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc
index 2e8c237..9eb722f 100644
--- a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc
+++ b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc
@@ -842,8 +842,7 @@
   const Function& target = Function::Cast(ConstantAt(DecodeOperandD()).value());
   const intptr_t argc = DecodeOperandF().value();
 
-  const auto recognized_kind = MethodRecognizer::RecognizeKind(target);
-  switch (recognized_kind) {
+  switch (target.recognized_kind()) {
     case MethodRecognizer::kFfiAsFunctionInternal:
       BuildFfiAsFunction();
       return;
@@ -1329,6 +1328,15 @@
       field, StoreInstanceFieldInstr::Kind::kInitializing, kNoStoreBarrier);
 }
 
+void BytecodeFlowGraphBuilder::BuildPushUninitializedSentinel() {
+  code_ += B->Constant(Object::sentinel());
+}
+
+void BytecodeFlowGraphBuilder::BuildJumpIfInitialized() {
+  code_ += B->Constant(Object::sentinel());
+  BuildJumpIfStrictCompare(Token::kNE);
+}
+
 void BytecodeFlowGraphBuilder::BuildLoadStatic() {
   const Constant operand = ConstantAt(DecodeOperandD());
   const auto& field = Field::Cast(operand.value());
@@ -1660,7 +1668,15 @@
   BuildDebugStepCheck();
   LoadStackSlots(1);
   ASSERT(code_.is_open());
-  code_ += B->Return(position_);
+  intptr_t yield_index = RawPcDescriptors::kInvalidYieldIndex;
+  if (function().IsAsyncClosure() || function().IsAsyncGenClosure()) {
+    if (pc_ == last_yield_point_pc_) {
+      // The return might actually be a yield point, if so we need to attach the
+      // yield index to the return instruction.
+      yield_index = last_yield_point_index_;
+    }
+  }
+  code_ += B->Return(position_, yield_index);
   ASSERT(IsStackEmpty());
 }
 
@@ -2010,8 +2026,7 @@
 
     case KernelBytecode::kNativeCall:
     case KernelBytecode::kNativeCall_Wide:
-      return MethodRecognizer::RecognizeKind(function()) ==
-             MethodRecognizer::kListFactory;
+      return function().recognized_kind() == MethodRecognizer::kListFactory;
 
     default:
       return false;
@@ -2320,6 +2335,10 @@
     while (update_position &&
            static_cast<uword>(pc_) >= source_pos_iter.PcOffset()) {
       position_ = source_pos_iter.TokenPos();
+      if (source_pos_iter.IsYieldPoint()) {
+        last_yield_point_pc_ = source_pos_iter.PcOffset();
+        ++last_yield_point_index_;
+      }
       update_position = source_pos_iter.MoveNext();
     }
 
diff --git a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.h b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.h
index 6b1ea18..2500f43 100644
--- a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.h
+++ b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.h
@@ -224,6 +224,8 @@
   intptr_t next_pc_ = -1;
   const KBCInstr* bytecode_instr_ = nullptr;
   TokenPosition position_;
+  intptr_t last_yield_point_pc_ = 0;
+  intptr_t last_yield_point_index_ = 0;
   Fragment code_;
   ZoneGrowableArray<LocalVariable*> local_vars_;
   ZoneGrowableArray<LocalVariable*> parameters_;
diff --git a/runtime/vm/compiler/frontend/bytecode_reader.cc b/runtime/vm/compiler/frontend/bytecode_reader.cc
index cbc4c49..f702f9b 100644
--- a/runtime/vm/compiler/frontend/bytecode_reader.cc
+++ b/runtime/vm/compiler/frontend/bytecode_reader.cc
@@ -502,11 +502,12 @@
   closures_->SetAt(closureIndex, closure);
 
   Type& signature_type = Type::Handle(
-      Z, ReadFunctionSignature(
-             closure, (flags & kHasOptionalPositionalParamsFlag) != 0,
-             (flags & kHasOptionalNamedParamsFlag) != 0,
-             (flags & kHasTypeParamsFlag) != 0,
-             /* has_positional_param_names = */ true, kNonNullable));
+      Z, ReadFunctionSignature(closure,
+                               (flags & kHasOptionalPositionalParamsFlag) != 0,
+                               (flags & kHasOptionalNamedParamsFlag) != 0,
+                               (flags & kHasTypeParamsFlag) != 0,
+                               /* has_positional_param_names = */ true,
+                               Nullability::kNonNullable));
 
   closure.SetSignatureType(signature_type);
 
@@ -970,10 +971,12 @@
       }
       pc_descriptors_list->AddDescriptor(RawPcDescriptors::kOther, start_pc,
                                          DeoptId::kNone,
-                                         TokenPosition::kNoSource, try_index);
+                                         TokenPosition::kNoSource, try_index,
+                                         RawPcDescriptors::kInvalidYieldIndex);
       pc_descriptors_list->AddDescriptor(RawPcDescriptors::kOther, end_pc,
                                          DeoptId::kNone,
-                                         TokenPosition::kNoSource, try_index);
+                                         TokenPosition::kNoSource, try_index,
+                                         RawPcDescriptors::kInvalidYieldIndex);
 
       // The exception handler keeps a zone handle of the types array, rather
       // than a raw pointer. Do not share the handle across iterations to avoid
@@ -1019,7 +1022,7 @@
 
 RawTypedData* BytecodeReaderHelper::NativeEntry(const Function& function,
                                                 const String& external_name) {
-  MethodRecognizer::Kind kind = MethodRecognizer::RecognizeKind(function);
+  MethodRecognizer::Kind kind = function.recognized_kind();
   // This list of recognized methods must be kept in sync with the list of
   // methods handled specially by the NativeCall bytecode in the interpreter.
   switch (kind) {
@@ -1508,7 +1511,7 @@
       const Nullability nullability =
           bytecode_component_->GetVersion() >= 24
               ? static_cast<Nullability>((flags & kNullabilityMask) / kFlagBit4)
-              : kLegacy;
+              : Nullability::kLegacy;
       return ReadType(tag, nullability);
     }
     default:
@@ -1669,14 +1672,7 @@
       if (!cls.is_declaration_loaded()) {
         LoadReferencedClass(cls);
       }
-      Type& type = Type::Handle(Z, cls.DeclarationType());
-      // TODO(regis): Remove this workaround once nullability of Null provided
-      // by CFE is always kNullable.
-      if (type.IsNullType()) {
-        ASSERT(type.IsNullable());
-        return type.raw();
-      }
-      return type.ToNullability(nullability, Heap::kOld);
+      return cls.DeclarationType(nullability);
     }
     case kTypeParameter: {
       Object& parent = Object::Handle(Z, ReadObject());
@@ -1710,9 +1706,9 @@
       }
       const TypeArguments& type_arguments =
           TypeArguments::CheckedHandle(Z, ReadObject());
-      const Type& type = Type::Handle(
-          Z, Type::New(cls, type_arguments, TokenPosition::kNoSource));
-      type.set_nullability(nullability);
+      const Type& type =
+          Type::Handle(Z, Type::New(cls, type_arguments,
+                                    TokenPosition::kNoSource, nullability));
       type.SetIsFinalized();
       return type.Canonicalize();
     }
@@ -1742,9 +1738,9 @@
       pending_recursive_types_->SetLength(id);
       pending_recursive_types_ = saved_pending_recursive_types;
 
-      Type& type = Type::Handle(
-          Z, Type::New(cls, type_arguments, TokenPosition::kNoSource));
-      type.set_nullability(nullability);
+      Type& type =
+          Type::Handle(Z, Type::New(cls, type_arguments,
+                                    TokenPosition::kNoSource, nullability));
       type_ref.set_type(type);
       type.SetIsFinalized();
       if (id != 0) {
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
index ca71934..555d02c 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
@@ -1539,8 +1539,8 @@
   while (!iterate_klass.IsNull()) {
     function = iterate_klass.LookupDynamicFunctionAllowPrivate(name);
     if (!function.IsNull()) {
-      if (function.AreValidArguments(type_args_len, argument_count,
-                                     argument_names,
+      if (function.AreValidArguments(NNBDMode::kLegacy, type_args_len,
+                                     argument_count, argument_names,
                                      /* error_message = */ NULL)) {
         return function;
       }
@@ -1572,8 +1572,10 @@
   return flow_graph_builder_->LoadLocal(variable);
 }
 
-Fragment StreamingFlowGraphBuilder::Return(TokenPosition position) {
-  return flow_graph_builder_->Return(position);
+Fragment StreamingFlowGraphBuilder::Return(TokenPosition position,
+                                           intptr_t yield_index) {
+  return flow_graph_builder_->Return(position, /*omit_result_type_check=*/false,
+                                     yield_index);
 }
 
 Fragment StreamingFlowGraphBuilder::PushArgument() {
@@ -3112,7 +3114,7 @@
     ++argument_count;
   }
 
-  const auto recognized_kind = MethodRecognizer::RecognizeKind(target);
+  const auto recognized_kind = target.recognized_kind();
   if (recognized_kind == MethodRecognizer::kFfiAsFunctionInternal) {
     return BuildFfiAsFunctionInternal();
   } else if (FLAG_precompiled_mode &&
@@ -3190,8 +3192,8 @@
   instructions += BuildArguments(&argument_names, NULL /* arg count */,
                                  NULL /* positional arg count */,
                                  special_case);  // read arguments.
-  ASSERT(target.AreValidArguments(type_args_len, argument_count, argument_names,
-                                  NULL));
+  ASSERT(target.AreValidArguments(NNBDMode::kLegacy, type_args_len,
+                                  argument_count, argument_names, NULL));
 
   // Special case identical(x, y) call.
   // Note: similar optimization is performed in bytecode flow graph builder -
@@ -3485,7 +3487,8 @@
   // special case this situation.
   const Type& object_type = Type::Handle(Z, Type::ObjectType());
 
-  if (type.IsInstantiated() && object_type.IsSubtypeOf(type, Heap::kOld)) {
+  if (type.IsInstantiated() &&
+      object_type.IsSubtypeOf(NNBDMode::kLegacy, type, Heap::kOld)) {
     // Evaluate the expression on the left but ignore it's result.
     instructions += Drop();
 
@@ -4787,10 +4790,6 @@
 
   ASSERT(flags == kNativeYieldFlags);  // Must have been desugared.
 
-  // Collect yield position
-  if (record_yield_positions_ != nullptr) {
-    record_yield_positions_->Add(Smi::Handle(Z, Smi::New(position.value())));
-  }
   // Setup yield/continue point:
   //
   //   ...
@@ -4805,7 +4804,8 @@
   // BuildGraphOfFunction will create a dispatch that jumps to
   // Continuation<:await_jump_var> upon entry to the function.
   //
-  Fragment instructions = IntConstant(yield_continuations().length() + 1);
+  const intptr_t new_yield_pos = yield_continuations().length() + 1;
+  Fragment instructions = IntConstant(new_yield_pos);
   instructions +=
       StoreLocal(TokenPosition::kNoSource, scopes()->yield_jump_variable);
   instructions += Drop();
@@ -4814,7 +4814,7 @@
       StoreLocal(TokenPosition::kNoSource, scopes()->yield_context_variable);
   instructions += Drop();
   instructions += BuildExpression();  // read expression.
-  instructions += Return(position);
+  instructions += Return(position, new_yield_pos);
 
   // Note: DropTempsInstr serves as an anchor instruction. It will not
   // be linked into the resulting graph.
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
index ba3c765..f04298e 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
@@ -21,11 +21,9 @@
 
 class StreamingFlowGraphBuilder : public KernelReaderHelper {
  public:
-  StreamingFlowGraphBuilder(
-      FlowGraphBuilder* flow_graph_builder,
-      const ExternalTypedData& data,
-      intptr_t data_program_offset,
-      GrowableObjectArray* record_yield_positions = nullptr)
+  StreamingFlowGraphBuilder(FlowGraphBuilder* flow_graph_builder,
+                            const ExternalTypedData& data,
+                            intptr_t data_program_offset)
       : KernelReaderHelper(
             flow_graph_builder->zone_,
             &flow_graph_builder->translation_helper_,
@@ -43,8 +41,7 @@
         inferred_type_metadata_helper_(this),
         procedure_attributes_metadata_helper_(this),
         call_site_attributes_metadata_helper_(this, &type_translator_),
-        closure_owner_(Object::Handle(flow_graph_builder->zone_)),
-        record_yield_positions_(record_yield_positions) {}
+        closure_owner_(Object::Handle(flow_graph_builder->zone_)) {}
 
   virtual ~StreamingFlowGraphBuilder() {}
 
@@ -157,7 +154,8 @@
   void InlineBailout(const char* reason);
   Fragment DebugStepCheck(TokenPosition position);
   Fragment LoadLocal(LocalVariable* variable);
-  Fragment Return(TokenPosition position);
+  Fragment Return(TokenPosition position,
+                  intptr_t yield_index = RawPcDescriptors::kInvalidYieldIndex);
   Fragment PushArgument();
   Fragment EvaluateAssertion();
   Fragment RethrowException(TokenPosition position, int catch_try_index);
@@ -368,7 +366,6 @@
   ProcedureAttributesMetadataHelper procedure_attributes_metadata_helper_;
   CallSiteAttributesMetadataHelper call_site_attributes_metadata_helper_;
   Object& closure_owner_;
-  GrowableObjectArray* record_yield_positions_;
 
   friend class KernelLoader;
 
diff --git a/runtime/vm/compiler/frontend/kernel_fingerprints.cc b/runtime/vm/compiler/frontend/kernel_fingerprints.cc
index bf79b16..cf6f13d 100644
--- a/runtime/vm/compiler/frontend/kernel_fingerprints.cc
+++ b/runtime/vm/compiler/frontend/kernel_fingerprints.cc
@@ -246,7 +246,7 @@
       break;
     case kTypeParameterType: {
       Nullability nullability = ReadNullability();
-      BuildHash(nullability);
+      BuildHash(static_cast<uint32_t>(nullability));
       ReadUInt();                              // read index for parameter.
       CalculateOptionalDartTypeFingerprint();  // read bound bound.
       break;
@@ -269,7 +269,7 @@
 
 void KernelFingerprintHelper::CalculateInterfaceTypeFingerprint(bool simple) {
   Nullability nullability = ReadNullability();
-  BuildHash(nullability);
+  BuildHash(static_cast<uint32_t>(nullability));
   NameIndex kernel_class = ReadCanonicalNameReference();
   ASSERT(H.IsClass(kernel_class));
   const String& class_name = H.DartClassName(kernel_class);
@@ -285,7 +285,7 @@
 
 void KernelFingerprintHelper::CalculateFunctionTypeFingerprint(bool simple) {
   Nullability nullability = ReadNullability();
-  BuildHash(nullability);
+  BuildHash(static_cast<uint32_t>(nullability));
 
   if (!simple) {
     CalculateTypeParametersListFingerprint();  // read type_parameters.
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index a3877ad..1426f50 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -40,8 +40,7 @@
     bool optimizing,
     intptr_t osr_id,
     intptr_t first_block_id,
-    bool inlining_unchecked_entry,
-    GrowableObjectArray* record_yield_positions)
+    bool inlining_unchecked_entry)
     : BaseFlowGraphBuilder(parsed_function,
                            first_block_id - 1,
                            osr_id,
@@ -69,7 +68,6 @@
       catch_block_(NULL) {
   const Script& script =
       Script::Handle(Z, parsed_function->function().script());
-  record_yield_positions_ = record_yield_positions;
   H.InitFromScript(script);
 }
 
@@ -411,15 +409,21 @@
   }
 }
 
-Fragment FlowGraphBuilder::LoadLateInstanceField(const Field& field,
-                                                 LocalVariable* instance) {
+Fragment FlowGraphBuilder::LoadLateField(const Field& field,
+                                         LocalVariable* instance) {
   Fragment instructions;
   TargetEntryInstr *is_uninitialized, *is_initialized;
   const TokenPosition position = field.token_pos();
+  const bool is_static = field.is_static();
 
   // Check whether the field has been initialized already.
-  instructions += LoadLocal(instance);
-  instructions += LoadField(field);
+  if (is_static) {
+    instructions += Constant(field);
+    instructions += LoadStaticField();
+  } else {
+    instructions += LoadLocal(instance);
+    instructions += LoadField(field);
+  }
   LocalVariable* temp = MakeTemporary();
   instructions += LoadLocal(temp);
   instructions += Constant(Object::sentinel());
@@ -436,14 +440,18 @@
     Function& init_function =
         Function::ZoneHandle(Z, field.EnsureInitializerFunction());
     Fragment initialize(is_uninitialized);
-    initialize += LoadLocal(instance);  // For the store.
-    initialize += LoadLocal(instance);  // For the init call.
-    initialize += PushArgument();
-    initialize += StaticCall(position, init_function,
-                             /* argument_count = */ 1, ICData::kStatic);
+    if (is_static) {
+      initialize += StaticCall(position, init_function,
+                               /* argument_count = */ 0, ICData::kStatic);
+    } else {
+      initialize += LoadLocal(instance);
+      initialize += PushArgument();
+      initialize += StaticCall(position, init_function,
+                               /* argument_count = */ 1, ICData::kStatic);
+    }
     initialize += StoreLocal(position, temp);
-    initialize += StoreInstanceFieldGuarded(
-        field, StoreInstanceFieldInstr::Kind::kInitializing);
+    initialize += Drop();
+    initialize += StoreLateField(field, instance, temp);
     initialize += Goto(join);
   } else {
     // The field has no initializer, so throw a LateInitializationError.
@@ -460,112 +468,6 @@
   }
 
   // Now that the field has been initialized, load it.
-  instructions = Fragment(instructions.entry, join);
-
-  return instructions;
-}
-
-Fragment FlowGraphBuilder::LoadLateStaticField(const Field& field) {
-  Fragment instructions;
-
-  // Check whether the field has been initialized already.
-  TargetEntryInstr *is_uninitialized, *is_initialized;
-  const TokenPosition position = field.token_pos();
-  instructions += Constant(field);
-  instructions += LoadStaticField();
-  LocalVariable* temp = MakeTemporary();
-  instructions += LoadLocal(temp);
-  instructions += Constant(Object::sentinel());
-  instructions += BranchIfStrictEqual(&is_uninitialized, &is_initialized);
-
-  JoinEntryInstr* join = BuildJoinEntry();
-
-  if (field.has_initializer()) {
-    // has_nontrivial_initializer is required for EnsureInitializerFunction. The
-    // trivial initializer case is treated as a normal field.
-    ASSERT(field.has_nontrivial_initializer());
-
-    // If the field isn't initialized, call the initializer and set the field.
-    Function& init_function =
-        Function::ZoneHandle(Z, field.EnsureInitializerFunction());
-    Fragment initialize(is_uninitialized);
-    initialize += StaticCall(position, init_function,
-                             /* argument_count = */ 0, ICData::kStatic);
-    initialize += StoreLocal(position, temp);
-    initialize += StoreStaticField(position, field);
-    initialize += Goto(join);
-  } else {
-    // The field has no initializer, so throw a LateInitializationError.
-    Fragment initialize(is_uninitialized);
-    initialize += ThrowLateInitializationError(
-        position, String::ZoneHandle(Z, field.name()));
-    initialize += Goto(join);
-  }
-
-  {
-    // Already initialized, so there's nothing to do.
-    Fragment already_initialized(is_initialized);
-    already_initialized += Goto(join);
-  }
-
-  // Now that the field has been initialized, load it.
-  instructions = Fragment(instructions.entry, join);
-
-  return instructions;
-}
-
-Fragment FlowGraphBuilder::StoreLateInstanceField(const Field& field,
-                                                  LocalVariable* instance,
-                                                  LocalVariable* setter_value) {
-  // Implicit setters for non-final late fields are the same as non-late fields.
-  if (!field.is_final()) {
-    return StoreInstanceFieldGuarded(field,
-                                     StoreInstanceFieldInstr::Kind::kOther);
-  }
-
-  // If a late final field has an initializer, the setter always throws. This
-  // case is typically caught as a compile error, but there are ways to avoid
-  // that error, so we also need this runtime error.
-  const TokenPosition position = field.token_pos();
-  if (field.has_initializer()) {
-    Fragment instructions;
-    instructions += Drop();
-    instructions += Drop();
-    instructions += ThrowLateInitializationError(
-        position, String::ZoneHandle(Z, field.name()));
-    return instructions;
-  }
-
-  // Late final fields with no initializer can be written to once.
-  Fragment instructions;
-  TargetEntryInstr *is_uninitialized, *is_initialized;
-
-  // Check whether the field has been initialized already.
-  instructions += Drop();
-  instructions += LoadField(field);
-  instructions += Constant(Object::sentinel());
-  instructions += BranchIfStrictEqual(&is_uninitialized, &is_initialized);
-
-  JoinEntryInstr* join = BuildJoinEntry();
-
-  {
-    // If the field isn't initialized, set it to the new value.
-    Fragment initialize(is_uninitialized);
-    initialize += LoadLocal(instance);
-    initialize += LoadLocal(setter_value);
-    initialize +=
-        StoreInstanceFieldGuarded(field, StoreInstanceFieldInstr::Kind::kOther);
-    initialize += Goto(join);
-  }
-
-  {
-    // If the field is already initialized, throw a LateInitializationError.
-    Fragment already_initialized(is_initialized);
-    already_initialized += ThrowLateInitializationError(
-        position, String::ZoneHandle(Z, field.name()));
-    already_initialized += Goto(join);
-  }
-
   return Fragment(instructions.entry, join);
 }
 
@@ -593,6 +495,59 @@
   return instructions;
 }
 
+Fragment FlowGraphBuilder::StoreLateField(const Field& field,
+                                          LocalVariable* instance,
+                                          LocalVariable* setter_value) {
+  Fragment instructions;
+  TargetEntryInstr *is_uninitialized, *is_initialized;
+  const TokenPosition position = field.token_pos();
+  const bool is_static = field.is_static();
+  const bool is_final = field.is_final();
+
+  if (is_final) {
+    // Check whether the field has been initialized already.
+    if (is_static) {
+      instructions += Constant(field);
+      instructions += LoadStaticField();
+    } else {
+      instructions += LoadLocal(instance);
+      instructions += LoadField(field);
+    }
+    instructions += Constant(Object::sentinel());
+    instructions += BranchIfStrictEqual(&is_uninitialized, &is_initialized);
+    JoinEntryInstr* join = BuildJoinEntry();
+
+    {
+      // If the field isn't initialized, do nothing.
+      Fragment initialize(is_uninitialized);
+      initialize += Goto(join);
+    }
+
+    {
+      // If the field is already initialized, throw a LateInitializationError.
+      Fragment already_initialized(is_initialized);
+      already_initialized += ThrowLateInitializationError(
+          position, String::ZoneHandle(Z, field.name()));
+      already_initialized += Goto(join);
+    }
+
+    instructions = Fragment(instructions.entry, join);
+  }
+
+  if (!is_static) {
+    instructions += LoadLocal(instance);
+  }
+  instructions += LoadLocal(setter_value);
+  if (is_static) {
+    instructions += StoreStaticField(position, field);
+  } else {
+    instructions += StoreInstanceFieldGuarded(
+        field, StoreInstanceFieldInstr::Kind::kInitializing);
+  }
+
+  return instructions;
+}
+
 Fragment FlowGraphBuilder::InitInstanceField(const Field& field) {
   ASSERT(field.is_instance());
   ASSERT(field.needs_load_guard());
@@ -621,7 +576,8 @@
 }
 
 Fragment FlowGraphBuilder::Return(TokenPosition position,
-                                  bool omit_result_type_check /* = false */) {
+                                  bool omit_result_type_check,
+                                  intptr_t yield_index) {
   Fragment instructions;
   const Function& function = parsed_function_->function();
 
@@ -649,7 +605,7 @@
     instructions += Drop();
   }
 
-  instructions += BaseFlowGraphBuilder::Return(position);
+  instructions += BaseFlowGraphBuilder::Return(position, yield_index);
 
   return instructions;
 }
@@ -835,7 +791,7 @@
   // TODO(alexmarkov): refactor this - StreamingFlowGraphBuilder should not be
   //  used for bytecode functions.
   StreamingFlowGraphBuilder streaming_flow_graph_builder(
-      this, kernel_data, kernel_data_program_offset, record_yield_positions_);
+      this, kernel_data, kernel_data_program_offset);
   return streaming_flow_graph_builder.BuildGraph();
 }
 
@@ -863,7 +819,7 @@
 
 bool FlowGraphBuilder::IsRecognizedMethodForFlowGraph(
     const Function& function) {
-  const MethodRecognizer::Kind kind = MethodRecognizer::RecognizeKind(function);
+  const MethodRecognizer::Kind kind = function.recognized_kind();
 
   switch (kind) {
     case MethodRecognizer::kTypedData_ByteDataView_factory:
@@ -965,7 +921,7 @@
   Fragment body(instruction_cursor);
   body += CheckStackOverflowInPrologue(function.token_pos());
 
-  const MethodRecognizer::Kind kind = MethodRecognizer::RecognizeKind(function);
+  const MethodRecognizer::Kind kind = function.recognized_kind();
   switch (kind) {
     case MethodRecognizer::kTypedData_ByteDataView_factory:
       body += BuildTypedDataViewFactoryConstructor(function, kByteDataViewCid);
@@ -2275,8 +2231,7 @@
           Function::ZoneHandle(Z, function.parent_function());
       const Class& owner = Class::ZoneHandle(Z, parent.Owner());
       AbstractType& type = AbstractType::ZoneHandle(Z);
-      type = Type::New(owner, TypeArguments::Handle(Z), owner.token_pos(),
-                       Heap::kOld);
+      type = Type::New(owner, TypeArguments::Handle(Z), owner.token_pos());
       type = ClassFinalizer::FinalizeType(owner, type);
       body += Constant(type);
     } else {
@@ -2674,30 +2629,44 @@
       body += CheckAssignable(setter_value->type(), setter_value->name(),
                               AssertAssignableInstr::kParameterCheck);
     }
-    if (is_method) {
-      if (field.is_late()) {
-        body += StoreLateInstanceField(
-            field, parsed_function_->ParameterVariable(0), setter_value);
+    if (field.is_late()) {
+      if (is_method) {
+        body += Drop();
+      }
+      body += Drop();
+      if (field.is_final() && field.has_initializer()) {
+        body += ThrowLateInitializationError(
+            field.token_pos(), String::ZoneHandle(Z, field.name()));
       } else {
-        body += StoreInstanceFieldGuarded(
-            field, StoreInstanceFieldInstr::Kind::kOther);
+        body += StoreLateField(
+            field, is_method ? parsed_function_->ParameterVariable(0) : nullptr,
+            setter_value);
       }
     } else {
-      body += StoreStaticField(TokenPosition::kNoSource, field);
+      if (is_method) {
+        body += StoreInstanceFieldGuarded(
+            field, StoreInstanceFieldInstr::Kind::kOther);
+      } else {
+        body += StoreStaticField(TokenPosition::kNoSource, field);
+      }
     }
     body += NullConstant();
   } else if (is_method) {
-#if !defined(PRODUCT)
     if (field.needs_load_guard()) {
+#if defined(PRODUCT)
+      UNREACHABLE();
+#else
       ASSERT(Isolate::Current()->HasAttemptedReload());
       body += LoadLocal(parsed_function_->ParameterVariable(0));
       body += InitInstanceField(field);
-      // TODO(rmacnak): Type check.
-    }
+
+      body += LoadLocal(parsed_function_->ParameterVariable(0));
+      body += LoadField(field);
+      body += CheckAssignable(AbstractType::Handle(Z, field.type()),
+                              Symbols::FunctionResult());
 #endif
-    if (field.is_late() && !field.has_trivial_initializer()) {
-      body +=
-          LoadLateInstanceField(field, parsed_function_->ParameterVariable(0));
+    } else if (field.is_late() && !field.has_trivial_initializer()) {
+      body += LoadLateField(field, parsed_function_->ParameterVariable(0));
     } else {
       body += LoadLocal(parsed_function_->ParameterVariable(0));
       body += LoadField(field);
@@ -2718,7 +2687,7 @@
       // In NNBD mode, static fields act like late fields regardless of whether
       // they're marked late. The only behavioural difference is in compile
       // errors that are handled by the front end.
-      body += LoadLateStaticField(field);
+      body += LoadLateField(field, /* instance = */ nullptr);
     } else {
       ASSERT(field.has_nontrivial_initializer());
       body += Constant(field);
@@ -2726,6 +2695,15 @@
       body += Constant(field);
       body += LoadStaticField();
     }
+    if (field.needs_load_guard()) {
+#if defined(PRODUCT)
+      UNREACHABLE();
+#else
+      ASSERT(Isolate::Current()->HasAttemptedReload());
+      body += CheckAssignable(AbstractType::Handle(Z, field.type()),
+                              Symbols::FunctionResult());
+#endif
+    }
   }
   body += Return(TokenPosition::kNoSource);
 
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.h b/runtime/vm/compiler/frontend/kernel_to_il.h
index 434106f..29893dc 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.h
+++ b/runtime/vm/compiler/frontend/kernel_to_il.h
@@ -56,8 +56,7 @@
                    bool optimizing,
                    intptr_t osr_id,
                    intptr_t first_block_id = 1,
-                   bool inlining_unchecked_entry = false,
-                   GrowableObjectArray* record_yield_position = nullptr);
+                   bool inlining_unchecked_entry = false);
   virtual ~FlowGraphBuilder();
 
   FlowGraph* BuildGraph();
@@ -132,15 +131,16 @@
 
   Fragment RethrowException(TokenPosition position, int catch_try_index);
   Fragment LoadLocal(LocalVariable* variable);
-  Fragment LoadLateInstanceField(const Field& field, LocalVariable* instance);
-  Fragment LoadLateStaticField(const Field& field);
-  Fragment StoreLateInstanceField(const Field& field,
-                                  LocalVariable* instance,
-                                  LocalVariable* setter_value);
+  Fragment LoadLateField(const Field& field, LocalVariable* instance);
+  Fragment StoreLateField(const Field& field,
+                          LocalVariable* instance,
+                          LocalVariable* setter_value);
   Fragment InitInstanceField(const Field& field);
   Fragment InitStaticField(const Field& field);
   Fragment NativeCall(const String* name, const Function* function);
-  Fragment Return(TokenPosition position, bool omit_result_type_check = false);
+  Fragment Return(TokenPosition position,
+                  bool omit_result_type_check = false,
+                  intptr_t yield_index = RawPcDescriptors::kInvalidYieldIndex);
   void SetResultTypeForStaticCall(StaticCallInstr* call,
                                   const Function& target,
                                   intptr_t argument_count,
@@ -387,8 +387,6 @@
 
   ActiveClass active_class_;
 
-  GrowableObjectArray* record_yield_positions_;
-
   friend class BreakableBlock;
   friend class CatchBlock;
   friend class ProgramState;
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.cc b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
index f02eb50..1886995 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.cc
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
@@ -1966,9 +1966,11 @@
     case kDynamicType:
     case kVoidType:
     case kBottomType:
-    case kNeverType:
       // those contain nothing.
       return;
+    case kNeverType:
+      ReadNullability();
+      return;
     case kInterfaceType:
       SkipInterfaceType(false);
       return;
@@ -2767,12 +2769,12 @@
       result_ = Object::void_type().raw();
       break;
     case kBottomType:
-      result_ =
-          Class::Handle(Z, I->object_store()->null_class()).DeclarationType();
-      // We set the nullability of Null to kNullable, even in legacy mode.
+      result_ = I->object_store()->null_type();
       ASSERT(result_.IsNullable());
       break;
     case kNeverType:
+      helper_->ReadNullability();
+      // Ignore nullability, as Never type is non-nullable.
       result_ = Object::never_type().raw();
       break;
     case kInterfaceType:
@@ -2814,18 +2816,13 @@
   if (simple) {
     if (finalize_ || klass.is_type_finalized()) {
       // Fast path for non-generic types: retrieve or populate the class's only
-      // canonical type, which is its declaration type.
-      result_ = klass.DeclarationType();
-      // TODO(regis): Remove this workaround once nullability of Null provided
-      // by CFE is always kNullable.
-      if (!result_.IsNullType()) {
-        result_ = Type::Cast(result_).ToNullability(nullability, Heap::kOld);
-      }
+      // canonical type (as long as only one nullability variant is used), which
+      // is its declaration type.
+      result_ = klass.DeclarationType(nullability);
     } else {
       // Note that the type argument vector is not yet extended.
-      result_ =
-          Type::New(klass, Object::null_type_arguments(), klass.token_pos());
-      Type::Cast(result_).set_nullability(nullability);
+      result_ = Type::New(klass, Object::null_type_arguments(),
+                          klass.token_pos(), nullability);
     }
     return;
   }
@@ -2930,8 +2927,7 @@
   finalize_ = finalize;
 
   Type& signature_type =
-      Type::ZoneHandle(Z, signature_function.SignatureType());
-  signature_type.set_nullability(nullability);
+      Type::ZoneHandle(Z, signature_function.SignatureType(nullability));
 
   if (finalize_) {
     signature_type ^=
diff --git a/runtime/vm/compiler/frontend/scope_builder.cc b/runtime/vm/compiler/frontend/scope_builder.cc
index 8e1302a..a1d2df1 100644
--- a/runtime/vm/compiler/frontend/scope_builder.cc
+++ b/runtime/vm/compiler/frontend/scope_builder.cc
@@ -1295,9 +1295,11 @@
     case kDynamicType:
     case kVoidType:
     case kBottomType:
-    case kNeverType:
       // those contain nothing.
       return;
+    case kNeverType:
+      helper_.ReadNullability();
+      return;
     case kInterfaceType:
       VisitInterfaceType(false);
       return;
diff --git a/runtime/vm/compiler/graph_intrinsifier.cc b/runtime/vm/compiler/graph_intrinsifier.cc
index 9485474..e0c0d63 100644
--- a/runtime/vm/compiler/graph_intrinsifier.cc
+++ b/runtime/vm/compiler/graph_intrinsifier.cc
@@ -17,10 +17,10 @@
 #include "vm/compiler/compiler_pass.h"
 #include "vm/compiler/jit/compiler.h"
 #include "vm/cpu.h"
+#include "vm/flag_list.h"
 
 namespace dart {
 
-DECLARE_FLAG(bool, code_comments);
 DECLARE_FLAG(bool, print_flow_graph);
 DECLARE_FLAG(bool, print_flow_graph_optimized);
 
@@ -299,8 +299,8 @@
       break;
     case kTypedDataInt32ArrayCid:
     case kExternalTypedDataInt32ArrayCid:
-    // Use same truncating unbox-instruction for int32 and uint32.
-    FALL_THROUGH;
+      // Use same truncating unbox-instruction for int32 and uint32.
+      FALL_THROUGH;
     case kTypedDataUint32ArrayCid:
     case kExternalTypedDataUint32ArrayCid:
       // Supports smi and mint, slow-case for bigints.
diff --git a/runtime/vm/compiler/jit/compiler.cc b/runtime/vm/compiler/jit/compiler.cc
index e52a66f..549c396 100644
--- a/runtime/vm/compiler/jit/compiler.cc
+++ b/runtime/vm/compiler/jit/compiler.cc
@@ -1017,41 +1017,6 @@
   }
 }
 
-void Compiler::ComputeYieldPositions(const Function& function) {
-  Thread* thread = Thread::Current();
-  Zone* zone = thread->zone();
-  const Script& script = Script::Handle(zone, function.script());
-  Array& yield_position_map = Array::Handle(zone, script.yield_positions());
-  if (yield_position_map.IsNull()) {
-    yield_position_map = HashTables::New<UnorderedHashMap<SmiTraits>>(4);
-  }
-  UnorderedHashMap<SmiTraits> function_map(yield_position_map.raw());
-  Smi& key = Smi::Handle(zone, Smi::New(function.token_pos().value()));
-
-  if (function_map.ContainsKey(key)) {
-    ASSERT(function_map.Release().raw() == yield_position_map.raw());
-    return;
-  }
-
-  CompilerState state(thread);
-  LongJumpScope jump;
-  auto& array = GrowableObjectArray::Handle(zone, GrowableObjectArray::New());
-  if (setjmp(*jump.Set()) == 0) {
-    ParsedFunction* parsed_function =
-        new ParsedFunction(thread, Function::ZoneHandle(zone, function.raw()));
-    ZoneGrowableArray<const ICData*>* ic_data_array =
-        new ZoneGrowableArray<const ICData*>();
-    kernel::FlowGraphBuilder builder(parsed_function, ic_data_array, nullptr,
-                                     /* not inlining */ nullptr, false,
-                                     Compiler::kNoOSRDeoptId, 1, false, &array);
-    builder.BuildGraph();
-  }
-  function_map.UpdateOrInsert(key, array);
-  // Release and store back to script
-  yield_position_map = function_map.Release().raw();
-  script.set_yield_positions(yield_position_map);
-}
-
 RawError* Compiler::CompileAllFunctions(const Class& cls) {
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
@@ -1452,10 +1417,6 @@
   UNREACHABLE();
 }
 
-void Compiler::ComputeYieldPositions(const Function& function) {
-  UNREACHABLE();
-}
-
 RawError* Compiler::CompileAllFunctions(const Class& cls) {
   FATAL1("Attempt to compile class %s", cls.ToCString());
   return Error::null();
diff --git a/runtime/vm/compiler/jit/compiler.h b/runtime/vm/compiler/jit/compiler.h
index 94e22b7..123e16a 100644
--- a/runtime/vm/compiler/jit/compiler.h
+++ b/runtime/vm/compiler/jit/compiler.h
@@ -108,8 +108,6 @@
   // Generates local var descriptors and sets it in 'code'. Do not call if the
   // local var descriptor already exists.
   static void ComputeLocalVarDescriptors(const Code& code);
-  // Collect yield positions for function and store into its script object
-  static void ComputeYieldPositions(const Function& function);
 
   // Eagerly compiles all functions in a class.
   //
diff --git a/runtime/vm/compiler/jit/jit_call_specializer.cc b/runtime/vm/compiler/jit/jit_call_specializer.cc
index a13bffc..8d6b46c 100644
--- a/runtime/vm/compiler/jit/jit_call_specializer.cc
+++ b/runtime/vm/compiler/jit/jit_call_specializer.cc
@@ -126,9 +126,7 @@
       has_one_target = PolymorphicInstanceCallInstr::ComputeRuntimeType(
                            targets) != Type::null();
     } else {
-      const bool polymorphic_target =
-          MethodRecognizer::PolymorphicTarget(target);
-      has_one_target = !polymorphic_target;
+      has_one_target = !target.is_polymorphic_target();
     }
   }
 
diff --git a/runtime/vm/compiler/method_recognizer.cc b/runtime/vm/compiler/method_recognizer.cc
index 07f910f..535e332 100644
--- a/runtime/vm/compiler/method_recognizer.cc
+++ b/runtime/vm/compiler/method_recognizer.cc
@@ -10,18 +10,9 @@
 
 namespace dart {
 
-MethodRecognizer::Kind MethodRecognizer::RecognizeKind(
-    const Function& function) {
-  return function.recognized_kind();
-}
-
-bool MethodRecognizer::PolymorphicTarget(const Function& function) {
-  return function.is_polymorphic_target();
-}
-
 intptr_t MethodRecognizer::NumArgsCheckedForStaticCall(
     const Function& function) {
-  switch (RecognizeKind(function)) {
+  switch (function.recognized_kind()) {
     case MethodRecognizer::kDoubleFromInteger:
     case MethodRecognizer::kMathMin:
     case MethodRecognizer::kMathMax:
@@ -176,14 +167,22 @@
   return kIllegalCid;
 }
 
-#define KIND_TO_STRING(class_name, function_name, enum_name, fp) #enum_name,
-static const char* recognized_list_method_name[] = {
-    "Unknown", RECOGNIZED_LIST(KIND_TO_STRING)};
-#undef KIND_TO_STRING
+static const struct {
+  const char* const class_name;
+  const char* const function_name;
+  const char* const enum_name;
+  const uint32_t fp;
+} recognized_methods[MethodRecognizer::kNumRecognizedMethods] = {
+    {"", "", "Unknown", 0},
+#define RECOGNIZE_METHOD(class_name, function_name, enum_name, fp)             \
+  {"" #class_name, "" #function_name, #enum_name, fp},
+    RECOGNIZED_LIST(RECOGNIZE_METHOD)
+#undef RECOGNIZE_METHOD
+};
 
 const char* MethodRecognizer::KindToCString(Kind kind) {
-  if (kind > kUnknown && kind < kNumRecognizedMethods)
-    return recognized_list_method_name[kind];
+  if (kind >= kUnknown && kind < kNumRecognizedMethods)
+    return recognized_methods[kind].enum_name;
   return "?";
 }
 
@@ -193,18 +192,22 @@
   Libraries(&libs);
   Function& func = Function::Handle();
 
-#define SET_RECOGNIZED_KIND(class_name, function_name, enum_name, fp)          \
-  func = Library::GetFunction(libs, #class_name, #function_name);              \
-  if (!func.IsNull()) {                                                        \
-    CHECK_FINGERPRINT3(func, class_name, function_name, enum_name, fp);        \
-    func.set_recognized_kind(k##enum_name);                                    \
-  } else if (!FLAG_precompiled_mode) {                                         \
-    OS::PrintErr("Missing %s::%s\n", #class_name, #function_name);             \
-    UNREACHABLE();                                                             \
+  for (intptr_t i = 1; i < MethodRecognizer::kNumRecognizedMethods; i++) {
+    const MethodRecognizer::Kind kind = static_cast<MethodRecognizer::Kind>(i);
+    func = Library::GetFunction(libs, recognized_methods[i].class_name,
+                                recognized_methods[i].function_name);
+    if (!func.IsNull()) {
+      CHECK_FINGERPRINT3(func, recognized_methods[i].class_name,
+                         recognized_methods[i].function_name,
+                         recognized_methods[i].enum_name,
+                         recognized_methods[i].fp);
+      func.set_recognized_kind(kind);
+    } else if (!FLAG_precompiled_mode) {
+      FATAL2("Missing %s::%s\n", recognized_methods[i].class_name,
+             recognized_methods[i].function_name);
+    }
   }
 
-  RECOGNIZED_LIST(SET_RECOGNIZED_KIND);
-
 #define SET_FUNCTION_BIT(class_name, function_name, dest, fp, setter, value)   \
   func = Library::GetFunction(libs, #class_name, #function_name);              \
   if (!func.IsNull()) {                                                        \
@@ -236,24 +239,6 @@
   libs->Add(&Library::ZoneHandle(Library::AsyncLibrary()));
   libs->Add(&Library::ZoneHandle(Library::FfiLibrary()));
 }
-
-RawGrowableObjectArray* MethodRecognizer::QueryRecognizedMethods(Zone* zone) {
-  const GrowableObjectArray& methods =
-      GrowableObjectArray::Handle(zone, GrowableObjectArray::New());
-  Function& func = Function::Handle(zone);
-
-  GrowableArray<Library*> libs(3);
-  Libraries(&libs);
-
-#define ADD_RECOGNIZED_METHOD(class_name, function_name, enum_name, fp)        \
-  func = Library::GetFunction(libs, #class_name, #function_name);              \
-  methods.Add(func);
-
-  RECOGNIZED_LIST(ADD_RECOGNIZED_METHOD);
-#undef ADD_RECOGNIZED_METHOD
-
-  return methods.raw();
-}
 #endif  // !defined(DART_PRECOMPILED_RUNTIME)
 
 Token::Kind MethodTokenRecognizer::RecognizeTokenKind(const String& name_) {
@@ -315,10 +300,10 @@
   {Symbols::k##symbol##Id, cid, fp, #symbol ", " #cid},  // NOLINT
 
 static struct {
-  intptr_t symbol_id;
-  intptr_t cid;
-  uint32_t finger_print;
-  const char* name;
+  const intptr_t symbol_id;
+  const intptr_t cid;
+  const uint32_t finger_print;
+  const char* const name;
 } factory_recognizer_list[] = {RECOGNIZED_LIST_FACTORY_LIST(RECOGNIZE_FACTORY){
     Symbols::kIllegal, -1, 0, NULL}};
 
diff --git a/runtime/vm/compiler/method_recognizer.h b/runtime/vm/compiler/method_recognizer.h
index 74889ff..1cf5d5b 100644
--- a/runtime/vm/compiler/method_recognizer.h
+++ b/runtime/vm/compiler/method_recognizer.h
@@ -34,8 +34,6 @@
         kNumRecognizedMethods
   };
 
-  static Kind RecognizeKind(const Function& function);
-  static bool PolymorphicTarget(const Function& function);
   static intptr_t NumArgsCheckedForStaticCall(const Function& function);
 
   // Try to find an annotation of the form
@@ -59,7 +57,6 @@
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
   static void InitializeState();
-  static RawGrowableObjectArray* QueryRecognizedMethods(Zone* zone);
 
  private:
   static void Libraries(GrowableArray<Library*>* libs);
diff --git a/runtime/vm/compiler/runtime_api.h b/runtime/vm/compiler/runtime_api.h
index f6f7eaa..ef2b206 100644
--- a/runtime/vm/compiler/runtime_api.h
+++ b/runtime/vm/compiler/runtime_api.h
@@ -699,6 +699,7 @@
   static word call_native_through_safepoint_stub_offset();
   static word call_native_through_safepoint_entry_point_offset();
 
+  static word bootstrap_native_wrapper_entry_point_offset();
   static word no_scope_native_wrapper_entry_point_offset();
   static word auto_scope_native_wrapper_entry_point_offset();
 
@@ -764,25 +765,12 @@
   static word shared_class_table_offset();
 #if !defined(PRODUCT)
   static word ClassOffsetFor(intptr_t cid);
-  static word StateOffsetFor(intptr_t cid);
-  static word NewSpaceCounterOffsetFor(intptr_t cid);
-  static word NewSpaceSizeOffsetFor(intptr_t cid);
   static word SharedTableOffsetFor();
   static word SizeOffsetFor(intptr_t cid, bool is_new);
 #endif  // !defined(PRODUCT)
   static const word kSizeOfClassPairLog2;
 };
 
-#if !defined(PRODUCT)
-class ClassHeapStats : public AllStatic {
- public:
-  static word TraceAllocationMask();
-  static word state_offset();
-  static word allocated_since_gc_new_space_offset();
-  static word allocated_size_since_gc_new_space_offset();
-};
-#endif  // !defined(PRODUCT)
-
 class Instructions : public AllStatic {
  public:
   static const word kMonomorphicEntryOffsetJIT;
diff --git a/runtime/vm/compiler/runtime_offsets_extracted.h b/runtime/vm/compiler/runtime_offsets_extracted.h
index 4c3564a..6fe7f06 100644
--- a/runtime/vm/compiler/runtime_offsets_extracted.h
+++ b/runtime/vm/compiler/runtime_offsets_extracted.h
@@ -77,14 +77,7 @@
 static constexpr dart::compiler::target::word
     Class_type_arguments_field_offset_in_words_offset = 96;
 static constexpr dart::compiler::target::word
-    ClassHeapStats_TraceAllocationMask = 1;
-static constexpr dart::compiler::target::word
-    ClassHeapStats_allocated_since_gc_new_space_offset = 48;
-static constexpr dart::compiler::target::word
-    ClassHeapStats_allocated_size_since_gc_new_space_offset = 52;
-static constexpr dart::compiler::target::word ClassHeapStats_state_offset = 160;
-static constexpr dart::compiler::target::word
-    ClassTable_shared_class_table_offset = 20;
+    ClassTable_shared_class_table_offset = 16;
 static constexpr dart::compiler::target::word ClassTable_table_offset = 8;
 static constexpr dart::compiler::target::word
     SharedClassTable_class_heap_stats_table_offset = 0;
@@ -145,7 +138,7 @@
 static constexpr dart::compiler::target::word Isolate_default_tag_offset = 24;
 static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 28;
 static constexpr dart::compiler::target::word Isolate_object_store_offset = 36;
-static constexpr dart::compiler::target::word Isolate_single_step_offset = 64;
+static constexpr dart::compiler::target::word Isolate_single_step_offset = 60;
 static constexpr dart::compiler::target::word Isolate_user_tag_offset = 16;
 static constexpr dart::compiler::target::word LinkedHashMap_data_offset = 16;
 static constexpr dart::compiler::target::word
@@ -193,11 +186,11 @@
 static constexpr dart::compiler::target::word String_length_offset = 4;
 static constexpr dart::compiler::target::word SubtypeTestCache_cache_offset = 4;
 static constexpr dart::compiler::target::word
-    Thread_AllocateArray_entry_point_offset = 292;
+    Thread_AllocateArray_entry_point_offset = 296;
 static constexpr dart::compiler::target::word Thread_active_exception_offset =
-    628;
-static constexpr dart::compiler::target::word Thread_active_stacktrace_offset =
     632;
+static constexpr dart::compiler::target::word Thread_active_stacktrace_offset =
+    636;
 static constexpr dart::compiler::target::word
     Thread_array_write_barrier_code_offset = 120;
 static constexpr dart::compiler::target::word
@@ -205,14 +198,16 @@
 static constexpr dart::compiler::target::word Thread_async_stack_trace_offset =
     88;
 static constexpr dart::compiler::target::word
-    Thread_auto_scope_native_wrapper_entry_point_offset = 252;
+    Thread_auto_scope_native_wrapper_entry_point_offset = 256;
 static constexpr dart::compiler::target::word Thread_bool_false_offset = 112;
 static constexpr dart::compiler::target::word Thread_bool_true_offset = 108;
 static constexpr dart::compiler::target::word
+    Thread_bootstrap_native_wrapper_entry_point_offset = 248;
+static constexpr dart::compiler::target::word
     Thread_call_to_runtime_entry_point_offset = 208;
 static constexpr dart::compiler::target::word
     Thread_call_to_runtime_stub_offset = 140;
-static constexpr dart::compiler::target::word Thread_dart_stream_offset = 664;
+static constexpr dart::compiler::target::word Thread_dart_stream_offset = 668;
 static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
     236;
 static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 164;
@@ -221,14 +216,14 @@
 static constexpr dart::compiler::target::word Thread_deoptimize_stub_offset =
     168;
 static constexpr dart::compiler::target::word Thread_double_abs_address_offset =
-    272;
+    276;
 static constexpr dart::compiler::target::word
-    Thread_double_negate_address_offset = 268;
+    Thread_double_negate_address_offset = 272;
 static constexpr dart::compiler::target::word Thread_end_offset = 64;
 static constexpr dart::compiler::target::word
     Thread_enter_safepoint_stub_offset = 188;
 static constexpr dart::compiler::target::word Thread_execution_state_offset =
-    648;
+    652;
 static constexpr dart::compiler::target::word
     Thread_exit_safepoint_stub_offset = 192;
 static constexpr dart::compiler::target::word
@@ -240,17 +235,17 @@
 static constexpr dart::compiler::target::word
     Thread_fix_callers_target_code_offset = 124;
 static constexpr dart::compiler::target::word
-    Thread_float_absolute_address_offset = 284;
+    Thread_float_absolute_address_offset = 288;
 static constexpr dart::compiler::target::word
-    Thread_float_negate_address_offset = 280;
+    Thread_float_negate_address_offset = 284;
 static constexpr dart::compiler::target::word Thread_float_not_address_offset =
-    276;
+    280;
 static constexpr dart::compiler::target::word
-    Thread_float_zerow_address_offset = 288;
+    Thread_float_zerow_address_offset = 292;
 static constexpr dart::compiler::target::word Thread_global_object_pool_offset =
-    636;
+    640;
 static constexpr dart::compiler::target::word
-    Thread_interpret_call_entry_point_offset = 256;
+    Thread_interpret_call_entry_point_offset = 260;
 static constexpr dart::compiler::target::word
     Thread_invoke_dart_code_from_bytecode_stub_offset = 136;
 static constexpr dart::compiler::target::word
@@ -271,7 +266,7 @@
 static constexpr dart::compiler::target::word
     Thread_monomorphic_miss_stub_offset = 160;
 static constexpr dart::compiler::target::word
-    Thread_no_scope_native_wrapper_entry_point_offset = 248;
+    Thread_no_scope_native_wrapper_entry_point_offset = 252;
 static constexpr dart::compiler::target::word
     Thread_null_error_shared_with_fpu_regs_entry_point_offset = 216;
 static constexpr dart::compiler::target::word
@@ -282,12 +277,12 @@
     Thread_null_error_shared_without_fpu_regs_stub_offset = 144;
 static constexpr dart::compiler::target::word Thread_object_null_offset = 104;
 static constexpr dart::compiler::target::word
-    Thread_predefined_symbols_address_offset = 260;
-static constexpr dart::compiler::target::word Thread_resume_pc_offset = 640;
+    Thread_predefined_symbols_address_offset = 264;
+static constexpr dart::compiler::target::word Thread_resume_pc_offset = 644;
 static constexpr dart::compiler::target::word
-    Thread_saved_shadow_call_stack_offset = 644;
+    Thread_saved_shadow_call_stack_offset = 648;
 static constexpr dart::compiler::target::word Thread_safepoint_state_offset =
-    652;
+    656;
 static constexpr dart::compiler::target::word
     Thread_slow_type_test_stub_offset = 180;
 static constexpr dart::compiler::target::word Thread_stack_limit_offset = 36;
@@ -318,7 +313,7 @@
     Thread_write_barrier_entry_point_offset = 200;
 static constexpr dart::compiler::target::word Thread_write_barrier_mask_offset =
     48;
-static constexpr dart::compiler::target::word Thread_callback_code_offset = 656;
+static constexpr dart::compiler::target::word Thread_callback_code_offset = 660;
 static constexpr dart::compiler::target::word TimelineStream_enabled_offset = 8;
 static constexpr dart::compiler::target::word TwoByteString_data_offset = 12;
 static constexpr dart::compiler::target::word Type_arguments_offset = 16;
@@ -344,15 +339,15 @@
 static constexpr dart::compiler::target::word TypeArguments_element_size = 4;
 static constexpr dart::compiler::target::word ClassTable_elements_start_offset =
     0;
-static constexpr dart::compiler::target::word ClassTable_element_size = 168;
+static constexpr dart::compiler::target::word ClassTable_element_size = 1;
 static constexpr dart::compiler::target::word Code_entry_point_offset[] = {
     4, 12, 8, 16};
 static constexpr dart::compiler::target::word
     Code_function_entry_point_offset[] = {4, 8};
 static constexpr dart::compiler::target::word
     Thread_write_barrier_wrappers_thread_offset[] = {
-        592, 596, 600, 604, 608, -1, 612, 616,
-        620, 624, -1,  -1,  -1,  -1, -1,  -1};
+        596, 600, 604, 608, 612, -1, 616, 620,
+        624, 628, -1,  -1,  -1,  -1, -1,  -1};
 static constexpr dart::compiler::target::word Array_header_size = 12;
 static constexpr dart::compiler::target::word Context_header_size = 12;
 static constexpr dart::compiler::target::word Double_InstanceSize = 16;
@@ -438,14 +433,7 @@
 static constexpr dart::compiler::target::word
     Class_type_arguments_field_offset_in_words_offset = 180;
 static constexpr dart::compiler::target::word
-    ClassHeapStats_TraceAllocationMask = 1;
-static constexpr dart::compiler::target::word
-    ClassHeapStats_allocated_since_gc_new_space_offset = 96;
-static constexpr dart::compiler::target::word
-    ClassHeapStats_allocated_size_since_gc_new_space_offset = 104;
-static constexpr dart::compiler::target::word ClassHeapStats_state_offset = 272;
-static constexpr dart::compiler::target::word
-    ClassTable_shared_class_table_offset = 40;
+    ClassTable_shared_class_table_offset = 32;
 static constexpr dart::compiler::target::word ClassTable_table_offset = 16;
 static constexpr dart::compiler::target::word
     SharedClassTable_class_heap_stats_table_offset = 0;
@@ -506,7 +494,7 @@
 static constexpr dart::compiler::target::word Isolate_default_tag_offset = 48;
 static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 56;
 static constexpr dart::compiler::target::word Isolate_object_store_offset = 72;
-static constexpr dart::compiler::target::word Isolate_single_step_offset = 128;
+static constexpr dart::compiler::target::word Isolate_single_step_offset = 120;
 static constexpr dart::compiler::target::word Isolate_user_tag_offset = 32;
 static constexpr dart::compiler::target::word LinkedHashMap_data_offset = 32;
 static constexpr dart::compiler::target::word
@@ -554,11 +542,11 @@
 static constexpr dart::compiler::target::word String_length_offset = 8;
 static constexpr dart::compiler::target::word SubtypeTestCache_cache_offset = 8;
 static constexpr dart::compiler::target::word
-    Thread_AllocateArray_entry_point_offset = 568;
+    Thread_AllocateArray_entry_point_offset = 576;
 static constexpr dart::compiler::target::word Thread_active_exception_offset =
-    1256;
-static constexpr dart::compiler::target::word Thread_active_stacktrace_offset =
     1264;
+static constexpr dart::compiler::target::word Thread_active_stacktrace_offset =
+    1272;
 static constexpr dart::compiler::target::word
     Thread_array_write_barrier_code_offset = 224;
 static constexpr dart::compiler::target::word
@@ -566,14 +554,16 @@
 static constexpr dart::compiler::target::word Thread_async_stack_trace_offset =
     176;
 static constexpr dart::compiler::target::word
-    Thread_auto_scope_native_wrapper_entry_point_offset = 488;
+    Thread_auto_scope_native_wrapper_entry_point_offset = 496;
 static constexpr dart::compiler::target::word Thread_bool_false_offset = 208;
 static constexpr dart::compiler::target::word Thread_bool_true_offset = 200;
 static constexpr dart::compiler::target::word
+    Thread_bootstrap_native_wrapper_entry_point_offset = 480;
+static constexpr dart::compiler::target::word
     Thread_call_to_runtime_entry_point_offset = 400;
 static constexpr dart::compiler::target::word
     Thread_call_to_runtime_stub_offset = 264;
-static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1328;
+static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1336;
 static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
     456;
 static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 312;
@@ -582,14 +572,14 @@
 static constexpr dart::compiler::target::word Thread_deoptimize_stub_offset =
     320;
 static constexpr dart::compiler::target::word Thread_double_abs_address_offset =
-    528;
+    536;
 static constexpr dart::compiler::target::word
-    Thread_double_negate_address_offset = 520;
+    Thread_double_negate_address_offset = 528;
 static constexpr dart::compiler::target::word Thread_end_offset = 128;
 static constexpr dart::compiler::target::word
     Thread_enter_safepoint_stub_offset = 360;
 static constexpr dart::compiler::target::word Thread_execution_state_offset =
-    1296;
+    1304;
 static constexpr dart::compiler::target::word
     Thread_exit_safepoint_stub_offset = 368;
 static constexpr dart::compiler::target::word
@@ -601,17 +591,17 @@
 static constexpr dart::compiler::target::word
     Thread_fix_callers_target_code_offset = 232;
 static constexpr dart::compiler::target::word
-    Thread_float_absolute_address_offset = 552;
+    Thread_float_absolute_address_offset = 560;
 static constexpr dart::compiler::target::word
-    Thread_float_negate_address_offset = 544;
+    Thread_float_negate_address_offset = 552;
 static constexpr dart::compiler::target::word Thread_float_not_address_offset =
-    536;
+    544;
 static constexpr dart::compiler::target::word
-    Thread_float_zerow_address_offset = 560;
+    Thread_float_zerow_address_offset = 568;
 static constexpr dart::compiler::target::word Thread_global_object_pool_offset =
-    1272;
+    1280;
 static constexpr dart::compiler::target::word
-    Thread_interpret_call_entry_point_offset = 496;
+    Thread_interpret_call_entry_point_offset = 504;
 static constexpr dart::compiler::target::word
     Thread_invoke_dart_code_from_bytecode_stub_offset = 256;
 static constexpr dart::compiler::target::word
@@ -632,7 +622,7 @@
 static constexpr dart::compiler::target::word
     Thread_monomorphic_miss_stub_offset = 304;
 static constexpr dart::compiler::target::word
-    Thread_no_scope_native_wrapper_entry_point_offset = 480;
+    Thread_no_scope_native_wrapper_entry_point_offset = 488;
 static constexpr dart::compiler::target::word
     Thread_null_error_shared_with_fpu_regs_entry_point_offset = 416;
 static constexpr dart::compiler::target::word
@@ -643,12 +633,12 @@
     Thread_null_error_shared_without_fpu_regs_stub_offset = 272;
 static constexpr dart::compiler::target::word Thread_object_null_offset = 192;
 static constexpr dart::compiler::target::word
-    Thread_predefined_symbols_address_offset = 504;
-static constexpr dart::compiler::target::word Thread_resume_pc_offset = 1280;
+    Thread_predefined_symbols_address_offset = 512;
+static constexpr dart::compiler::target::word Thread_resume_pc_offset = 1288;
 static constexpr dart::compiler::target::word
-    Thread_saved_shadow_call_stack_offset = 1288;
+    Thread_saved_shadow_call_stack_offset = 1296;
 static constexpr dart::compiler::target::word Thread_safepoint_state_offset =
-    1304;
+    1312;
 static constexpr dart::compiler::target::word
     Thread_slow_type_test_stub_offset = 344;
 static constexpr dart::compiler::target::word Thread_stack_limit_offset = 72;
@@ -680,7 +670,7 @@
 static constexpr dart::compiler::target::word Thread_write_barrier_mask_offset =
     96;
 static constexpr dart::compiler::target::word Thread_callback_code_offset =
-    1312;
+    1320;
 static constexpr dart::compiler::target::word TimelineStream_enabled_offset =
     16;
 static constexpr dart::compiler::target::word TwoByteString_data_offset = 16;
@@ -707,15 +697,15 @@
 static constexpr dart::compiler::target::word TypeArguments_element_size = 8;
 static constexpr dart::compiler::target::word ClassTable_elements_start_offset =
     0;
-static constexpr dart::compiler::target::word ClassTable_element_size = 288;
+static constexpr dart::compiler::target::word ClassTable_element_size = 1;
 static constexpr dart::compiler::target::word Code_entry_point_offset[] = {
     8, 24, 16, 32};
 static constexpr dart::compiler::target::word
     Code_function_entry_point_offset[] = {8, 16};
 static constexpr dart::compiler::target::word
     Thread_write_barrier_wrappers_thread_offset[] = {
-        1168, 1176, 1184, 1192, -1,   -1,   1200, 1208,
-        1216, 1224, 1232, -1,   1240, 1248, -1,   -1};
+        1176, 1184, 1192, 1200, -1,   -1,   1208, 1216,
+        1224, 1232, 1240, -1,   1248, 1256, -1,   -1};
 static constexpr dart::compiler::target::word Array_header_size = 24;
 static constexpr dart::compiler::target::word Context_header_size = 24;
 static constexpr dart::compiler::target::word Double_InstanceSize = 16;
@@ -799,14 +789,7 @@
 static constexpr dart::compiler::target::word
     Class_type_arguments_field_offset_in_words_offset = 96;
 static constexpr dart::compiler::target::word
-    ClassHeapStats_TraceAllocationMask = 1;
-static constexpr dart::compiler::target::word
-    ClassHeapStats_allocated_since_gc_new_space_offset = 48;
-static constexpr dart::compiler::target::word
-    ClassHeapStats_allocated_size_since_gc_new_space_offset = 52;
-static constexpr dart::compiler::target::word ClassHeapStats_state_offset = 160;
-static constexpr dart::compiler::target::word
-    ClassTable_shared_class_table_offset = 20;
+    ClassTable_shared_class_table_offset = 16;
 static constexpr dart::compiler::target::word ClassTable_table_offset = 8;
 static constexpr dart::compiler::target::word
     SharedClassTable_class_heap_stats_table_offset = 0;
@@ -867,7 +850,7 @@
 static constexpr dart::compiler::target::word Isolate_default_tag_offset = 24;
 static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 28;
 static constexpr dart::compiler::target::word Isolate_object_store_offset = 36;
-static constexpr dart::compiler::target::word Isolate_single_step_offset = 64;
+static constexpr dart::compiler::target::word Isolate_single_step_offset = 60;
 static constexpr dart::compiler::target::word Isolate_user_tag_offset = 16;
 static constexpr dart::compiler::target::word LinkedHashMap_data_offset = 16;
 static constexpr dart::compiler::target::word
@@ -915,11 +898,11 @@
 static constexpr dart::compiler::target::word String_length_offset = 4;
 static constexpr dart::compiler::target::word SubtypeTestCache_cache_offset = 4;
 static constexpr dart::compiler::target::word
-    Thread_AllocateArray_entry_point_offset = 292;
+    Thread_AllocateArray_entry_point_offset = 296;
 static constexpr dart::compiler::target::word Thread_active_exception_offset =
-    592;
-static constexpr dart::compiler::target::word Thread_active_stacktrace_offset =
     596;
+static constexpr dart::compiler::target::word Thread_active_stacktrace_offset =
+    600;
 static constexpr dart::compiler::target::word
     Thread_array_write_barrier_code_offset = 120;
 static constexpr dart::compiler::target::word
@@ -927,14 +910,16 @@
 static constexpr dart::compiler::target::word Thread_async_stack_trace_offset =
     88;
 static constexpr dart::compiler::target::word
-    Thread_auto_scope_native_wrapper_entry_point_offset = 252;
+    Thread_auto_scope_native_wrapper_entry_point_offset = 256;
 static constexpr dart::compiler::target::word Thread_bool_false_offset = 112;
 static constexpr dart::compiler::target::word Thread_bool_true_offset = 108;
 static constexpr dart::compiler::target::word
+    Thread_bootstrap_native_wrapper_entry_point_offset = 248;
+static constexpr dart::compiler::target::word
     Thread_call_to_runtime_entry_point_offset = 208;
 static constexpr dart::compiler::target::word
     Thread_call_to_runtime_stub_offset = 140;
-static constexpr dart::compiler::target::word Thread_dart_stream_offset = 628;
+static constexpr dart::compiler::target::word Thread_dart_stream_offset = 632;
 static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
     236;
 static constexpr dart::compiler::target::word Thread_optimize_stub_offset = 164;
@@ -943,14 +928,14 @@
 static constexpr dart::compiler::target::word Thread_deoptimize_stub_offset =
     168;
 static constexpr dart::compiler::target::word Thread_double_abs_address_offset =
-    272;
+    276;
 static constexpr dart::compiler::target::word
-    Thread_double_negate_address_offset = 268;
+    Thread_double_negate_address_offset = 272;
 static constexpr dart::compiler::target::word Thread_end_offset = 64;
 static constexpr dart::compiler::target::word
     Thread_enter_safepoint_stub_offset = 188;
 static constexpr dart::compiler::target::word Thread_execution_state_offset =
-    612;
+    616;
 static constexpr dart::compiler::target::word
     Thread_exit_safepoint_stub_offset = 192;
 static constexpr dart::compiler::target::word
@@ -962,17 +947,17 @@
 static constexpr dart::compiler::target::word
     Thread_fix_callers_target_code_offset = 124;
 static constexpr dart::compiler::target::word
-    Thread_float_absolute_address_offset = 284;
+    Thread_float_absolute_address_offset = 288;
 static constexpr dart::compiler::target::word
-    Thread_float_negate_address_offset = 280;
+    Thread_float_negate_address_offset = 284;
 static constexpr dart::compiler::target::word Thread_float_not_address_offset =
-    276;
+    280;
 static constexpr dart::compiler::target::word
-    Thread_float_zerow_address_offset = 288;
+    Thread_float_zerow_address_offset = 292;
 static constexpr dart::compiler::target::word Thread_global_object_pool_offset =
-    600;
+    604;
 static constexpr dart::compiler::target::word
-    Thread_interpret_call_entry_point_offset = 256;
+    Thread_interpret_call_entry_point_offset = 260;
 static constexpr dart::compiler::target::word
     Thread_invoke_dart_code_from_bytecode_stub_offset = 136;
 static constexpr dart::compiler::target::word
@@ -993,7 +978,7 @@
 static constexpr dart::compiler::target::word
     Thread_monomorphic_miss_stub_offset = 160;
 static constexpr dart::compiler::target::word
-    Thread_no_scope_native_wrapper_entry_point_offset = 248;
+    Thread_no_scope_native_wrapper_entry_point_offset = 252;
 static constexpr dart::compiler::target::word
     Thread_null_error_shared_with_fpu_regs_entry_point_offset = 216;
 static constexpr dart::compiler::target::word
@@ -1004,12 +989,12 @@
     Thread_null_error_shared_without_fpu_regs_stub_offset = 144;
 static constexpr dart::compiler::target::word Thread_object_null_offset = 104;
 static constexpr dart::compiler::target::word
-    Thread_predefined_symbols_address_offset = 260;
-static constexpr dart::compiler::target::word Thread_resume_pc_offset = 604;
+    Thread_predefined_symbols_address_offset = 264;
+static constexpr dart::compiler::target::word Thread_resume_pc_offset = 608;
 static constexpr dart::compiler::target::word
-    Thread_saved_shadow_call_stack_offset = 608;
+    Thread_saved_shadow_call_stack_offset = 612;
 static constexpr dart::compiler::target::word Thread_safepoint_state_offset =
-    616;
+    620;
 static constexpr dart::compiler::target::word
     Thread_slow_type_test_stub_offset = 180;
 static constexpr dart::compiler::target::word Thread_stack_limit_offset = 36;
@@ -1040,7 +1025,7 @@
     Thread_write_barrier_entry_point_offset = 200;
 static constexpr dart::compiler::target::word Thread_write_barrier_mask_offset =
     48;
-static constexpr dart::compiler::target::word Thread_callback_code_offset = 620;
+static constexpr dart::compiler::target::word Thread_callback_code_offset = 624;
 static constexpr dart::compiler::target::word TimelineStream_enabled_offset = 8;
 static constexpr dart::compiler::target::word TwoByteString_data_offset = 12;
 static constexpr dart::compiler::target::word Type_arguments_offset = 16;
@@ -1066,7 +1051,7 @@
 static constexpr dart::compiler::target::word TypeArguments_element_size = 4;
 static constexpr dart::compiler::target::word ClassTable_elements_start_offset =
     0;
-static constexpr dart::compiler::target::word ClassTable_element_size = 168;
+static constexpr dart::compiler::target::word ClassTable_element_size = 1;
 static constexpr dart::compiler::target::word Code_entry_point_offset[] = {
     4, 12, 8, 16};
 static constexpr dart::compiler::target::word
@@ -1156,14 +1141,7 @@
 static constexpr dart::compiler::target::word
     Class_type_arguments_field_offset_in_words_offset = 180;
 static constexpr dart::compiler::target::word
-    ClassHeapStats_TraceAllocationMask = 1;
-static constexpr dart::compiler::target::word
-    ClassHeapStats_allocated_since_gc_new_space_offset = 96;
-static constexpr dart::compiler::target::word
-    ClassHeapStats_allocated_size_since_gc_new_space_offset = 104;
-static constexpr dart::compiler::target::word ClassHeapStats_state_offset = 272;
-static constexpr dart::compiler::target::word
-    ClassTable_shared_class_table_offset = 40;
+    ClassTable_shared_class_table_offset = 32;
 static constexpr dart::compiler::target::word ClassTable_table_offset = 16;
 static constexpr dart::compiler::target::word
     SharedClassTable_class_heap_stats_table_offset = 0;
@@ -1224,7 +1202,7 @@
 static constexpr dart::compiler::target::word Isolate_default_tag_offset = 48;
 static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 56;
 static constexpr dart::compiler::target::word Isolate_object_store_offset = 72;
-static constexpr dart::compiler::target::word Isolate_single_step_offset = 128;
+static constexpr dart::compiler::target::word Isolate_single_step_offset = 120;
 static constexpr dart::compiler::target::word Isolate_user_tag_offset = 32;
 static constexpr dart::compiler::target::word LinkedHashMap_data_offset = 32;
 static constexpr dart::compiler::target::word
@@ -1272,7 +1250,7 @@
 static constexpr dart::compiler::target::word String_length_offset = 8;
 static constexpr dart::compiler::target::word SubtypeTestCache_cache_offset = 8;
 static constexpr dart::compiler::target::word
-    Thread_AllocateArray_entry_point_offset = 568;
+    Thread_AllocateArray_entry_point_offset = 576;
 static constexpr dart::compiler::target::word Thread_active_exception_offset =
     1344;
 static constexpr dart::compiler::target::word Thread_active_stacktrace_offset =
@@ -1284,10 +1262,12 @@
 static constexpr dart::compiler::target::word Thread_async_stack_trace_offset =
     176;
 static constexpr dart::compiler::target::word
-    Thread_auto_scope_native_wrapper_entry_point_offset = 488;
+    Thread_auto_scope_native_wrapper_entry_point_offset = 496;
 static constexpr dart::compiler::target::word Thread_bool_false_offset = 208;
 static constexpr dart::compiler::target::word Thread_bool_true_offset = 200;
 static constexpr dart::compiler::target::word
+    Thread_bootstrap_native_wrapper_entry_point_offset = 480;
+static constexpr dart::compiler::target::word
     Thread_call_to_runtime_entry_point_offset = 400;
 static constexpr dart::compiler::target::word
     Thread_call_to_runtime_stub_offset = 264;
@@ -1300,9 +1280,9 @@
 static constexpr dart::compiler::target::word Thread_deoptimize_stub_offset =
     320;
 static constexpr dart::compiler::target::word Thread_double_abs_address_offset =
-    528;
+    536;
 static constexpr dart::compiler::target::word
-    Thread_double_negate_address_offset = 520;
+    Thread_double_negate_address_offset = 528;
 static constexpr dart::compiler::target::word Thread_end_offset = 128;
 static constexpr dart::compiler::target::word
     Thread_enter_safepoint_stub_offset = 360;
@@ -1319,17 +1299,17 @@
 static constexpr dart::compiler::target::word
     Thread_fix_callers_target_code_offset = 232;
 static constexpr dart::compiler::target::word
-    Thread_float_absolute_address_offset = 552;
+    Thread_float_absolute_address_offset = 560;
 static constexpr dart::compiler::target::word
-    Thread_float_negate_address_offset = 544;
+    Thread_float_negate_address_offset = 552;
 static constexpr dart::compiler::target::word Thread_float_not_address_offset =
-    536;
+    544;
 static constexpr dart::compiler::target::word
-    Thread_float_zerow_address_offset = 560;
+    Thread_float_zerow_address_offset = 568;
 static constexpr dart::compiler::target::word Thread_global_object_pool_offset =
     1360;
 static constexpr dart::compiler::target::word
-    Thread_interpret_call_entry_point_offset = 496;
+    Thread_interpret_call_entry_point_offset = 504;
 static constexpr dart::compiler::target::word
     Thread_invoke_dart_code_from_bytecode_stub_offset = 256;
 static constexpr dart::compiler::target::word
@@ -1350,7 +1330,7 @@
 static constexpr dart::compiler::target::word
     Thread_monomorphic_miss_stub_offset = 304;
 static constexpr dart::compiler::target::word
-    Thread_no_scope_native_wrapper_entry_point_offset = 480;
+    Thread_no_scope_native_wrapper_entry_point_offset = 488;
 static constexpr dart::compiler::target::word
     Thread_null_error_shared_with_fpu_regs_entry_point_offset = 416;
 static constexpr dart::compiler::target::word
@@ -1361,7 +1341,7 @@
     Thread_null_error_shared_without_fpu_regs_stub_offset = 272;
 static constexpr dart::compiler::target::word Thread_object_null_offset = 192;
 static constexpr dart::compiler::target::word
-    Thread_predefined_symbols_address_offset = 504;
+    Thread_predefined_symbols_address_offset = 512;
 static constexpr dart::compiler::target::word Thread_resume_pc_offset = 1368;
 static constexpr dart::compiler::target::word
     Thread_saved_shadow_call_stack_offset = 1376;
@@ -1425,16 +1405,16 @@
 static constexpr dart::compiler::target::word TypeArguments_element_size = 8;
 static constexpr dart::compiler::target::word ClassTable_elements_start_offset =
     0;
-static constexpr dart::compiler::target::word ClassTable_element_size = 288;
+static constexpr dart::compiler::target::word ClassTable_element_size = 1;
 static constexpr dart::compiler::target::word Code_entry_point_offset[] = {
     8, 24, 16, 32};
 static constexpr dart::compiler::target::word
     Code_function_entry_point_offset[] = {8, 16};
 static constexpr dart::compiler::target::word
     Thread_write_barrier_wrappers_thread_offset[] = {
-        1168, 1176, 1184, 1192, 1200, 1208, 1216, 1224, 1232, 1240, 1248,
-        1256, 1264, 1272, 1280, -1,   -1,   -1,   -1,   1288, 1296, 1304,
-        1312, 1320, 1328, 1336, -1,   -1,   -1,   -1,   -1,   -1};
+        1176, 1184, 1192, 1200, 1208, 1216, 1224, 1232, 1240, 1248, 1256,
+        1264, 1272, 1280, 1288, -1,   -1,   -1,   -1,   1296, 1304, 1312,
+        -1,   1320, 1328, 1336, -1,   -1,   -1,   -1,   -1,   -1};
 static constexpr dart::compiler::target::word Array_header_size = 24;
 static constexpr dart::compiler::target::word Context_header_size = 24;
 static constexpr dart::compiler::target::word Double_InstanceSize = 16;
diff --git a/runtime/vm/compiler/runtime_offsets_list.h b/runtime/vm/compiler/runtime_offsets_list.h
index dc49487..7631752 100644
--- a/runtime/vm/compiler/runtime_offsets_list.h
+++ b/runtime/vm/compiler/runtime_offsets_list.h
@@ -65,11 +65,6 @@
   FIELD(Class, num_type_arguments_offset)                                      \
   FIELD(Class, super_type_offset)                                              \
   FIELD(Class, type_arguments_field_offset_in_words_offset)                    \
-  NOT_IN_PRODUCT(FIELD(ClassHeapStats, TraceAllocationMask))                   \
-  NOT_IN_PRODUCT(FIELD(ClassHeapStats, allocated_since_gc_new_space_offset))   \
-  NOT_IN_PRODUCT(                                                              \
-      FIELD(ClassHeapStats, allocated_size_since_gc_new_space_offset))         \
-  NOT_IN_PRODUCT(FIELD(ClassHeapStats, state_offset))                          \
   FIELD(ClassTable, shared_class_table_offset)                                 \
   FIELD(ClassTable, table_offset)                                              \
   NOT_IN_PRODUCT(FIELD(SharedClassTable, class_heap_stats_table_offset))       \
@@ -155,6 +150,7 @@
   FIELD(Thread, auto_scope_native_wrapper_entry_point_offset)                  \
   FIELD(Thread, bool_false_offset)                                             \
   FIELD(Thread, bool_true_offset)                                              \
+  FIELD(Thread, bootstrap_native_wrapper_entry_point_offset)                   \
   FIELD(Thread, call_to_runtime_entry_point_offset)                            \
   FIELD(Thread, call_to_runtime_stub_offset)                                   \
   FIELD(Thread, dart_stream_offset)                                            \
@@ -236,14 +232,6 @@
   ARRAY(Array, element_offset)                                                 \
   ARRAY(TypeArguments, type_at_offset)                                         \
   NOT_IN_PRODUCT(ARRAY(ClassTable, ClassOffsetFor))                            \
-  NOT_IN_PRODUCT(ARRAY_STRUCTFIELD(                                            \
-      ClassTable, NewSpaceCounterOffsetFor, ClassOffsetFor,                    \
-      ClassHeapStats::allocated_since_gc_new_space_offset()))                  \
-  NOT_IN_PRODUCT(ARRAY_STRUCTFIELD(ClassTable, StateOffsetFor, ClassOffsetFor, \
-                                   ClassHeapStats::state_offset()))            \
-  NOT_IN_PRODUCT(ARRAY_STRUCTFIELD(                                            \
-      ClassTable, NewSpaceSizeOffsetFor, ClassOffsetFor,                       \
-      ClassHeapStats::allocated_size_since_gc_new_space_offset()))             \
   RANGE(Code, entry_point_offset, CodeEntryKind, CodeEntryKind::kNormal,       \
         CodeEntryKind::kMonomorphicUnchecked,                                  \
         [](CodeEntryKind value) { return true; })                              \
diff --git a/runtime/vm/compiler/stub_code_compiler_arm.cc b/runtime/vm/compiler/stub_code_compiler_arm.cc
index f506902..901940d 100644
--- a/runtime/vm/compiler/stub_code_compiler_arm.cc
+++ b/runtime/vm/compiler/stub_code_compiler_arm.cc
@@ -602,83 +602,10 @@
 //   R2 : address of first argument in argument array.
 //   R1 : argc_tag including number of arguments and function kind.
 void StubCodeCompiler::GenerateCallBootstrapNativeStub(Assembler* assembler) {
-  const intptr_t thread_offset = target::NativeArguments::thread_offset();
-  const intptr_t argc_tag_offset = target::NativeArguments::argc_tag_offset();
-  const intptr_t argv_offset = target::NativeArguments::argv_offset();
-  const intptr_t retval_offset = target::NativeArguments::retval_offset();
-
-  __ EnterStubFrame();
-
-  // Save exit frame information to enable stack walking as we are about
-  // to transition to native code.
-  __ StoreToOffset(kWord, FP, THR,
-                   target::Thread::top_exit_frame_info_offset());
-
-#if defined(DEBUG)
-  {
-    Label ok;
-    // Check that we are always entering from Dart code.
-    __ LoadFromOffset(kWord, R8, THR, target::Thread::vm_tag_offset());
-    __ CompareImmediate(R8, VMTag::kDartCompiledTagId);
-    __ b(&ok, EQ);
-    __ Stop("Not coming from Dart code.");
-    __ Bind(&ok);
-  }
-#endif
-
-  // Mark that the thread is executing native code.
-  __ StoreToOffset(kWord, R9, THR, target::Thread::vm_tag_offset());
-
-  // Reserve space for the native arguments structure passed on the stack (the
-  // outgoing pointer parameter to the native arguments structure is passed in
-  // R0) and align frame before entering the C++ world.
-  __ ReserveAlignedFrameSpace(target::NativeArguments::StructSize());
-
-  // Initialize target::NativeArguments structure and call native function.
-  // Registers R0, R1, R2, and R3 are used.
-
-  ASSERT(thread_offset == 0 * target::kWordSize);
-  // Set thread in NativeArgs.
-  __ mov(R0, Operand(THR));
-
-  // There are no native calls to closures, so we do not need to set the tag
-  // bits kClosureFunctionBit and kInstanceFunctionBit in argc_tag_.
-  ASSERT(argc_tag_offset == 1 * target::kWordSize);
-  // Set argc in target::NativeArguments: R1 already contains argc.
-
-  ASSERT(argv_offset == 2 * target::kWordSize);
-  // Set argv in target::NativeArguments: R2 already contains argv.
-
-  // Set retval in NativeArgs.
-  ASSERT(retval_offset == 3 * target::kWordSize);
-  __ add(R3, FP, Operand(2 * target::kWordSize));
-
-  // Passing the structure by value as in runtime calls would require changing
-  // Dart API for native functions.
-  // For now, space is reserved on the stack and we pass a pointer to it.
-  __ stm(IA, SP, (1 << R0) | (1 << R1) | (1 << R2) | (1 << R3));
-  __ mov(R0, Operand(SP));  // Pass the pointer to the target::NativeArguments.
-
-  // Call native function or redirection via simulator.
-  __ blx(R9);
-
-  // Mark that the thread is executing Dart code.
-  __ LoadImmediate(R2, VMTag::kDartCompiledTagId);
-  __ StoreToOffset(kWord, R2, THR, target::Thread::vm_tag_offset());
-
-  // Reset exit frame information in Isolate structure.
-  __ LoadImmediate(R2, 0);
-  __ StoreToOffset(kWord, R2, THR,
-                   target::Thread::top_exit_frame_info_offset());
-
-  // Restore the global object pool after returning from runtime (old space is
-  // moving, so the GOP could have been relocated).
-  if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
-    __ ldr(PP, Address(THR, target::Thread::global_object_pool_offset()));
-  }
-
-  __ LeaveStubFrame();
-  __ Ret();
+  GenerateCallNativeWithWrapperStub(
+      assembler,
+      Address(THR,
+              target::Thread::bootstrap_native_wrapper_entry_point_offset()));
 }
 
 // Input parameters:
@@ -1123,13 +1050,11 @@
 
   // Successfully allocated the object(s), now update top to point to
   // next object start and initialize the object.
-  NOT_IN_PRODUCT(__ LoadAllocationStatsAddress(R3, cid));
   __ str(NOTFP, Address(THR, target::Thread::top_offset()));
   __ add(R0, R0, Operand(kHeapObjectTag));
 
   // Initialize the tags.
   // R0: new object start as a tagged pointer.
-  // R3: allocation stats address.
   // NOTFP: new object end address.
   // R9: allocation size.
   {
@@ -1161,13 +1086,11 @@
 
   // Initialize all array elements to raw_null.
   // R0: new object start as a tagged pointer.
-  // R3: allocation stats address.
   // R8, R9: null
   // R4: iterator which initially points to the start of the variable
   // data area to be initialized.
   // NOTFP: new object end address.
   // R9: allocation size.
-  NOT_IN_PRODUCT(__ IncrementAllocationStatsWithSize(R3, R9));
 
   __ LoadObject(R8, NullObject());
   __ mov(R9, Operand(R8));
@@ -1518,7 +1441,6 @@
     // R1: number of context variables.
     // R2: object size.
     // R3: next object start.
-    NOT_IN_PRODUCT(__ LoadAllocationStatsAddress(R4, cid));
     __ str(R3, Address(THR, target::Thread::top_offset()));
     __ add(R0, R0, Operand(kHeapObjectTag));
 
@@ -1527,7 +1449,6 @@
     // R1: number of context variables.
     // R2: object size.
     // R3: next object start.
-    // R4: allocation stats address.
     const intptr_t shift = target::RawObject::kTagBitsSizeTagPos -
                            target::ObjectAlignment::kObjectAlignmentLog2;
     __ CompareImmediate(R2, target::RawObject::kSizeTagMaxSizeTag);
@@ -1549,7 +1470,6 @@
     // R1: number of context variables as integer value (not object).
     // R2: object size.
     // R3: next object start.
-    // R4: allocation stats address.
     __ str(R1, FieldAddress(R0, target::Context::num_variables_offset()));
 
     // Setup the parent field.
@@ -1557,7 +1477,6 @@
     // R1: number of context variables.
     // R2: object size.
     // R3: next object start.
-    // R4: allocation stats address.
     __ LoadObject(R8, NullObject());
     __ MoveRegister(R9, R8);  // Needed for InitializeFieldsNoBarrier.
     __ StoreIntoObjectNoBarrier(
@@ -1569,12 +1488,10 @@
     // R2: object size.
     // R3: next object start.
     // R8, R9: raw null.
-    // R4: allocation stats address.
     Label loop;
     __ AddImmediate(NOTFP, R0,
                     target::Context::variable_offset(0) - kHeapObjectTag);
     __ InitializeFieldsNoBarrier(R0, NOTFP, R3, R8, R9);
-    NOT_IN_PRODUCT(__ IncrementAllocationStatsWithSize(R4, R2));
 
     // Done allocating and initializing the context.
     // R0: new object.
@@ -1849,12 +1766,6 @@
     }
     __ str(kEndOfInstanceReg, Address(THR, target::Thread::top_offset()));
 
-    // Load the address of the allocation stats table. We split up the load
-    // and the increment so that the dependent load is not too nearby.
-    NOT_IN_PRODUCT(static Register kAllocationStatsReg = R4);
-    NOT_IN_PRODUCT(__ LoadAllocationStatsAddress(kAllocationStatsReg,
-                                                 target::Class::GetId(cls)));
-
     // Set the tags.
     ASSERT(target::Class::GetId(cls) != kIllegalCid);
     const uint32_t tags = target::MakeTagWordForNewSpaceObject(
@@ -1888,10 +1799,6 @@
           kInstanceReg, FieldAddress(kInstanceReg, offset), kTypeArgumentsReg);
     }
 
-    // Update allocation stats.
-    NOT_IN_PRODUCT(__ IncrementAllocationStats(kAllocationStatsReg,
-                                               target::Class::GetId(cls)));
-
     __ Ret();
     __ Bind(&slow_case);
   }
diff --git a/runtime/vm/compiler/stub_code_compiler_arm64.cc b/runtime/vm/compiler/stub_code_compiler_arm64.cc
index 688e60b..afebf6d 100644
--- a/runtime/vm/compiler/stub_code_compiler_arm64.cc
+++ b/runtime/vm/compiler/stub_code_compiler_arm64.cc
@@ -147,9 +147,8 @@
   __ mov(SP, CSP);
   __ mov(CSP, R25);
 
-  // Refresh write barrier mask.
-  __ ldr(BARRIER_MASK,
-         Address(THR, target::Thread::write_barrier_mask_offset()));
+  // Refresh pinned registers values (inc. write barrier mask and null object).
+  __ RestorePinnedRegisters();
 
   // Retval is next to 1st argument.
   // Mark that the thread is executing Dart code.
@@ -624,9 +623,8 @@
   __ mov(SP, CSP);
   __ mov(CSP, R25);
 
-  // Refresh write barrier mask.
-  __ ldr(BARRIER_MASK,
-         Address(THR, target::Thread::write_barrier_mask_offset()));
+  // Refresh pinned registers values (inc. write barrier mask and null object).
+  __ RestorePinnedRegisters();
 
   // Mark that the thread is executing Dart code.
   __ LoadImmediate(R2, VMTag::kDartCompiledTagId);
@@ -667,98 +665,10 @@
 //   R2 : address of first argument in argument array.
 //   R1 : argc_tag including number of arguments and function kind.
 void StubCodeCompiler::GenerateCallBootstrapNativeStub(Assembler* assembler) {
-  const intptr_t thread_offset = target::NativeArguments::thread_offset();
-  const intptr_t argc_tag_offset = target::NativeArguments::argc_tag_offset();
-  const intptr_t argv_offset = target::NativeArguments::argv_offset();
-  const intptr_t retval_offset = target::NativeArguments::retval_offset();
-
-  __ EnterStubFrame();
-
-  // Save exit frame information to enable stack walking as we are about
-  // to transition to native code.
-  __ StoreToOffset(FP, THR, target::Thread::top_exit_frame_info_offset());
-
-#if defined(DEBUG)
-  {
-    Label ok;
-    // Check that we are always entering from Dart code.
-    __ LoadFromOffset(R6, THR, target::Thread::vm_tag_offset());
-    __ CompareImmediate(R6, VMTag::kDartCompiledTagId);
-    __ b(&ok, EQ);
-    __ Stop("Not coming from Dart code.");
-    __ Bind(&ok);
-  }
-#endif
-
-  // Mark that the thread is executing native code.
-  __ StoreToOffset(R5, THR, target::Thread::vm_tag_offset());
-
-  // Reserve space for the native arguments structure passed on the stack (the
-  // outgoing pointer parameter to the native arguments structure is passed in
-  // R0) and align frame before entering the C++ world.
-  __ ReserveAlignedFrameSpace(target::NativeArguments::StructSize());
-
-  // Initialize target::NativeArguments structure and call native function.
-  // Registers R0, R1, R2, and R3 are used.
-
-  ASSERT(thread_offset == 0 * target::kWordSize);
-  // Set thread in NativeArgs.
-  __ mov(R0, THR);
-
-  // There are no native calls to closures, so we do not need to set the tag
-  // bits kClosureFunctionBit and kInstanceFunctionBit in argc_tag_.
-  ASSERT(argc_tag_offset == 1 * target::kWordSize);
-  // Set argc in target::NativeArguments: R1 already contains argc.
-
-  ASSERT(argv_offset == 2 * target::kWordSize);
-  // Set argv in target::NativeArguments: R2 already contains argv.
-
-  // Set retval in NativeArgs.
-  ASSERT(retval_offset == 3 * target::kWordSize);
-  __ AddImmediate(R3, FP, 2 * target::kWordSize);
-
-  // Passing the structure by value as in runtime calls would require changing
-  // Dart API for native functions.
-  // For now, space is reserved on the stack and we pass a pointer to it.
-  __ StoreToOffset(R0, SP, thread_offset);
-  __ StoreToOffset(R1, SP, argc_tag_offset);
-  __ StoreToOffset(R2, SP, argv_offset);
-  __ StoreToOffset(R3, SP, retval_offset);
-  __ mov(R0, SP);  // Pass the pointer to the target::NativeArguments.
-
-  // We are entering runtime code, so the C stack pointer must be restored from
-  // the stack limit to the top of the stack. We cache the stack limit address
-  // in the Dart SP register, which is callee-saved in the C ABI.
-  __ mov(R25, CSP);
-  __ mov(CSP, SP);
-
-  // Call native function or redirection via simulator.
-  __ blr(R5);
-
-  // Restore SP and CSP.
-  __ mov(SP, CSP);
-  __ mov(CSP, R25);
-
-  // Refresh write barrier mask.
-  __ ldr(BARRIER_MASK,
-         Address(THR, target::Thread::write_barrier_mask_offset()));
-
-  // Mark that the thread is executing Dart code.
-  __ LoadImmediate(R2, VMTag::kDartCompiledTagId);
-  __ StoreToOffset(R2, THR, target::Thread::vm_tag_offset());
-
-  // Reset exit frame information in Isolate structure.
-  __ StoreToOffset(ZR, THR, target::Thread::top_exit_frame_info_offset());
-
-  // Restore the global object pool after returning from runtime (old space is
-  // moving, so the GOP could have been relocated).
-  if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
-    __ ldr(PP, Address(THR, target::Thread::global_object_pool_offset()));
-    __ sub(PP, PP, Operand(kHeapObjectTag));  // Pool in PP is untagged!
-  }
-
-  __ LeaveStubFrame();
-  __ ret();
+  GenerateCallNativeWithWrapperStub(
+      assembler,
+      Address(THR,
+              target::Thread::bootstrap_native_wrapper_entry_point_offset()));
 }
 
 // Input parameters:
@@ -1225,7 +1135,6 @@
   // R7: potential next object start.
   __ str(R7, Address(THR, target::Thread::top_offset()));
   __ add(R0, R0, Operand(kHeapObjectTag));
-  NOT_IN_PRODUCT(__ UpdateAllocationStatsWithSize(cid, R3));
 
   // R0: new object start as a tagged pointer.
   // R1: array element type.
@@ -1268,13 +1177,12 @@
   __ AddImmediate(R1, R0, target::Array::data_offset() - kHeapObjectTag);
   // R1: iterator which initially points to the start of the variable
   // data area to be initialized.
-  __ LoadObject(TMP, NullObject());
   Label loop, done;
   __ Bind(&loop);
   // TODO(cshapiro): StoreIntoObjectNoBarrier
   __ CompareRegisters(R1, R7);
   __ b(&done, CS);
-  __ str(TMP, Address(R1));  // Store if unsigned lower.
+  __ str(NULL_REG, Address(R1));  // Store if unsigned lower.
   __ AddImmediate(R1, target::kWordSize);
   __ b(&loop);  // Loop until R1 == R7.
   __ Bind(&done);
@@ -1346,9 +1254,8 @@
     __ mov(THR, R3);
   }
 
-  // Refresh write barrier mask.
-  __ ldr(BARRIER_MASK,
-         Address(THR, target::Thread::write_barrier_mask_offset()));
+  // Refresh pinned registers values (inc. write barrier mask and null object).
+  __ RestorePinnedRegisters();
 
   // Save the current VMTag on the stack.
   __ LoadFromOffset(R4, THR, target::Thread::vm_tag_offset());
@@ -1498,9 +1405,8 @@
     __ mov(THR, R3);
   }
 
-  // Refresh write barrier mask.
-  __ ldr(BARRIER_MASK,
-         Address(THR, target::Thread::write_barrier_mask_offset()));
+  // Refresh pinned registers values (inc. write barrier mask and null object).
+  __ RestorePinnedRegisters();
 
   // Save the current VMTag on the stack.
   __ LoadFromOffset(R4, THR, target::Thread::vm_tag_offset());
@@ -1648,7 +1554,6 @@
     // R3: next object start.
     __ str(R3, Address(THR, target::Thread::top_offset()));
     __ add(R0, R0, Operand(kHeapObjectTag));
-    NOT_IN_PRODUCT(__ UpdateAllocationStatsWithSize(cid, R2));
 
     // Calculate the size tag.
     // R0: new object.
@@ -2673,9 +2578,8 @@
   __ mov(SP, CSP);
   __ mov(CSP, R25);
 
-  // Refresh write barrier mask.
-  __ ldr(BARRIER_MASK,
-         Address(THR, target::Thread::write_barrier_mask_offset()));
+  // Refresh pinned registers values (inc. write barrier mask and null object).
+  __ RestorePinnedRegisters();
 
   // Mark that the thread is executing Dart code.
   __ LoadImmediate(R2, VMTag::kDartCompiledTagId);
@@ -3162,8 +3066,8 @@
 #elif defined(USING_SHADOW_CALL_STACK)
 #error Unimplemented
 #endif
-  __ ldr(BARRIER_MASK,
-         Address(THR, target::Thread::write_barrier_mask_offset()));
+  // Refresh pinned registers values (inc. write barrier mask and null object).
+  __ RestorePinnedRegisters();
   // Set the tag.
   __ LoadImmediate(R2, VMTag::kDartCompiledTagId);
   __ StoreToOffset(R2, THR, target::Thread::vm_tag_offset());
diff --git a/runtime/vm/compiler/stub_code_compiler_ia32.cc b/runtime/vm/compiler/stub_code_compiler_ia32.cc
index 06817a0..8ed7559 100644
--- a/runtime/vm/compiler/stub_code_compiler_ia32.cc
+++ b/runtime/vm/compiler/stub_code_compiler_ia32.cc
@@ -417,67 +417,10 @@
 //   ECX : address of the native function to call.
 //   EDX : argc_tag including number of arguments and function kind.
 void StubCodeCompiler::GenerateCallBootstrapNativeStub(Assembler* assembler) {
-  const intptr_t native_args_struct_offset = target::kWordSize;
-  const intptr_t thread_offset =
-      target::NativeArguments::thread_offset() + native_args_struct_offset;
-  const intptr_t argc_tag_offset =
-      target::NativeArguments::argc_tag_offset() + native_args_struct_offset;
-  const intptr_t argv_offset =
-      target::NativeArguments::argv_offset() + native_args_struct_offset;
-  const intptr_t retval_offset =
-      target::NativeArguments::retval_offset() + native_args_struct_offset;
-
-  __ EnterStubFrame();
-
-  // Save exit frame information to enable stack walking as we are about
-  // to transition to dart VM code.
-  __ movl(Address(THR, target::Thread::top_exit_frame_info_offset()), EBP);
-
-#if defined(DEBUG)
-  {
-    Label ok;
-    // Check that we are always entering from Dart code.
-    __ cmpl(Assembler::VMTagAddress(), Immediate(VMTag::kDartCompiledTagId));
-    __ j(EQUAL, &ok, Assembler::kNearJump);
-    __ Stop("Not coming from Dart code.");
-    __ Bind(&ok);
-  }
-#endif
-
-  // Mark that the thread is executing native code.
-  __ movl(Assembler::VMTagAddress(), ECX);
-
-  // Reserve space for the native arguments structure, the outgoing parameter
-  // (pointer to the native arguments structure) and align frame before
-  // entering the C++ world.
-  __ AddImmediate(
-      ESP,
-      Immediate(-static_cast<int32_t>(target::NativeArguments::StructSize()) -
-                target::kWordSize));
-  if (OS::ActivationFrameAlignment() > 1) {
-    __ andl(ESP, Immediate(~(OS::ActivationFrameAlignment() - 1)));
-  }
-
-  // Pass NativeArguments structure by value and call native function.
-  __ movl(Address(ESP, thread_offset), THR);    // Set thread in NativeArgs.
-  __ movl(Address(ESP, argc_tag_offset), EDX);  // Set argc in NativeArguments.
-  __ movl(Address(ESP, argv_offset), EAX);      // Set argv in NativeArguments.
-  __ leal(EAX,
-          Address(EBP, 2 * target::kWordSize));  // Compute return value addr.
-  __ movl(Address(ESP, retval_offset), EAX);  // Set retval in NativeArguments.
-  __ leal(EAX,
-          Address(ESP, target::kWordSize));  // Pointer to the NativeArguments.
-  __ movl(Address(ESP, 0), EAX);  // Pass the pointer to the NativeArguments.
-  __ call(ECX);
-
-  __ movl(Assembler::VMTagAddress(), Immediate(VMTag::kDartCompiledTagId));
-
-  // Reset exit frame information in Isolate structure.
-  __ movl(Address(THR, target::Thread::top_exit_frame_info_offset()),
-          Immediate(0));
-
-  __ LeaveFrame();
-  __ ret();
+  GenerateCallNativeWithWrapperStub(
+      assembler,
+      Address(THR,
+              target::Thread::bootstrap_native_wrapper_entry_point_offset()));
 }
 
 // Input parameters:
@@ -877,7 +820,6 @@
   __ movl(Address(THR, target::Thread::top_offset()), EBX);
   __ subl(EBX, EAX);
   __ addl(EAX, Immediate(kHeapObjectTag));
-  NOT_IN_PRODUCT(__ UpdateAllocationStatsWithSize(cid, EBX, EDI));
 
   // Initialize the tags.
   // EAX: new object start as a tagged pointer.
@@ -1260,7 +1202,6 @@
     __ subl(EBX, EAX);
     __ addl(EAX, Immediate(kHeapObjectTag));
     // Generate isolate-independent code to allow sharing between isolates.
-    NOT_IN_PRODUCT(__ UpdateAllocationStatsWithSize(cid, EBX, EDI));
 
     // Calculate the size tag.
     // EAX: new object.
@@ -1531,7 +1472,6 @@
       __ j(ABOVE_EQUAL, &slow_case);
     }
     __ movl(Address(THR, target::Thread::top_offset()), EBX);
-    NOT_IN_PRODUCT(__ UpdateAllocationStats(target::Class::GetId(cls), ECX));
 
     // EAX: new object start (untagged).
     // EBX: next object start.
diff --git a/runtime/vm/compiler/stub_code_compiler_x64.cc b/runtime/vm/compiler/stub_code_compiler_x64.cc
index 5bdc6d2..b73316a 100644
--- a/runtime/vm/compiler/stub_code_compiler_x64.cc
+++ b/runtime/vm/compiler/stub_code_compiler_x64.cc
@@ -605,75 +605,10 @@
 //   RBX : address of the native function to call.
 //   R10 : argc_tag including number of arguments and function kind.
 void StubCodeCompiler::GenerateCallBootstrapNativeStub(Assembler* assembler) {
-  const intptr_t native_args_struct_offset = 0;
-  const intptr_t thread_offset =
-      target::NativeArguments::thread_offset() + native_args_struct_offset;
-  const intptr_t argc_tag_offset =
-      target::NativeArguments::argc_tag_offset() + native_args_struct_offset;
-  const intptr_t argv_offset =
-      target::NativeArguments::argv_offset() + native_args_struct_offset;
-  const intptr_t retval_offset =
-      target::NativeArguments::retval_offset() + native_args_struct_offset;
-
-  __ EnterStubFrame();
-
-  // Save exit frame information to enable stack walking as we are about
-  // to transition to native code.
-  __ movq(Address(THR, target::Thread::top_exit_frame_info_offset()), RBP);
-
-#if defined(DEBUG)
-  {
-    Label ok;
-    // Check that we are always entering from Dart code.
-    __ movq(R8, Immediate(VMTag::kDartCompiledTagId));
-    __ cmpq(R8, Assembler::VMTagAddress());
-    __ j(EQUAL, &ok, Assembler::kNearJump);
-    __ Stop("Not coming from Dart code.");
-    __ Bind(&ok);
-  }
-#endif
-
-  // Mark that the thread is executing native code.
-  __ movq(Assembler::VMTagAddress(), RBX);
-
-  // Reserve space for the native arguments structure passed on the stack (the
-  // outgoing pointer parameter to the native arguments structure is passed in
-  // RDI) and align frame before entering the C++ world.
-  __ subq(RSP, Immediate(target::NativeArguments::StructSize()));
-  if (OS::ActivationFrameAlignment() > 1) {
-    __ andq(RSP, Immediate(~(OS::ActivationFrameAlignment() - 1)));
-  }
-
-  // Pass target::NativeArguments structure by value and call native function.
-  __ movq(Address(RSP, thread_offset), THR);  // Set thread in NativeArgs.
-  __ movq(Address(RSP, argc_tag_offset),
-          R10);  // Set argc in target::NativeArguments.
-  __ movq(Address(RSP, argv_offset),
-          RAX);  // Set argv in target::NativeArguments.
-  __ leaq(RAX,
-          Address(RBP, 2 * target::kWordSize));  // Compute return value addr.
-  __ movq(Address(RSP, retval_offset),
-          RAX);  // Set retval in target::NativeArguments.
-
-  // Pass the pointer to the target::NativeArguments.
-  __ movq(CallingConventions::kArg1Reg, RSP);
-  __ CallCFunction(RBX);
-
-  // Mark that the thread is executing Dart code.
-  __ movq(Assembler::VMTagAddress(), Immediate(VMTag::kDartCompiledTagId));
-
-  // Reset exit frame information in Isolate structure.
-  __ movq(Address(THR, target::Thread::top_exit_frame_info_offset()),
-          Immediate(0));
-
-  // Restore the global object pool after returning from runtime (old space is
-  // moving, so the GOP could have been relocated).
-  if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
-    __ movq(PP, Address(THR, target::Thread::global_object_pool_offset()));
-  }
-
-  __ LeaveStubFrame();
-  __ ret();
+  GenerateCallNativeWithWrapperStub(
+      assembler,
+      Address(THR,
+              target::Thread::bootstrap_native_wrapper_entry_point_offset()));
 }
 
 // Input parameters:
@@ -1123,7 +1058,7 @@
   // next object start and initialize the object.
   __ movq(Address(THR, target::Thread::top_offset()), RCX);
   __ addq(RAX, Immediate(kHeapObjectTag));
-  NOT_IN_PRODUCT(__ UpdateAllocationStatsWithSize(cid, RDI));
+
   // Initialize the tags.
   // RAX: new object start as a tagged pointer.
   // RDI: allocation size.
@@ -1553,7 +1488,6 @@
     __ subq(R13, RAX);
     __ addq(RAX, Immediate(kHeapObjectTag));
     // Generate isolate-independent code to allow sharing between isolates.
-    NOT_IN_PRODUCT(__ UpdateAllocationStatsWithSize(cid, R13));
 
     // Calculate the size tag.
     // RAX: new object.
@@ -1871,7 +1805,6 @@
       __ j(ABOVE_EQUAL, &slow_case);
     }
     __ movq(Address(THR, target::Thread::top_offset()), RBX);
-    NOT_IN_PRODUCT(__ UpdateAllocationStats(target::Class::GetId(cls)));
 
     // RAX: new object start (untagged).
     // RBX: next object start.
diff --git a/runtime/vm/constants_arm64.cc b/runtime/vm/constants_arm64.cc
index 95a52c0..7248ef1 100644
--- a/runtime/vm/constants_arm64.cc
+++ b/runtime/vm/constants_arm64.cc
@@ -10,7 +10,7 @@
 const char* cpu_reg_names[kNumberOfCpuRegisters] = {
     "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",  "r8",  "r9",  "r10",
     "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21",
-    "r22", "r23", "r24", "ip0", "ip1", "pp",  "ctx", "fp",  "lr",  "r31",
+    "nr",  "r23", "r24", "ip0", "ip1", "pp",  "ctx", "fp",  "lr",  "r31",
 };
 
 const char* fpu_reg_names[kNumberOfFpuRegisters] = {
diff --git a/runtime/vm/constants_arm64.h b/runtime/vm/constants_arm64.h
index cca7779..d141f81 100644
--- a/runtime/vm/constants_arm64.h
+++ b/runtime/vm/constants_arm64.h
@@ -36,7 +36,7 @@
   R19 = 19,
   R20 = 20,
   R21 = 21,
-  R22 = 22,
+  R22 = 22,  // NULL_REG
   R23 = 23,
   R24 = 24,
   R25 = 25,
@@ -124,6 +124,7 @@
 const Register CALLEE_SAVED_TEMP = R19;
 const Register CALLEE_SAVED_TEMP2 = R20;
 const Register BARRIER_MASK = R28;
+const Register NULL_REG = R22;  // Caches NullObject() value.
 
 // ABI for catch-clause entry point.
 const Register kExceptionObjectReg = R0;
@@ -173,9 +174,9 @@
 const intptr_t kReservedCpuRegisters =
     (1 << SPREG) |  // Dart SP
     (1 << FPREG) | (1 << TMP) | (1 << TMP2) | (1 << PP) | (1 << THR) |
-    (1 << LR) | (1 << BARRIER_MASK) | (1 << R31) |  // C++ SP
+    (1 << LR) | (1 << BARRIER_MASK) | (1 << NULL_REG) | (1 << R31) |  // C++ SP
     (1 << R18);
-constexpr intptr_t kNumberOfReservedCpuRegisters = 10;
+constexpr intptr_t kNumberOfReservedCpuRegisters = 11;
 // CPU registers available to Dart allocator.
 const RegList kDartAvailableCpuRegs =
     kAllCpuRegistersList & ~kReservedCpuRegisters;
diff --git a/runtime/vm/constants_kbc.h b/runtime/vm/constants_kbc.h
index 025d22d..1c59cac 100644
--- a/runtime/vm/constants_kbc.h
+++ b/runtime/vm/constants_kbc.h
@@ -553,9 +553,9 @@
   V(UnusedOpcode079,                       0, RESV, ___, ___, ___)             \
   V(UnusedOpcode080,                       0, RESV, ___, ___, ___)             \
   V(UnusedOpcode081,                       0, RESV, ___, ___, ___)             \
-  V(UnusedOpcode082,                       0, RESV, ___, ___, ___)             \
-  V(UnusedOpcode083,                       0, RESV, ___, ___, ___)             \
-  V(UnusedOpcode084,                       0, RESV, ___, ___, ___)             \
+  V(JumpIfInitialized,                     T, ORDN, tgt, ___, ___)             \
+  V(JumpIfInitialized_Wide,                T, WIDE, tgt, ___, ___)             \
+  V(PushUninitializedSentinel,             0, ORDN, ___, ___, ___)             \
   V(Trap,                                  0, ORDN, ___, ___, ___)             \
   V(Entry,                                 D, ORDN, num, ___, ___)             \
   V(Entry_Wide,                            D, WIDE, num, ___, ___)             \
@@ -749,7 +749,7 @@
   // Maximum bytecode format version supported by VM.
   // The range of supported versions should include version produced by bytecode
   // generator (currentBytecodeFormatVersion in pkg/vm/lib/bytecode/dbc.dart).
-  static const intptr_t kMaxSupportedBytecodeFormatVersion = 26;
+  static const intptr_t kMaxSupportedBytecodeFormatVersion = 27;
 
   enum Opcode {
 #define DECLARE_BYTECODE(name, encoding, kind, op1, op2, op3) k##name,
@@ -887,6 +887,8 @@
       case KernelBytecode::kJumpIfNotNull_Wide:
       case KernelBytecode::kJumpIfUnchecked:
       case KernelBytecode::kJumpIfUnchecked_Wide:
+      case KernelBytecode::kJumpIfInitialized:
+      case KernelBytecode::kJumpIfInitialized_Wide:
         return true;
 
       default:
diff --git a/runtime/vm/cpu_arm.cc b/runtime/vm/cpu_arm.cc
index c3d91d4..4078722 100644
--- a/runtime/vm/cpu_arm.cc
+++ b/runtime/vm/cpu_arm.cc
@@ -175,7 +175,11 @@
              CpuInfo::FieldContains(kCpuInfoModel, "ARMv7")) {
     arm_version_ = ARMv7;
   } else {
-    FATAL("Unsupported ARM CPU architecture.");
+#if defined(DART_RUN_IN_QEMU_ARMv7)
+    arm_version_ = ARMv7;
+#else
+    FATAL("Unrecognized ARM CPU architecture.");
+#endif
   }
 
   // Has floating point unit.
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index a8a2f94..63b9e59 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -607,7 +607,7 @@
   MallocHooks::Cleanup();
   Flags::Cleanup();
 #if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
-  IsolateReloadContext::SetFileModifiedCallback(NULL);
+  IsolateGroupReloadContext::SetFileModifiedCallback(NULL);
   Service::SetEmbedderStreamCallbacks(NULL, NULL);
 #endif  // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
   return NULL;
@@ -851,6 +851,10 @@
     buffer.AddString(FLAG_causal_async_stacks ? " causal_async_stacks"
                                               : " no-causal_async_stacks");
 
+#if !defined(PRODUCT)
+    buffer.AddString(FLAG_code_comments ? " code-comments"
+                                        : " no-code-comments");
+#endif
 
 // Generated code must match the host architecture and ABI.
 #if defined(TARGET_ARCH_ARM)
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 7db09c1..b5b144d 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -152,7 +152,8 @@
     ASSERT(!list_class.IsNull());
     const Instance& instance = Instance::Cast(obj);
     const Class& obj_class = Class::Handle(zone, obj.clazz());
-    if (Class::IsSubtypeOf(obj_class, Object::null_type_arguments(), list_class,
+    if (Class::IsSubtypeOf(NNBDMode::kLegacy, obj_class,
+                           Object::null_type_arguments(), list_class,
                            Object::null_type_arguments(), Heap::kNew)) {
       return instance.raw();
     }
@@ -168,7 +169,8 @@
     ASSERT(!map_class.IsNull());
     const Instance& instance = Instance::Cast(obj);
     const Class& obj_class = Class::Handle(zone, obj.clazz());
-    if (Class::IsSubtypeOf(obj_class, Object::null_type_arguments(), map_class,
+    if (Class::IsSubtypeOf(NNBDMode::kLegacy, obj_class,
+                           Object::null_type_arguments(), map_class,
                            Object::null_type_arguments(), Heap::kNew)) {
       return instance.raw();
     }
@@ -2043,7 +2045,8 @@
     RETURN_TYPE_ERROR(Z, object, Instance);
   }
   CHECK_CALLBACK_STATE(T);
-  *value = instance.IsInstanceOf(type_obj, Object::null_type_arguments(),
+  *value = instance.IsInstanceOf(NNBDMode::kLegacy, type_obj,
+                                 Object::null_type_arguments(),
                                  Object::null_type_arguments());
   return Api::Success();
 }
@@ -2205,8 +2208,8 @@
     ASSERT(!future_class.IsNull());
     const Class& obj_class = Class::Handle(Z, obj.clazz());
     bool is_future = Class::IsSubtypeOf(
-        obj_class, Object::null_type_arguments(), future_class,
-        Object::null_type_arguments(), Heap::kNew);
+        NNBDMode::kLegacy, obj_class, Object::null_type_arguments(),
+        future_class, Object::null_type_arguments(), Heap::kNew);
     return is_future;
   }
   return false;
@@ -4043,8 +4046,8 @@
       // We do not support generic constructors.
       ASSERT(redirect_type.IsInstantiated(kFunctions));
       redirect_type ^= redirect_type.InstantiateFrom(
-          type_arguments, Object::null_type_arguments(), kNoneFree, NULL,
-          Heap::kNew);
+          NNBDMode::kLegacy, type_arguments, Object::null_type_arguments(),
+          kNoneFree, NULL, Heap::kNew);
       redirect_type ^= redirect_type.Canonicalize();
     }
 
@@ -5852,33 +5855,33 @@
   }
 #if !defined(DART_PRECOMPILED_RUNTIME)
   if (file_modified_callback != NULL) {
-    if (IsolateReloadContext::file_modified_callback() != NULL) {
+    if (IsolateGroupReloadContext::file_modified_callback() != NULL) {
       return strdup(
           "Dart_SetFileModifiedCallback permits only one callback to be"
           " registered, please remove the existing callback and then add"
           " this callback");
     }
   } else {
-    if (IsolateReloadContext::file_modified_callback() == NULL) {
+    if (IsolateGroupReloadContext::file_modified_callback() == NULL) {
       return strdup(
           "Dart_SetFileModifiedCallback expects 'file_modified_callback' to"
           " be set before it is cleared.");
     }
   }
-  IsolateReloadContext::SetFileModifiedCallback(file_modified_callback);
+  IsolateGroupReloadContext::SetFileModifiedCallback(file_modified_callback);
 #endif  // !defined(DART_PRECOMPILED_RUNTIME)
 #endif  // !defined(PRODUCT)
   return NULL;
 }
 
 DART_EXPORT bool Dart_IsReloading() {
-#if defined(PRODUCT)
+#if defined(PRODUCT) || defined(DART_PRECOMPILED_RUNTIME)
   return false;
 #else
   Thread* thread = Thread::Current();
   Isolate* isolate = thread->isolate();
   CHECK_ISOLATE(isolate);
-  return isolate->IsReloading();
+  return isolate->group()->IsReloading();
 #endif
 }
 
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index 937f7cf..1ba6b82 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -1543,26 +1543,6 @@
   }
 }
 
-// Helper class to ensure new gen GC is triggered without any side effects.
-// The normal call to CollectGarbage(Heap::kNew) could potentially trigger
-// an old gen collection if there is a promotion failure and this could
-// perturb the test.
-class GCTestHelper : public AllStatic {
- public:
-  static void CollectNewSpace() {
-    Thread* thread = Thread::Current();
-    ASSERT(thread->execution_state() == Thread::kThreadInVM);
-    thread->heap()->new_space()->Scavenge();
-  }
-
-  static void WaitForGCTasks() {
-    Thread* thread = Thread::Current();
-    ASSERT(thread->execution_state() == Thread::kThreadInVM);
-    thread->heap()->WaitForMarkerTasks(thread);
-    thread->heap()->WaitForSweeperTasks(thread);
-  }
-};
-
 static void ExternalStringCallbackFinalizer(void* isolate_callback_data,
                                             Dart_WeakPersistentHandle handle,
                                             void* peer) {
@@ -1595,12 +1575,10 @@
     TransitionNativeToVM transition(thread);
     EXPECT_EQ(40, peer8);
     EXPECT_EQ(41, peer16);
-    Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
-    GCTestHelper::WaitForGCTasks();
+    GCTestHelper::CollectOldSpace();
     EXPECT_EQ(40, peer8);
     EXPECT_EQ(41, peer16);
-    Isolate::Current()->heap()->CollectGarbage(Heap::kNew);
-    GCTestHelper::WaitForGCTasks();
+    GCTestHelper::CollectNewSpace();
     EXPECT_EQ(80, peer8);
     EXPECT_EQ(82, peer16);
   }
@@ -2288,7 +2266,7 @@
 
   {
     TransitionNativeToVM transition(Thread::Current());
-    Isolate::Current()->heap()->CollectAllGarbage();
+    GCTestHelper::CollectAllGarbage();
   }
 
   EXPECT(!byte_data_finalizer_run);
@@ -2298,7 +2276,7 @@
 
   {
     TransitionNativeToVM transition(Thread::Current());
-    Isolate::Current()->heap()->CollectAllGarbage();
+    GCTestHelper::CollectAllGarbage();
   }
 
   EXPECT(byte_data_finalizer_run);
@@ -2481,7 +2459,7 @@
   virtual void Run() {
     Thread::EnterIsolateAsHelper(isolate_, Thread::kUnknownTask);
     for (intptr_t i = 0; i < 10; i++) {
-      Thread::Current()->heap()->CollectAllGarbage(Heap::kDebugging);
+      GCTestHelper::CollectAllGarbage();
     }
     Thread::ExitIsolateAsHelper();
     {
@@ -2801,11 +2779,9 @@
   {
     TransitionNativeToVM transition(thread);
     EXPECT(peer == 0);
-    Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
-    GCTestHelper::WaitForGCTasks();
+    GCTestHelper::CollectOldSpace();
     EXPECT(peer == 0);
-    Isolate::Current()->heap()->CollectGarbage(Heap::kNew);
-    GCTestHelper::WaitForGCTasks();
+    GCTestHelper::CollectNewSpace();
     EXPECT(peer == 42);
   }
 }
@@ -2830,15 +2806,10 @@
 
     {
       TransitionNativeToVM transition(thread);
-      Isolate::Current()->heap()->CollectAllGarbage();
+      GCTestHelper::CollectAllGarbage();
     }
   }
 
-  {
-    TransitionNativeToVM transition(thread);
-    GCTestHelper::WaitForGCTasks();
-  }
-
   EXPECT_EQ(20, count);
 }
 
@@ -2890,8 +2861,7 @@
   Dart_ExitScope();
   {
     TransitionNativeToVM transition(thread);
-    Isolate::Current()->heap()->CollectGarbage(Heap::kNew);
-    GCTestHelper::WaitForGCTasks();
+    GCTestHelper::CollectNewSpace();
     EXPECT(peer == 42);
   }
 }
@@ -3130,7 +3100,6 @@
       TransitionNativeToVM transition(thread);
       // Garbage collect new space.
       GCTestHelper::CollectNewSpace();
-      GCTestHelper::WaitForGCTasks();
     }
 
     // Nothing should be invalidated or cleared.
@@ -3150,8 +3119,7 @@
     {
       TransitionNativeToVM transition(thread);
       // Garbage collect old space.
-      Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
-      GCTestHelper::WaitForGCTasks();
+      GCTestHelper::CollectOldSpace();
     }
 
     // Nothing should be invalidated or cleared.
@@ -3176,7 +3144,6 @@
     TransitionNativeToVM transition(thread);
     // Garbage collect new space again.
     GCTestHelper::CollectNewSpace();
-    GCTestHelper::WaitForGCTasks();
   }
 
   {
@@ -3191,8 +3158,7 @@
   {
     TransitionNativeToVM transition(thread);
     // Garbage collect old space again.
-    Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
-    GCTestHelper::WaitForGCTasks();
+    GCTestHelper::CollectOldSpace();
   }
 
   {
@@ -3206,9 +3172,7 @@
   {
     TransitionNativeToVM transition(thread);
     // Garbage collect one last time to revisit deleted handles.
-    Isolate::Current()->heap()->CollectGarbage(Heap::kNew);
-    Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
-    GCTestHelper::WaitForGCTasks();
+    GCTestHelper::CollectAllGarbage();
   }
 }
 
@@ -3253,10 +3217,9 @@
   }
   {
     TransitionNativeToVM transition(thread);
-    Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
+    GCTestHelper::CollectOldSpace();
     EXPECT(peer == 0);
     GCTestHelper::CollectNewSpace();
-    GCTestHelper::WaitForGCTasks();
     EXPECT(peer == 42);
   }
 }
@@ -3279,10 +3242,9 @@
   EXPECT(peer == 0);
   {
     TransitionNativeToVM transition(thread);
-    Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
+    GCTestHelper::CollectOldSpace();
     EXPECT(peer == 0);
     GCTestHelper::CollectNewSpace();
-    GCTestHelper::WaitForGCTasks();
     EXPECT(peer == 0);
   }
 }
@@ -3329,13 +3291,12 @@
   }
   {
     TransitionNativeToVM transition(thread);
-    Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
+    GCTestHelper::CollectOldSpace();
     EXPECT(heap->ExternalInWords(Heap::kNew) ==
            (kWeak1ExternalSize + kWeak2ExternalSize) / kWordSize);
     // Collect weakly referenced string, and promote strongly referenced string.
     GCTestHelper::CollectNewSpace();
     GCTestHelper::CollectNewSpace();
-    GCTestHelper::WaitForGCTasks();
     EXPECT(heap->ExternalInWords(Heap::kNew) == 0);
     EXPECT(heap->ExternalInWords(Heap::kOld) == kWeak2ExternalSize / kWordSize);
   }
@@ -3345,8 +3306,7 @@
   Dart_DeletePersistentHandle(strong_ref);
   {
     TransitionNativeToVM transition(thread);
-    Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
-    GCTestHelper::WaitForGCTasks();
+    GCTestHelper::CollectOldSpace();
     EXPECT(heap->ExternalInWords(Heap::kOld) == 0);
   }
 }
@@ -3389,8 +3349,7 @@
   Dart_DeleteWeakPersistentHandle(isolate, weak1);
   {
     TransitionNativeToVM transition(thread);
-    Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
-    GCTestHelper::WaitForGCTasks();  // Finalize GC for accurate live size.
+    GCTestHelper::CollectOldSpace();
     EXPECT_EQ(0, heap->ExternalInWords(Heap::kOld));
   }
 }
@@ -3466,8 +3425,7 @@
   EXPECT_EQ(0, heap->ExternalInWords(Heap::kOld));
   {
     TransitionNativeToVM transition(thread);
-    Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
-    GCTestHelper::WaitForGCTasks();  // Finalize GC for accurate live size.
+    GCTestHelper::CollectOldSpace();
     EXPECT_EQ(0, heap->ExternalInWords(Heap::kOld));
   }
 }
@@ -3600,7 +3558,7 @@
 
   {
     TransitionNativeToVM transition(thread);
-    Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
+    GCTestHelper::CollectOldSpace();
   }
 
   {
@@ -7308,7 +7266,7 @@
     EXPECT(out == reinterpret_cast<void*>(&peer));
     {
       TransitionNativeToVM transition(thread);
-      isolate->heap()->CollectGarbage(Heap::kNew);
+      GCTestHelper::CollectNewSpace();
       EXPECT_EQ(1, isolate->heap()->PeerCount());
     }
     out = &out;
@@ -7318,7 +7276,7 @@
   Dart_ExitScope();
   {
     TransitionNativeToVM transition(thread);
-    isolate->heap()->CollectGarbage(Heap::kNew);
+    GCTestHelper::CollectNewSpace();
     EXPECT_EQ(0, isolate->heap()->PeerCount());
   }
 }
@@ -7398,7 +7356,7 @@
   Dart_ExitScope();
   {
     TransitionNativeToVM transition(thread);
-    isolate->heap()->CollectGarbage(Heap::kNew);
+    GCTestHelper::CollectNewSpace();
     EXPECT_EQ(0, isolate->heap()->PeerCount());
   }
 }
@@ -7429,9 +7387,9 @@
   EXPECT_EQ(kPeerCount, isolate->heap()->PeerCount());
   {
     TransitionNativeToVM transition(thread);
-    isolate->heap()->CollectGarbage(Heap::kNew);
+    GCTestHelper::CollectNewSpace();
     EXPECT_EQ(kPeerCount, isolate->heap()->PeerCount());
-    isolate->heap()->CollectGarbage(Heap::kNew);
+    GCTestHelper::CollectNewSpace();
     EXPECT_EQ(kPeerCount, isolate->heap()->PeerCount());
   }
 }
@@ -7456,8 +7414,8 @@
   EXPECT_EQ(1, isolate->heap()->PeerCount());
   {
     TransitionNativeToVM transition(thread);
-    isolate->heap()->CollectGarbage(Heap::kNew);
-    isolate->heap()->CollectGarbage(Heap::kNew);
+    GCTestHelper::CollectNewSpace();
+    GCTestHelper::CollectNewSpace();
   }
   {
     CHECK_API_SCOPE(thread);
@@ -7497,7 +7455,7 @@
   EXPECT(out == reinterpret_cast<void*>(&peer));
   {
     TransitionNativeToVM transition(thread);
-    isolate->heap()->CollectGarbage(Heap::kOld);
+    GCTestHelper::CollectOldSpace();
     EXPECT_EQ(1, isolate->heap()->PeerCount());
   }
   EXPECT_VALID(Dart_GetPeer(str, &out));
@@ -7533,7 +7491,7 @@
     EXPECT(out == reinterpret_cast<void*>(&peer));
     {
       TransitionNativeToVM transition(thread);
-      isolate->heap()->CollectGarbage(Heap::kOld);
+      GCTestHelper::CollectOldSpace();
       EXPECT_EQ(1, isolate->heap()->PeerCount());
     }
     EXPECT_VALID(Dart_GetPeer(str, &out));
@@ -7542,7 +7500,7 @@
   Dart_ExitScope();
   {
     TransitionNativeToVM transition(thread);
-    isolate->heap()->CollectGarbage(Heap::kOld);
+    GCTestHelper::CollectOldSpace();
     EXPECT_EQ(0, isolate->heap()->PeerCount());
   }
 }
@@ -7629,7 +7587,7 @@
   Dart_ExitScope();
   {
     TransitionNativeToVM transition(thread);
-    isolate->heap()->CollectGarbage(Heap::kOld);
+    GCTestHelper::CollectOldSpace();
     EXPECT_EQ(0, isolate->heap()->PeerCount());
   }
 }
diff --git a/runtime/vm/dart_entry.cc b/runtime/vm/dart_entry.cc
index 49e4b47..bfe8f9e 100644
--- a/runtime/vm/dart_entry.cc
+++ b/runtime/vm/dart_entry.cc
@@ -359,11 +359,12 @@
 
 RawArray* ArgumentsDescriptor::New(intptr_t type_args_len,
                                    intptr_t num_arguments,
-                                   const Array& optional_arguments_names) {
+                                   const Array& optional_arguments_names,
+                                   Heap::Space space) {
   const intptr_t num_named_args =
       optional_arguments_names.IsNull() ? 0 : optional_arguments_names.Length();
   if (num_named_args == 0) {
-    return ArgumentsDescriptor::New(type_args_len, num_arguments);
+    return ArgumentsDescriptor::New(type_args_len, num_arguments, space);
   }
   ASSERT(type_args_len >= 0);
   ASSERT(num_arguments >= 0);
@@ -377,8 +378,7 @@
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
   const intptr_t descriptor_len = LengthFor(num_named_args);
-  Array& descriptor =
-      Array::Handle(zone, Array::New(descriptor_len, Heap::kOld));
+  Array& descriptor = Array::Handle(zone, Array::New(descriptor_len, space));
 
   // Set length of type argument vector.
   descriptor.SetAt(kTypeArgsLenIndex, Smi::Handle(Smi::New(type_args_len)));
@@ -428,27 +428,28 @@
 }
 
 RawArray* ArgumentsDescriptor::New(intptr_t type_args_len,
-                                   intptr_t num_arguments) {
+                                   intptr_t num_arguments,
+                                   Heap::Space space) {
   ASSERT(type_args_len >= 0);
   ASSERT(num_arguments >= 0);
 
   if ((type_args_len == 0) && (num_arguments < kCachedDescriptorCount)) {
     return cached_args_descriptors_[num_arguments];
   }
-  return NewNonCached(type_args_len, num_arguments, true);
+  return NewNonCached(type_args_len, num_arguments, true, space);
 }
 
 RawArray* ArgumentsDescriptor::NewNonCached(intptr_t type_args_len,
                                             intptr_t num_arguments,
-                                            bool canonicalize) {
+                                            bool canonicalize,
+                                            Heap::Space space) {
   // Build the arguments descriptor array, which consists of the length of the
   // type argument vector, total argument count; the positional argument count;
   // and a terminating null to simplify iterating in generated code.
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
   const intptr_t descriptor_len = LengthFor(0);
-  Array& descriptor =
-      Array::Handle(zone, Array::New(descriptor_len, Heap::kOld));
+  Array& descriptor = Array::Handle(zone, Array::New(descriptor_len, space));
   const Smi& arg_count = Smi::Handle(zone, Smi::New(num_arguments));
 
   // Set type argument vector length.
@@ -479,7 +480,8 @@
 
 void ArgumentsDescriptor::Init() {
   for (int i = 0; i < kCachedDescriptorCount; i++) {
-    cached_args_descriptors_[i] = NewNonCached(/*type_args_len=*/0, i, false);
+    cached_args_descriptors_[i] =
+        NewNonCached(/*type_args_len=*/0, i, false, Heap::kOld);
   }
 }
 
diff --git a/runtime/vm/dart_entry.h b/runtime/vm/dart_entry.h
index 94764a3..980fcfc 100644
--- a/runtime/vm/dart_entry.h
+++ b/runtime/vm/dart_entry.h
@@ -74,13 +74,16 @@
   // num_arguments) is indicated by a non-zero type_args_len.
   static RawArray* New(intptr_t type_args_len,
                        intptr_t num_arguments,
-                       const Array& optional_arguments_names);
+                       const Array& optional_arguments_names,
+                       Heap::Space space = Heap::kOld);
 
   // Allocate and return an arguments descriptor that has no optional
   // arguments. All arguments are positional. The presence of a type argument
   // vector as first argument (not counted in num_arguments) is indicated
   // by a non-zero type_args_len.
-  static RawArray* New(intptr_t type_args_len, intptr_t num_arguments);
+  static RawArray* New(intptr_t type_args_len,
+                       intptr_t num_arguments,
+                       Heap::Space space = Heap::kOld);
 
   // Initialize the preallocated fixed length arguments descriptors cache.
   static void Init();
@@ -119,7 +122,8 @@
 
   static RawArray* NewNonCached(intptr_t type_args_len,
                                 intptr_t num_arguments,
-                                bool canonicalize);
+                                bool canonicalize,
+                                Heap::Space space);
 
   // Used by Simulator to parse argument descriptors.
   static intptr_t name_index(intptr_t index) {
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index 392705a..c5ce88a 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -969,7 +969,8 @@
         if (type.IsDynamicType()) {
           return true;
         }
-        if (exc_obj.IsInstanceOf(type, Object::null_type_arguments(),
+        if (exc_obj.IsInstanceOf(NNBDMode::kLegacy, type,
+                                 Object::null_type_arguments(),
                                  Object::null_type_arguments())) {
           return true;
         }
@@ -1014,7 +1015,6 @@
   // Attempt to determine the token pos and try index from the async closure.
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
-  const Script& script = Script::Handle(zone, function().script());
 
   ASSERT(function_.IsAsyncGenClosure() || function_.IsAsyncClosure());
   // This should only be called on frames that aren't active on the stack.
@@ -1057,28 +1057,17 @@
   if (await_jump_var < 0) {
     return;
   }
-  intptr_t await_to_token_map_index = await_jump_var - 1;
-  const auto& array =
-      GrowableObjectArray::Handle(zone, script.GetYieldPositions(function_));
-  // await_jump_var is non zero means that array should not be empty
-  // index also fall into the correct range
-  ASSERT(array.Length() > 0 && await_to_token_map_index < array.Length());
-  const Object& token_pos =
-      Object::Handle(zone, array.At(await_to_token_map_index));
-  ASSERT(token_pos.IsSmi());
-  token_pos_ = TokenPosition(Smi::Cast(token_pos).Value());
-  token_pos_initialized_ = true;
-  GetPcDescriptors();
-  PcDescriptors::Iterator iter(pc_desc_, RawPcDescriptors::kAnyKind);
-  while (iter.MoveNext()) {
-    if (iter.TokenPos() == token_pos_) {
-      // Match the lowest try index at this token position.
-      // TODO(johnmccutchan): Is this heuristic precise enough?
-      if (iter.TryIndex() != kInvalidTryIndex) {
-        if ((try_index_ == -1) || (iter.TryIndex() < try_index_)) {
-          try_index_ = iter.TryIndex();
-        }
-      }
+
+  const auto& pc_descriptors =
+      PcDescriptors::Handle(zone, code().pc_descriptors());
+  ASSERT(!pc_descriptors.IsNull());
+  PcDescriptors::Iterator it(pc_descriptors, RawPcDescriptors::kOther);
+  while (it.MoveNext()) {
+    if (it.YieldIndex() == await_jump_var) {
+      try_index_ = it.TryIndex();
+      token_pos_ = it.TokenPos();
+      token_pos_initialized_ = true;
+      return;
     }
   }
 }
@@ -1911,16 +1900,6 @@
 
 void Debugger::OnIsolateRunnable() {}
 
-static RawFunction* ResolveLibraryFunction(const Library& library,
-                                           const String& fname) {
-  ASSERT(!library.IsNull());
-  const Object& object = Object::Handle(library.ResolveName(fname));
-  if (!object.IsNull() && object.IsFunction()) {
-    return Function::Cast(object).raw();
-  }
-  return Function::null();
-}
-
 bool Debugger::SetupStepOverAsyncSuspension(const char** error) {
   ActivationFrame* top_frame = TopDartFrame();
   if (!IsAtAsyncJump(top_frame)) {
@@ -1974,26 +1953,6 @@
   }
 }
 
-RawFunction* Debugger::ResolveFunction(const Library& library,
-                                       const String& class_name,
-                                       const String& function_name) {
-  ASSERT(!library.IsNull());
-  ASSERT(!class_name.IsNull());
-  ASSERT(!function_name.IsNull());
-  if (class_name.Length() == 0) {
-    return ResolveLibraryFunction(library, function_name);
-  }
-  const Class& cls = Class::Handle(library.LookupClass(class_name));
-  Function& function = Function::Handle();
-  if (!cls.IsNull()) {
-    function = cls.LookupStaticFunction(function_name);
-    if (function.IsNull()) {
-      function = cls.LookupDynamicFunction(function_name);
-    }
-  }
-  return function.raw();
-}
-
 // Deoptimize all functions in the isolate.
 // TODO(hausner): Actually we only need to deoptimize those functions
 // that inline the function that contains the newly created breakpoint.
@@ -2266,8 +2225,9 @@
     return NULL;
   }
 
+  bool sync_async_end = false;
   intptr_t synchronous_stack_trace_length =
-      StackTraceUtils::CountFrames(thread, 0, async_function);
+      StackTraceUtils::CountFrames(thread, 0, async_function, &sync_async_end);
 
   // Append the top frames from the synchronous stack trace, up until the active
   // asynchronous function. We truncate the remainder of the synchronous
@@ -2304,8 +2264,11 @@
   // Now we append the asynchronous causal stack trace. These are not active
   // frames but a historical record of how this asynchronous function was
   // activated.
+
+  intptr_t frame_skip =
+      sync_async_end ? StackTrace::kSyncAsyncCroppedFrames : 0;
   while (!async_stack_trace.IsNull()) {
-    for (intptr_t i = 0; i < async_stack_trace.Length(); i++) {
+    for (intptr_t i = frame_skip; i < async_stack_trace.Length(); i++) {
       code_obj = async_stack_trace.CodeAtFrame(i);
       if (code_obj.IsNull()) {
         break;
@@ -2340,22 +2303,15 @@
       }
     }
     // Follow the link.
+    frame_skip = async_stack_trace.skip_sync_start_in_parent_stack()
+                     ? StackTrace::kSyncAsyncCroppedFrames
+                     : 0;
     async_stack_trace = async_stack_trace.async_link();
   }
 
   return stack_trace;
 }
 
-#if !defined(DART_PRECOMPILED_RUNTIME)
-static bool CheckAndSkipAsync(int skip_sync_async_frames_count,
-                              const String& function_name) {
-  return (skip_sync_async_frames_count == 2 &&
-          function_name.Equals(Symbols::_ClosureCall())) ||
-         (skip_sync_async_frames_count == 1 &&
-          function_name.Equals(Symbols::_AsyncAwaitCompleterStart()));
-}
-#endif
-
 DebuggerStackTrace* Debugger::CollectAwaiterReturnStackTrace() {
 #if defined(DART_PRECOMPILED_RUNTIME)
   // Causal async stacks are not supported in the AOT runtime.
@@ -2407,9 +2363,8 @@
 
         if (skip_sync_async_frames_count > 0) {
           function_name = function.QualifiedScrubbedName();
-          if (CheckAndSkipAsync(skip_sync_async_frames_count, function_name)) {
-            skip_sync_async_frames_count--;
-          } else {
+          if (!StackTraceUtils::CheckAndSkipAsync(&skip_sync_async_frames_count,
+                                                  function_name)) {
             // Unexpected function in synchronous call of async function.
             break;
           }
@@ -2457,10 +2412,8 @@
 
             if (skip_sync_async_frames_count > 0) {
               function_name ^= function.QualifiedScrubbedName();
-              if (CheckAndSkipAsync(skip_sync_async_frames_count,
-                                    function_name)) {
-                skip_sync_async_frames_count--;
-              } else {
+              if (!StackTraceUtils::CheckAndSkipAsync(
+                      &skip_sync_async_frames_count, function_name)) {
                 // Unexpected function in sync async call
                 skip_sync_async_frames_count = -1;
                 abort_attempt_to_navigate_through_sync_async = true;
@@ -2512,10 +2465,8 @@
 
           if (skip_sync_async_frames_count > 0) {
             function_name ^= function.QualifiedScrubbedName();
-            if (CheckAndSkipAsync(skip_sync_async_frames_count,
-                                  function_name)) {
-              skip_sync_async_frames_count--;
-            } else {
+            if (!StackTraceUtils::CheckAndSkipAsync(
+                    &skip_sync_async_frames_count, function_name)) {
               // Unexpected function in synchronous call of async function.
               break;
             }
@@ -4357,6 +4308,8 @@
   Object& closure_or_null =
       Object::Handle(zone, top_frame->GetAsyncOperation());
   if (!closure_or_null.IsNull()) {
+    ASSERT(top_frame->function().IsAsyncClosure() ||
+           top_frame->function().IsAsyncGenClosure());
     ASSERT(closure_or_null.IsInstance());
     ASSERT(Instance::Cast(closure_or_null).IsClosure());
     if (top_frame->function().is_declared_in_bytecode()) {
@@ -4376,18 +4329,16 @@
 #endif  // !defined(DART_PRECOMPILED_RUNTIME)
     }
     ASSERT(!top_frame->IsInterpreted());
-    const Script& script = Script::Handle(zone, top_frame->SourceScript());
-    const auto& yield_positions = GrowableObjectArray::Handle(
-        zone, script.GetYieldPositions(top_frame->function()));
-    // No yield statements
-    if (yield_positions.IsNull() || (yield_positions.Length() == 0)) {
+    const auto& pc_descriptors =
+        PcDescriptors::Handle(zone, top_frame->code().pc_descriptors());
+    if (pc_descriptors.IsNull()) {
       return false;
     }
-    intptr_t looking_for = top_frame->TokenPos().value();
-    Smi& value = Smi::Handle(zone);
-    for (int i = 0; i < yield_positions.Length(); i++) {
-      value ^= yield_positions.At(i);
-      if (value.Value() == looking_for) {
+    const TokenPosition looking_for = top_frame->TokenPos();
+    PcDescriptors::Iterator it(pc_descriptors, RawPcDescriptors::kOther);
+    while (it.MoveNext()) {
+      if (it.TokenPos() == looking_for &&
+          it.YieldIndex() != RawPcDescriptors::kInvalidYieldIndex) {
         return true;
       }
     }
diff --git a/runtime/vm/debugger.h b/runtime/vm/debugger.h
index 3300813..b1fdd40 100644
--- a/runtime/vm/debugger.h
+++ b/runtime/vm/debugger.h
@@ -507,10 +507,6 @@
   }
   void NotifyDoneLoading();
 
-  RawFunction* ResolveFunction(const Library& library,
-                               const String& class_name,
-                               const String& function_name);
-
   // Set breakpoint at closest location to function entry.
   Breakpoint* SetBreakpointAtEntry(const Function& target_function,
                                    bool single_shot);
diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc
index 761ea02..6d9ea92 100644
--- a/runtime/vm/exceptions.cc
+++ b/runtime/vm/exceptions.cc
@@ -192,16 +192,23 @@
               if (cached_catch_entry_moves != NULL) {
                 cached_catch_entry_moves_ = *cached_catch_entry_moves;
               }
-#if !defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_PRECOMPILER)
-              intptr_t num_vars = Smi::Value(code_->variables());
               if (cached_catch_entry_moves_.IsEmpty()) {
-                GetCatchEntryMovesFromDeopt(num_vars, frame);
-              }
-#else
-              if (cached_catch_entry_moves_.IsEmpty()) {
+#if defined(DART_PRECOMPILED_RUNTIME)
+                // Only AOT mode is supported.
                 ReadCompressedCatchEntryMoves();
+#elif defined(DART_PRECOMPILER)
+                // Both AOT and JIT modes are supported.
+                if (FLAG_precompiled_mode) {
+                  ReadCompressedCatchEntryMoves();
+                } else {
+                  GetCatchEntryMovesFromDeopt(code_->num_variables(), frame);
+                }
+#else
+                // Only JIT mode is supported.
+                ASSERT(!FLAG_precompiled_mode);
+                GetCatchEntryMovesFromDeopt(code_->num_variables(), frame);
+#endif
               }
-#endif  // !defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_PRECOMPILER)
             }
           }
           if (needs_stacktrace || is_catch_all) {
@@ -323,7 +330,9 @@
     CatchEntryMovesMapReader reader(td);
     catch_entry_moves_ = reader.ReadMovesForPcOffset(pc_offset);
   }
-#else
+#endif  // defined(DART_PRECOMPILED_RUNTIME) || defined(DART_PRECOMPILER)
+
+#if !defined(DART_PRECOMPILED_RUNTIME)
   void GetCatchEntryMovesFromDeopt(intptr_t num_vars, StackFrame* frame) {
     Isolate* isolate = thread_->isolate();
     DeoptContext* deopt_context =
@@ -336,7 +345,7 @@
     isolate->set_deopt_context(NULL);
     delete deopt_context;
   }
-#endif  // defined(DART_PRECOMPILED_RUNTIME) || defined(DART_PRECOMPILER)
+#endif  // !defined(DART_PRECOMPILED_RUNTIME)
 
   bool needs_stacktrace;
   uword handler_pc;
diff --git a/runtime/vm/flag_list.h b/runtime/vm/flag_list.h
index a3d9e05..6912711 100644
--- a/runtime/vm/flag_list.h
+++ b/runtime/vm/flag_list.h
@@ -24,22 +24,40 @@
 constexpr bool kDartUseBytecode = false;
 #endif
 
+// The disassembler might be force included even in product builds so we need
+// to conditionally make these into product flags to make the disassembler
+// usable in product mode.
+#if defined(FORCE_INCLUDE_DISASSEMBLER)
+#define DISASSEMBLE_FLAGS(P, R, C, D)                                          \
+  P(disassemble, bool, false, "Disassemble dart code.")                        \
+  P(disassemble_optimized, bool, false, "Disassemble optimized code.")         \
+  P(disassemble_relative, bool, false, "Use offsets instead of absolute PCs")  \
+  P(support_disassembler, bool, true, "Support the disassembler.")
+#else
+#define DISASSEMBLE_FLAGS(P, R, C, D)                                          \
+  R(disassemble, false, bool, false, "Disassemble dart code.")                 \
+  R(disassemble_optimized, false, bool, false, "Disassemble optimized code.")  \
+  R(disassemble_relative, false, bool, false,                                  \
+    "Use offsets instead of absolute PCs")                                     \
+  R(support_disassembler, false, bool, true, "Support the disassembler.")
+#endif
+
 // List of all flags in the VM.
-// Flags can be one of three categories:
+// Flags can be one of four categories:
 // * P roduct flags: Can be set in any of the deployment modes, including in
 //   production.
 // * R elease flags: Generally available flags except when building product.
-// * D ebug flags: Can only be set in debug VMs, which also have C++ assertions
-//   enabled.
 // * pre C ompile flags: Generally available flags except when building product
 //   or precompiled runtime.
+// * D ebug flags: Can only be set in debug VMs, which also have C++ assertions
+//   enabled.
 //
 // Usage:
 //   P(name, type, default_value, comment)
 //   R(name, product_value, type, default_value, comment)
-//   D(name, type, default_value, comment)
 //   C(name, precompiled_value, product_value, type, default_value, comment)
-#define FLAG_LIST(P, R, D, C)                                                  \
+//   D(name, type, default_value, comment)
+#define FLAG_LIST(P, R, C, D)                                                  \
   P(experimental_unsafe_mode_use_at_your_own_risk, bool, false,                \
     "Omit runtime strong mode type checks and disable optimizations based on " \
     "types.")                                                                  \
@@ -67,10 +85,9 @@
   C(deoptimize_every, 0, 0, int, 0,                                            \
     "Deoptimize on every N stack overflow checks")                             \
   R(disable_alloc_stubs_after_gc, false, bool, false, "Stress testing flag.")  \
-  R(disassemble, false, bool, false, "Disassemble dart code.")                 \
-  R(disassemble_optimized, false, bool, false, "Disassemble optimized code.")  \
-  R(disassemble_relative, false, bool, false,                                  \
-    "Use offsets instead of absolute PCs")                                     \
+  DISASSEMBLE_FLAGS(P, R, C, D)                                                \
+  R(code_comments, false, bool, false,                                         \
+    "Include comments into code and disassembly.")                             \
   R(dump_megamorphic_stats, false, bool, false,                                \
     "Dump megamorphic cache statistics")                                       \
   R(dump_symbol_stats, false, bool, false, "Dump symbol table statistics")     \
@@ -148,12 +165,15 @@
   P(reorder_basic_blocks, bool, true, "Reorder basic blocks")                  \
   C(stress_async_stacks, false, false, bool, false,                            \
     "Stress test async stack traces")                                          \
+  P(strong_non_nullable_type_checks, bool, false,                              \
+    "Enable strong non-nullable type checking mode.")                          \
   P(use_bare_instructions, bool, true, "Enable bare instructions mode.")       \
+  P(enable_isolate_groups, bool, kDartPrecompiledRuntime,                      \
+    "Enable isolate group support.")                                           \
   P(show_invisible_frames, bool, false,                                        \
     "Show invisible frames in stack traces.")                                  \
   R(show_invisible_isolates, false, bool, false,                               \
     "Show invisible isolates in the vm-service.")                              \
-  R(support_disassembler, false, bool, true, "Support the disassembler.")      \
   R(support_il_printer, false, bool, true, "Support the IL printer.")          \
   C(support_reload, false, false, bool, true, "Support isolate reload.")       \
   R(support_service, false, bool, true, "Support the service protocol.")       \
@@ -217,7 +237,7 @@
 // same as during runtime.
 //
 // Usage:
-//   P(name, command-line-flag-name)
+//   V(name, command-line-flag-name)
 #define VM_GLOBAL_FLAG_LIST(V)                                                 \
   V(use_bare_instructions, FLAG_use_bare_instructions)
 
diff --git a/runtime/vm/flags.cc b/runtime/vm/flags.cc
index 3cd3422..672cd68 100644
--- a/runtime/vm/flags.cc
+++ b/runtime/vm/flags.cc
@@ -16,60 +16,60 @@
             false,
             "Ignore unrecognized flags.");
 
-#define PRODUCT_FLAG_MARCO(name, type, default_value, comment)                 \
+#define PRODUCT_FLAG_MACRO(name, type, default_value, comment)                 \
   type FLAG_##name =                                                           \
       Flags::Register_##type(&FLAG_##name, #name, default_value, comment);
 
 #if defined(DEBUG)
-#define DEBUG_FLAG_MARCO(name, type, default_value, comment)                   \
+#define DEBUG_FLAG_MACRO(name, type, default_value, comment)                   \
   type FLAG_##name =                                                           \
       Flags::Register_##type(&FLAG_##name, #name, default_value, comment);
 #else  // defined(DEBUG)
-#define DEBUG_FLAG_MARCO(name, type, default_value, comment)
+#define DEBUG_FLAG_MACRO(name, type, default_value, comment)
 #endif  // defined(DEBUG)
 
 #if defined(PRODUCT) && defined(DART_PRECOMPILED_RUNTIME)
 // Nothing to be done for the product flag definitions.
-#define RELEASE_FLAG_MARCO(name, product_value, type, default_value, comment)
+#define RELEASE_FLAG_MACRO(name, product_value, type, default_value, comment)
 // Nothing to be done for the precompilation flag definitions.
-#define PRECOMPILE_FLAG_MARCO(name, pre_value, product_value, type,            \
+#define PRECOMPILE_FLAG_MACRO(name, pre_value, product_value, type,            \
                               default_value, comment)
 
 #elif defined(PRODUCT)  // !PRECOMPILED
 // Nothing to be done for the product flag definitions.
-#define RELEASE_FLAG_MARCO(name, product_value, type, default_value, comment)
+#define RELEASE_FLAG_MACRO(name, product_value, type, default_value, comment)
 // Nothing to be done for the precompilation flag definitions.
-#define PRECOMPILE_FLAG_MARCO(name, pre_value, product_value, type,            \
+#define PRECOMPILE_FLAG_MACRO(name, pre_value, product_value, type,            \
                               default_value, comment)
 
 #elif defined(DART_PRECOMPILED_RUNTIME)  // !PRODUCT
-#define RELEASE_FLAG_MARCO(name, product_value, type, default_value, comment)  \
+#define RELEASE_FLAG_MACRO(name, product_value, type, default_value, comment)  \
   type FLAG_##name =                                                           \
       Flags::Register_##type(&FLAG_##name, #name, default_value, comment);
 // Nothing to be done for the precompilation flag definitions.
-#define PRECOMPILE_FLAG_MARCO(name, pre_value, product_value, type,            \
+#define PRECOMPILE_FLAG_MACRO(name, pre_value, product_value, type,            \
                               default_value, comment)
 
 #else  // !PRODUCT && !PRECOMPILED
-#define RELEASE_FLAG_MARCO(name, product_value, type, default_value, comment)  \
+#define RELEASE_FLAG_MACRO(name, product_value, type, default_value, comment)  \
   type FLAG_##name =                                                           \
       Flags::Register_##type(&FLAG_##name, #name, default_value, comment);
-#define PRECOMPILE_FLAG_MARCO(name, pre_value, product_value, type,            \
+#define PRECOMPILE_FLAG_MACRO(name, pre_value, product_value, type,            \
                               default_value, comment)                          \
   type FLAG_##name =                                                           \
       Flags::Register_##type(&FLAG_##name, #name, default_value, comment);
 #endif
 
 // Define all of the non-product flags here.
-FLAG_LIST(PRODUCT_FLAG_MARCO,
-          RELEASE_FLAG_MARCO,
-          DEBUG_FLAG_MARCO,
-          PRECOMPILE_FLAG_MARCO)
+FLAG_LIST(PRODUCT_FLAG_MACRO,
+          RELEASE_FLAG_MACRO,
+          PRECOMPILE_FLAG_MACRO,
+          DEBUG_FLAG_MACRO)
 
-#undef RELEASE_FLAG_MARCO
-#undef DEBUG_FLAG_MARCO
-#undef PRODUCT_FLAG_MARCO
-#undef PRECOMPILE_FLAG_MARCO
+#undef PRODUCT_FLAG_MACRO
+#undef RELEASE_FLAG_MACRO
+#undef PRECOMPILE_FLAG_MACRO
+#undef DEBUG_FLAG_MACRO
 
 bool Flags::initialized_ = false;
 
diff --git a/runtime/vm/flags.h b/runtime/vm/flags.h
index d230f5d..790e277 100644
--- a/runtime/vm/flags.h
+++ b/runtime/vm/flags.h
@@ -107,57 +107,57 @@
   DISALLOW_IMPLICIT_CONSTRUCTORS(Flags);
 };
 
-#define PRODUCT_FLAG_MARCO(name, type, default_value, comment)                 \
+#define PRODUCT_FLAG_MACRO(name, type, default_value, comment)                 \
   extern type FLAG_##name;
 
 #if defined(DEBUG)
-#define DEBUG_FLAG_MARCO(name, type, default_value, comment)                   \
+#define DEBUG_FLAG_MACRO(name, type, default_value, comment)                   \
   extern type FLAG_##name;
 #else  // defined(DEBUG)
-#define DEBUG_FLAG_MARCO(name, type, default_value, comment)                   \
+#define DEBUG_FLAG_MACRO(name, type, default_value, comment)                   \
   const type FLAG_##name = default_value;
 #endif  // defined(DEBUG)
 
 #if defined(PRODUCT) && defined(DART_PRECOMPILED_RUNTIME)
-#define RELEASE_FLAG_MARCO(name, product_value, type, default_value, comment)  \
+#define RELEASE_FLAG_MACRO(name, product_value, type, default_value, comment)  \
   const type FLAG_##name = product_value;
-#define PRECOMPILE_FLAG_MARCO(name, precompiled_value, product_value, type,    \
+#define PRECOMPILE_FLAG_MACRO(name, precompiled_value, product_value, type,    \
                               default_value, comment)                          \
   const type FLAG_##name = precompiled_value;
 
 #elif defined(PRODUCT)  // !PRECOMPILED
-#define RELEASE_FLAG_MARCO(name, product_value, type, default_value, comment)  \
+#define RELEASE_FLAG_MACRO(name, product_value, type, default_value, comment)  \
   const type FLAG_##name = product_value;
-#define PRECOMPILE_FLAG_MARCO(name, precompiled_value, product_value, type,    \
+#define PRECOMPILE_FLAG_MACRO(name, precompiled_value, product_value, type,    \
                               default_value, comment)                          \
   const type FLAG_##name = product_value;
 
 #elif defined(DART_PRECOMPILED_RUNTIME)  // !PRODUCT
-#define RELEASE_FLAG_MARCO(name, product_value, type, default_value, comment)  \
+#define RELEASE_FLAG_MACRO(name, product_value, type, default_value, comment)  \
   extern type FLAG_##name;
-#define PRECOMPILE_FLAG_MARCO(name, precompiled_value, product_value, type,    \
+#define PRECOMPILE_FLAG_MACRO(name, precompiled_value, product_value, type,    \
                               default_value, comment)                          \
   const type FLAG_##name = precompiled_value;
 
 #else  // !PRODUCT && !PRECOMPILED
-#define RELEASE_FLAG_MARCO(name, product_value, type, default_value, comment)  \
+#define RELEASE_FLAG_MACRO(name, product_value, type, default_value, comment)  \
   extern type FLAG_##name;
-#define PRECOMPILE_FLAG_MARCO(name, precompiled_value, product_value, type,    \
+#define PRECOMPILE_FLAG_MACRO(name, precompiled_value, product_value, type,    \
                               default_value, comment)                          \
   extern type FLAG_##name;
 
 #endif
 
 // Now declare all flags here.
-FLAG_LIST(PRODUCT_FLAG_MARCO,
-          RELEASE_FLAG_MARCO,
-          DEBUG_FLAG_MARCO,
-          PRECOMPILE_FLAG_MARCO)
+FLAG_LIST(PRODUCT_FLAG_MACRO,
+          RELEASE_FLAG_MACRO,
+          PRECOMPILE_FLAG_MACRO,
+          DEBUG_FLAG_MACRO)
 
-#undef RELEASE_FLAG_MARCO
-#undef DEBUG_FLAG_MARCO
-#undef PRODUCT_FLAG_MARCO
-#undef PRECOMPILE_FLAG_MARCO
+#undef RELEASE_FLAG_MACRO
+#undef DEBUG_FLAG_MACRO
+#undef PRODUCT_FLAG_MACRO
+#undef PRECOMPILE_FLAG_MACRO
 
 }  // namespace dart
 
diff --git a/runtime/vm/heap/heap.cc b/runtime/vm/heap/heap.cc
index 33487fb..26a8a5e 100644
--- a/runtime/vm/heap/heap.cc
+++ b/runtime/vm/heap/heap.cc
@@ -429,9 +429,19 @@
   if (old_space_.ShouldPerformIdleMarkCompact(deadline)) {
     TIMELINE_FUNCTION_GC_DURATION(thread, "IdleGC");
     CollectOldSpaceGarbage(thread, kMarkCompact, kIdle);
-  } else if (old_space_.ShouldPerformIdleMarkSweep(deadline)) {
-    TIMELINE_FUNCTION_GC_DURATION(thread, "IdleGC");
-    CollectOldSpaceGarbage(thread, kMarkSweep, kIdle);
+  } else if (old_space_.ShouldStartIdleMarkSweep(deadline)) {
+    PageSpace::Phase phase;
+    {
+      MonitorLocker ml(old_space_.tasks_lock());
+      phase = old_space_.phase();
+    }
+    if (phase == PageSpace::kAwaitingFinalization) {
+      TIMELINE_FUNCTION_GC_DURATION(thread, "IdleGC");
+      CollectOldSpaceGarbage(thread, Heap::kMarkSweep, Heap::kFinalize);
+    } else if (phase == PageSpace::kDone) {
+      TIMELINE_FUNCTION_GC_DURATION(thread, "IdleGC");
+      StartConcurrentMarking(thread);
+    }
   } else if (old_space_.NeedsGarbageCollection()) {
     // Even though the following GC may exceed our idle deadline, we need to
     // ensure than that promotions during idle scavenges do not lead to
@@ -446,7 +456,7 @@
 }
 
 void Heap::NotifyLowMemory() {
-  CollectAllGarbage(kLowMemory);
+  CollectMostGarbage(kLowMemory);
 }
 
 void Heap::EvacuateNewSpace(Thread* thread, GCReason reason) {
@@ -561,7 +571,8 @@
 void Heap::CollectMostGarbage(GCReason reason) {
   Thread* thread = Thread::Current();
   CollectNewSpaceGarbage(thread, reason);
-  CollectOldSpaceGarbage(thread, kMarkSweep, reason);
+  CollectOldSpaceGarbage(
+      thread, reason == kLowMemory ? kMarkCompact : kMarkSweep, reason);
 }
 
 void Heap::CollectAllGarbage(GCReason reason) {
@@ -570,8 +581,15 @@
   // New space is evacuated so this GC will collect all dead objects
   // kept alive by a cross-generational pointer.
   EvacuateNewSpace(thread, reason);
+  if (thread->is_marking()) {
+    // If incremental marking is happening, we need to finish the GC cycle
+    // and perform a follow-up GC to pruge any "floating garbage" that may be
+    // retained by the incremental barrier.
+    CollectOldSpaceGarbage(thread, kMarkSweep, reason);
+  }
   CollectOldSpaceGarbage(
       thread, reason == kLowMemory ? kMarkCompact : kMarkSweep, reason);
+  WaitForSweeperTasks(thread);
 }
 
 void Heap::CheckStartConcurrentMarking(Thread* thread, GCReason reason) {
@@ -583,11 +601,15 @@
   }
 
   if (old_space_.AlmostNeedsGarbageCollection()) {
-    if (BeginOldSpaceGC(thread)) {
-      TIMELINE_FUNCTION_GC_DURATION_BASIC(thread, "StartConcurrentMarking");
-      old_space_.CollectGarbage(/*compact=*/false, /*finalize=*/false);
-      EndOldSpaceGC();
-    }
+    StartConcurrentMarking(thread);
+  }
+}
+
+void Heap::StartConcurrentMarking(Thread* thread) {
+  if (BeginOldSpaceGC(thread)) {
+    TIMELINE_FUNCTION_GC_DURATION_BASIC(thread, "StartConcurrentMarking");
+    old_space_.CollectGarbage(/*compact=*/false, /*finalize=*/false);
+    EndOldSpaceGC();
   }
 }
 
diff --git a/runtime/vm/heap/heap.h b/runtime/vm/heap/heap.h
index 7414467..bedad67 100644
--- a/runtime/vm/heap/heap.h
+++ b/runtime/vm/heap/heap.h
@@ -133,7 +133,9 @@
   void CollectMostGarbage(GCReason reason = kFull);
 
   // Collect both generations by performing an evacuation followed by a
-  // mark-sweep. This function will collect all unreachable objects.
+  // mark-sweep. If incremental marking was in progress, perform another
+  // mark-sweep. This function will collect all unreachable objects, including
+  // those in inter-generational cycles or stored during incremental marking.
   void CollectAllGarbage(GCReason reason = kFull);
 
   bool NeedsGarbageCollection() const {
@@ -141,6 +143,7 @@
   }
 
   void CheckStartConcurrentMarking(Thread* thread, GCReason reason);
+  void StartConcurrentMarking(Thread* thread);
   void CheckFinishConcurrentMarking(Thread* thread);
   void WaitForMarkerTasks(Thread* thread);
   void WaitForSweeperTasks(Thread* thread);
@@ -506,6 +509,47 @@
   DISALLOW_COPY_AND_ASSIGN(BumpAllocateScope);
 };
 
+#if defined(TESTING)
+class GCTestHelper : public AllStatic {
+ public:
+  // Collect new gen without triggering any side effects. The normal call to
+  // CollectGarbage(Heap::kNew) could potentially trigger an old gen collection
+  // if there is enough promotion, and this can perturb some tests.
+  static void CollectNewSpace() {
+    Thread* thread = Thread::Current();
+    ASSERT(thread->execution_state() == Thread::kThreadInVM);
+    thread->heap()->new_space()->Scavenge();
+  }
+
+  // Fully collect old gen and wait for the sweeper to finish. The normal call
+  // to CollectGarbage(Heap::kOld) may leave so-called "floating garbage",
+  // objects that were seen by the incremental barrier but later made
+  // unreachable, and this can perturb some tests.
+  static void CollectOldSpace() {
+    Thread* thread = Thread::Current();
+    ASSERT(thread->execution_state() == Thread::kThreadInVM);
+    if (thread->is_marking()) {
+      thread->heap()->CollectGarbage(Heap::kMarkSweep, Heap::kDebugging);
+    }
+    thread->heap()->CollectGarbage(Heap::kMarkSweep, Heap::kDebugging);
+    WaitForGCTasks();
+  }
+
+  static void CollectAllGarbage() {
+    Thread* thread = Thread::Current();
+    ASSERT(thread->execution_state() == Thread::kThreadInVM);
+    thread->heap()->CollectAllGarbage(Heap::kDebugging);
+  }
+
+  static void WaitForGCTasks() {
+    Thread* thread = Thread::Current();
+    ASSERT(thread->execution_state() == Thread::kThreadInVM);
+    thread->heap()->WaitForMarkerTasks(thread);
+    thread->heap()->WaitForSweeperTasks(thread);
+  }
+};
+#endif  // TESTING
+
 }  // namespace dart
 
 #endif  // RUNTIME_VM_HEAP_HEAP_H_
diff --git a/runtime/vm/heap/heap_test.cc b/runtime/vm/heap/heap_test.cc
index 6ffad95..0bbe2fa 100644
--- a/runtime/vm/heap/heap_test.cc
+++ b/runtime/vm/heap/heap_test.cc
@@ -9,6 +9,7 @@
 #include "vm/globals.h"
 #include "vm/heap/become.h"
 #include "vm/heap/heap.h"
+#include "vm/object_graph.h"
 #include "vm/symbols.h"
 #include "vm/unit_test.h"
 
@@ -27,14 +28,19 @@
   EXPECT(!Dart_IsNull(result));
   EXPECT(Dart_IsList(result));
   TransitionNativeToVM transition(thread);
-  Isolate* isolate = Isolate::Current();
-  Heap* heap = isolate->heap();
-  heap->CollectGarbage(Heap::kOld);
+  GCTestHelper::CollectOldSpace();
 }
 
 #if !defined(PRODUCT)
 TEST_CASE(OldGC_Unsync) {
+  // Finalize any GC in progress as it is unsafe to change FLAG_marker_tasks
+  // when incremental marking is in progress.
+  {
+    TransitionNativeToVM transition(thread);
+    GCTestHelper::CollectAllGarbage();
+  }
   FLAG_marker_tasks = 0;
+
   const char* kScriptChars =
       "main() {\n"
       "  return [1, 2, 3];\n"
@@ -47,9 +53,7 @@
   EXPECT(!Dart_IsNull(result));
   EXPECT(Dart_IsList(result));
   TransitionNativeToVM transition(thread);
-  Isolate* isolate = Isolate::Current();
-  Heap* heap = isolate->heap();
-  heap->CollectGarbage(Heap::kOld);
+  GCTestHelper::CollectOldSpace();
 }
 #endif  // !defined(PRODUCT)
 
@@ -68,31 +72,16 @@
   EXPECT(Dart_IsList(result));
   {
     TransitionNativeToVM transition(thread);
-    thread->heap()->CollectGarbage(Heap::kOld);
+    GCTestHelper::CollectOldSpace();
   }
   Dart_ExitScope();
   {
     TransitionNativeToVM transition(thread);
-    thread->heap()->CollectGarbage(Heap::kOld);
+    GCTestHelper::CollectOldSpace();
   }
 }
 
 #ifndef PRODUCT
-class ClassHeapStatsTestHelper {
- public:
-  static ClassHeapStats* GetHeapStatsForCid(ClassTable* class_table,
-                                            intptr_t cid) {
-    return class_table->shared_class_table()->PreliminaryStatsAt(cid);
-  }
-
-  static void DumpClassHeapStats(ClassHeapStats* stats) {
-    OS::PrintErr("%" Pd " ", stats->recent.new_count.load());
-    OS::PrintErr("%" Pd " ", stats->post_gc.new_count.load());
-    OS::PrintErr("%" Pd " ", stats->pre_gc.new_count.load());
-    OS::PrintErr("\n");
-  }
-};
-
 static RawClass* GetClass(const Library& lib, const char* name) {
   const Class& cls = Class::Handle(
       lib.LookupClass(String::Handle(Symbols::New(Thread::Current(), name))));
@@ -111,17 +100,14 @@
       "  var x = new A();\n"
       "  return new A();\n"
       "}\n";
-  bool saved_concurrent_sweep_mode = FLAG_concurrent_sweep;
-  FLAG_concurrent_sweep = false;
   Dart_Handle h_lib = TestCase::LoadTestScript(kScriptChars, NULL);
   Isolate* isolate = Isolate::Current();
   ClassTable* class_table = isolate->class_table();
-  Heap* heap = isolate->heap();
   Dart_EnterScope();
   Dart_Handle result = Dart_Invoke(h_lib, NewString("main"), 0, NULL);
   EXPECT_VALID(result);
   EXPECT(!Dart_IsNull(result));
-  ClassHeapStats* class_stats;
+  intptr_t cid;
   {
     TransitionNativeToVM transition(thread);
     Library& lib = Library::Handle();
@@ -129,112 +115,86 @@
     EXPECT(!lib.IsNull());
     const Class& cls = Class::Handle(GetClass(lib, "A"));
     ASSERT(!cls.IsNull());
-    intptr_t cid = cls.id();
-    class_stats =
-        ClassHeapStatsTestHelper::GetHeapStatsForCid(class_table, cid);
-    // Verify preconditions:
-    EXPECT_EQ(0, class_stats->pre_gc.old_count);
-    EXPECT_EQ(0, class_stats->post_gc.old_count);
-    EXPECT_EQ(0, class_stats->recent.old_count);
-    EXPECT_EQ(0, class_stats->pre_gc.new_count);
-    EXPECT_EQ(0, class_stats->post_gc.new_count);
-    // Class allocated twice since GC from new space.
-    EXPECT_EQ(2, class_stats->recent.new_count);
+    cid = cls.id();
+
+    {
+      // Verify preconditions: allocated twice in new space.
+      CountObjectsVisitor visitor(thread, class_table->NumCids());
+      HeapIterationScope iter(thread);
+      iter.IterateObjects(&visitor);
+      isolate->VisitWeakPersistentHandles(&visitor);
+      EXPECT_EQ(2, visitor.new_count_[cid]);
+      EXPECT_EQ(0, visitor.old_count_[cid]);
+    }
+
     // Perform GC.
-    heap->CollectGarbage(Heap::kNew);
-    // Verify postconditions:
-    EXPECT_EQ(0, class_stats->pre_gc.old_count);
-    EXPECT_EQ(0, class_stats->post_gc.old_count);
-    EXPECT_EQ(0, class_stats->recent.old_count);
-    // Total allocations before GC.
-    EXPECT_EQ(2, class_stats->pre_gc.new_count);
-    // Only one survived.
-    EXPECT_EQ(1, class_stats->post_gc.new_count);
-    EXPECT_EQ(0, class_stats->recent.new_count);
+    GCTestHelper::CollectNewSpace();
+
+    {
+      // Verify postconditions: Only one survived.
+      CountObjectsVisitor visitor(thread, class_table->NumCids());
+      HeapIterationScope iter(thread);
+      iter.IterateObjects(&visitor);
+      isolate->VisitWeakPersistentHandles(&visitor);
+      EXPECT_EQ(1, visitor.new_count_[cid]);
+      EXPECT_EQ(0, visitor.old_count_[cid]);
+    }
+
     // Perform GC. The following is heavily dependent on the behaviour
     // of the GC: Retained instance of A will be promoted.
-    heap->CollectGarbage(Heap::kNew);
-    // Verify postconditions:
-    EXPECT_EQ(0, class_stats->pre_gc.old_count);
-    EXPECT_EQ(0, class_stats->post_gc.old_count);
-    // One promoted instance.
-    EXPECT_EQ(1, class_stats->promoted_count);
-    // Promotion counted as an allocation from old space.
-    EXPECT_EQ(1, class_stats->recent.old_count);
-    // There was one instance allocated before GC.
-    EXPECT_EQ(1, class_stats->pre_gc.new_count);
-    // There are no instances allocated in new space after GC.
-    EXPECT_EQ(0, class_stats->post_gc.new_count);
-    // No new allocations.
-    EXPECT_EQ(0, class_stats->recent.new_count);
+    GCTestHelper::CollectNewSpace();
+
+    {
+      // Verify postconditions: One promoted instance.
+      CountObjectsVisitor visitor(thread, class_table->NumCids());
+      HeapIterationScope iter(thread);
+      iter.IterateObjects(&visitor);
+      isolate->VisitWeakPersistentHandles(&visitor);
+      EXPECT_EQ(0, visitor.new_count_[cid]);
+      EXPECT_EQ(1, visitor.old_count_[cid]);
+    }
+
     // Perform a GC on new space.
-    heap->CollectGarbage(Heap::kNew);
-    // There were no instances allocated before GC.
-    EXPECT_EQ(0, class_stats->pre_gc.new_count);
-    // There are no instances allocated in new space after GC.
-    EXPECT_EQ(0, class_stats->post_gc.new_count);
-    // No new allocations.
-    EXPECT_EQ(0, class_stats->recent.new_count);
-    // Nothing was promoted.
-    EXPECT_EQ(0, class_stats->promoted_count);
-    heap->CollectGarbage(Heap::kOld);
-    // Verify postconditions:
-    EXPECT_EQ(1, class_stats->pre_gc.old_count);
-    EXPECT_EQ(1, class_stats->post_gc.old_count);
-    EXPECT_EQ(0, class_stats->recent.old_count);
+    GCTestHelper::CollectNewSpace();
+
+    {
+      // Verify postconditions:
+      CountObjectsVisitor visitor(thread, class_table->NumCids());
+      HeapIterationScope iter(thread);
+      iter.IterateObjects(&visitor);
+      isolate->VisitWeakPersistentHandles(&visitor);
+      EXPECT_EQ(0, visitor.new_count_[cid]);
+      EXPECT_EQ(1, visitor.old_count_[cid]);
+    }
+
+    GCTestHelper::CollectOldSpace();
+
+    {
+      // Verify postconditions:
+      CountObjectsVisitor visitor(thread, class_table->NumCids());
+      HeapIterationScope iter(thread);
+      iter.IterateObjects(&visitor);
+      isolate->VisitWeakPersistentHandles(&visitor);
+      EXPECT_EQ(0, visitor.new_count_[cid]);
+      EXPECT_EQ(1, visitor.old_count_[cid]);
+    }
   }
   // Exit scope, freeing instance.
   Dart_ExitScope();
   {
     TransitionNativeToVM transition(thread);
     // Perform GC.
-    heap->CollectGarbage(Heap::kOld);
-    // Verify postconditions:
-    EXPECT_EQ(1, class_stats->pre_gc.old_count);
-    EXPECT_EQ(0, class_stats->post_gc.old_count);
-    EXPECT_EQ(0, class_stats->recent.old_count);
-    // Perform GC.
-    heap->CollectGarbage(Heap::kOld);
-    EXPECT_EQ(0, class_stats->pre_gc.old_count);
-    EXPECT_EQ(0, class_stats->post_gc.old_count);
-    EXPECT_EQ(0, class_stats->recent.old_count);
+    GCTestHelper::CollectOldSpace();
+    {
+      // Verify postconditions:
+      CountObjectsVisitor visitor(thread, class_table->NumCids());
+      HeapIterationScope iter(thread);
+      iter.IterateObjects(&visitor);
+      isolate->VisitWeakPersistentHandles(&visitor);
+      EXPECT_EQ(0, visitor.new_count_[cid]);
+      EXPECT_EQ(0, visitor.old_count_[cid]);
+    }
   }
-  FLAG_concurrent_sweep = saved_concurrent_sweep_mode;
-}
-
-TEST_CASE(ArrayHeapStats) {
-  const char* kScriptChars =
-      "List f(int len) {\n"
-      "  return new List(len);\n"
-      "}\n"
-      ""
-      "main() {\n"
-      "  return f(1234);\n"
-      "}\n";
-  Dart_Handle h_lib = TestCase::LoadTestScript(kScriptChars, NULL);
-  Isolate* isolate = Isolate::Current();
-  ClassTable* class_table = isolate->class_table();
-  intptr_t cid = kArrayCid;
-  ClassHeapStats* class_stats =
-      ClassHeapStatsTestHelper::GetHeapStatsForCid(class_table, cid);
-  Dart_EnterScope();
-  // Invoke 'main' twice, since initial compilation might trigger extra array
-  // allocations.
-  Dart_Handle result = Dart_Invoke(h_lib, NewString("main"), 0, NULL);
-  EXPECT_VALID(result);
-  EXPECT(!Dart_IsNull(result));
-  intptr_t before = class_stats->recent.new_size;
-  Dart_Handle result2 = Dart_Invoke(h_lib, NewString("main"), 0, NULL);
-  EXPECT_VALID(result2);
-  EXPECT(!Dart_IsNull(result2));
-  intptr_t after = class_stats->recent.new_size;
-  const intptr_t expected_size = Array::InstanceSize(1234);
-  // Invoking the method might involve some additional tiny array allocations,
-  // so we allow slightly more than expected.
-  static const intptr_t kTolerance = 10 * kWordSize;
-  EXPECT_LE(expected_size, after - before);
-  EXPECT_GT(expected_size + kTolerance, after - before);
-  Dart_ExitScope();
 }
 #endif  // !PRODUCT
 
@@ -283,6 +243,11 @@
 
 ISOLATE_UNIT_TEST_CASE(IterateReadOnly) {
   const String& obj = String::Handle(String::New("x", Heap::kOld));
+
+  // It is not safe to make the heap read-only if marking or sweeping is in
+  // progress.
+  GCTestHelper::WaitForGCTasks();
+
   Heap* heap = Thread::Current()->isolate()->heap();
   EXPECT(heap->Contains(RawObject::ToAddr(obj.raw())));
   heap->WriteProtect(true);
@@ -292,9 +257,6 @@
 }
 
 void TestBecomeForward(Heap::Space before_space, Heap::Space after_space) {
-  Isolate* isolate = Isolate::Current();
-  Heap* heap = isolate->heap();
-
   const String& before_obj = String::Handle(String::New("old", before_space));
   const String& after_obj = String::Handle(String::New("new", after_space));
 
@@ -310,7 +272,7 @@
 
   EXPECT(before_obj.raw() == after_obj.raw());
 
-  heap->CollectAllGarbage();
+  GCTestHelper::CollectAllGarbage();
 
   EXPECT(before_obj.raw() == after_obj.raw());
 }
@@ -357,9 +319,6 @@
 }
 
 ISOLATE_UNIT_TEST_CASE(BecomeForwardRememberedObject) {
-  Isolate* isolate = Isolate::Current();
-  Heap* heap = isolate->heap();
-
   const String& new_element = String::Handle(String::New("new", Heap::kNew));
   const String& old_element = String::Handle(String::New("old", Heap::kOld));
   const Array& before_obj = Array::Handle(Array::New(1, Heap::kOld));
@@ -381,7 +340,7 @@
   EXPECT(before_obj.raw() == after_obj.raw());
   EXPECT(!after_obj.raw()->IsRemembered());
 
-  heap->CollectAllGarbage();
+  GCTestHelper::CollectAllGarbage();
 
   EXPECT(before_obj.raw() == after_obj.raw());
 }
@@ -395,18 +354,11 @@
   intptr_t size_before =
       heap->new_space()->UsedInWords() + heap->old_space()->UsedInWords();
 
-  {
-    // Prevent allocation from starting marking, otherwise the incremental write
-    // barrier will keep these objects live.
-    NoHeapGrowthControlScope force_growth;
-    EXPECT(!thread->is_marking());
-    Array& old = Array::Handle(Array::New(1, Heap::kOld));
-    Array& neu = Array::Handle(Array::New(1, Heap::kNew));
-    old.SetAt(0, neu);
-    old = Array::null();
-    neu = Array::null();
-    EXPECT(!thread->is_marking());
-  }
+  Array& old = Array::Handle(Array::New(1, Heap::kOld));
+  Array& neu = Array::Handle(Array::New(1, Heap::kNew));
+  old.SetAt(0, neu);
+  old = Array::null();
+  neu = Array::null();
 
   heap->CollectAllGarbage();
   heap->WaitForMarkerTasks(thread);  // Finalize marking to get live size.
@@ -426,18 +378,11 @@
   intptr_t size_before =
       heap->new_space()->UsedInWords() + heap->old_space()->UsedInWords();
 
-  {
-    // Prevent allocation from starting marking, otherwise the incremental write
-    // barrier will keep these objects live.
-    NoHeapGrowthControlScope force_growth;
-    EXPECT(!thread->is_marking());
-    Array& old = Array::Handle(Array::New(1, Heap::kOld));
-    Array& neu = Array::Handle(Array::New(1, Heap::kNew));
-    neu.SetAt(0, old);
-    old = Array::null();
-    neu = Array::null();
-    EXPECT(!thread->is_marking());
-  }
+  Array& old = Array::Handle(Array::New(1, Heap::kOld));
+  Array& neu = Array::Handle(Array::New(1, Heap::kNew));
+  neu.SetAt(0, old);
+  old = Array::null();
+  neu = Array::null();
 
   heap->CollectAllGarbage();
   heap->WaitForMarkerTasks(thread);  // Finalize marking to get live size.
@@ -457,19 +402,12 @@
   intptr_t size_before =
       heap->new_space()->UsedInWords() + heap->old_space()->UsedInWords();
 
-  {
-    // Prevent allocation from starting marking, otherwise the incremental write
-    // barrier will keep these objects live.
-    NoHeapGrowthControlScope force_growth;
-    EXPECT(!thread->is_marking());
-    Array& old = Array::Handle(Array::New(1, Heap::kOld));
-    Array& neu = Array::Handle(Array::New(1, Heap::kNew));
-    neu.SetAt(0, old);
-    old.SetAt(0, neu);
-    old = Array::null();
-    neu = Array::null();
-    EXPECT(!thread->is_marking());
-  }
+  Array& old = Array::Handle(Array::New(1, Heap::kOld));
+  Array& neu = Array::Handle(Array::New(1, Heap::kNew));
+  neu.SetAt(0, old);
+  old.SetAt(0, neu);
+  old = Array::null();
+  neu = Array::null();
 
   heap->CollectAllGarbage();
   heap->WaitForMarkerTasks(thread);  // Finalize marking to get live size.
@@ -489,17 +427,10 @@
   intptr_t size_before =
       heap->new_space()->UsedInWords() + heap->old_space()->UsedInWords();
 
-  {
-    // Prevent allocation from starting marking, otherwise the incremental write
-    // barrier will keep these objects live.
-    NoHeapGrowthControlScope force_growth;
-    EXPECT(!thread->is_marking());
-    Array& old = Array::Handle(Array::New(1, Heap::kOld));
-    Array& neu = Array::Handle(Array::New(1, Heap::kNew));
-    neu.SetAt(0, old);
-    old = Array::null();
-    EXPECT(!thread->is_marking());
-  }
+  Array& old = Array::Handle(Array::New(1, Heap::kOld));
+  Array& neu = Array::Handle(Array::New(1, Heap::kNew));
+  neu.SetAt(0, old);
+  old = Array::null();
 
   heap->CollectAllGarbage();
   heap->WaitForMarkerTasks(thread);  // Finalize marking to get live size.
@@ -519,17 +450,10 @@
   intptr_t size_before =
       heap->new_space()->UsedInWords() + heap->old_space()->UsedInWords();
 
-  {
-    // Prevent allocation from starting marking, otherwise the incremental write
-    // barrier will keep these objects live.
-    NoHeapGrowthControlScope force_growth;
-    EXPECT(!thread->is_marking());
-    Array& old = Array::Handle(Array::New(1, Heap::kOld));
-    Array& neu = Array::Handle(Array::New(1, Heap::kNew));
-    old.SetAt(0, neu);
-    neu = Array::null();
-    EXPECT(!thread->is_marking());
-  }
+  Array& old = Array::Handle(Array::New(1, Heap::kOld));
+  Array& neu = Array::Handle(Array::New(1, Heap::kNew));
+  old.SetAt(0, neu);
+  neu = Array::null();
 
   heap->CollectAllGarbage();
   heap->WaitForMarkerTasks(thread);  // Finalize marking to get live size.
@@ -549,17 +473,10 @@
   intptr_t size_before =
       heap->new_space()->UsedInWords() + heap->old_space()->UsedInWords();
 
-  {
-    // Prevent allocation from starting marking, otherwise the incremental write
-    // barrier will keep these objects live.
-    NoHeapGrowthControlScope force_growth;
-    EXPECT(!thread->is_marking());
-    Array& old = Array::Handle(Array::New(1, Heap::kOld));
-    Array& neu = Array::Handle(Array::New(1, Heap::kNew));
-    neu = Array::null();
-    old.SetAt(0, old);
-    EXPECT(!thread->is_marking());
-  }
+  Array& old = Array::Handle(Array::New(1, Heap::kOld));
+  Array& neu = Array::Handle(Array::New(1, Heap::kNew));
+  neu = Array::null();
+  old.SetAt(0, old);
 
   heap->CollectAllGarbage();
   heap->WaitForMarkerTasks(thread);  // Finalize marking to get live size.
@@ -579,17 +496,10 @@
   intptr_t size_before =
       heap->new_space()->UsedInWords() + heap->old_space()->UsedInWords();
 
-  {
-    // Prevent allocation from starting marking, otherwise the incremental write
-    // barrier will keep these objects live.
-    NoHeapGrowthControlScope force_growth;
-    EXPECT(!thread->is_marking());
-    Array& old = Array::Handle(Array::New(1, Heap::kOld));
-    Array& neu = Array::Handle(Array::New(1, Heap::kNew));
-    old = Array::null();
-    neu.SetAt(0, neu);
-    EXPECT(!thread->is_marking());
-  }
+  Array& old = Array::Handle(Array::New(1, Heap::kOld));
+  Array& neu = Array::Handle(Array::New(1, Heap::kNew));
+  old = Array::null();
+  neu.SetAt(0, neu);
 
   heap->CollectAllGarbage();
   heap->WaitForMarkerTasks(thread);  // Finalize marking to get live size.
@@ -608,20 +518,13 @@
   intptr_t size_before =
       heap->new_space()->UsedInWords() + heap->old_space()->UsedInWords();
 
-  {
-    // Prevent allocation from starting marking, otherwise the incremental write
-    // barrier will keep these objects live.
-    NoHeapGrowthControlScope force_growth;
-    EXPECT(!thread->is_marking());
-    Array& old = Array::Handle(Array::New(1, Heap::kOld));
-    Array& old2 = Array::Handle(Array::New(1, Heap::kOld));
-    Array& neu = Array::Handle(Array::New(1, Heap::kNew));
-    old.SetAt(0, old2);
-    neu.SetAt(0, old);
-    old = Array::null();
-    old2 = Array::null();
-    EXPECT(!thread->is_marking());
-  }
+  Array& old = Array::Handle(Array::New(1, Heap::kOld));
+  Array& old2 = Array::Handle(Array::New(1, Heap::kOld));
+  Array& neu = Array::Handle(Array::New(1, Heap::kNew));
+  old.SetAt(0, old2);
+  neu.SetAt(0, old);
+  old = Array::null();
+  old2 = Array::null();
 
   heap->CollectAllGarbage();
 
@@ -639,20 +542,13 @@
   intptr_t size_before =
       heap->new_space()->UsedInWords() + heap->old_space()->UsedInWords();
 
-  {
-    // Prevent allocation from starting marking, otherwise the incremental write
-    // barrier will keep these objects live.
-    NoHeapGrowthControlScope force_growth;
-    EXPECT(!thread->is_marking());
-    Array& old = Array::Handle(Array::New(1, Heap::kOld));
-    Array& neu = Array::Handle(Array::New(1, Heap::kNew));
-    Array& neu2 = Array::Handle(Array::New(1, Heap::kOld));
-    neu.SetAt(0, neu2);
-    old.SetAt(0, neu);
-    neu = Array::null();
-    neu2 = Array::null();
-    EXPECT(!thread->is_marking());
-  }
+  Array& old = Array::Handle(Array::New(1, Heap::kOld));
+  Array& neu = Array::Handle(Array::New(1, Heap::kNew));
+  Array& neu2 = Array::Handle(Array::New(1, Heap::kOld));
+  neu.SetAt(0, neu2);
+  old.SetAt(0, neu);
+  neu = Array::null();
+  neu2 = Array::null();
 
   heap->CollectAllGarbage();
 
@@ -728,14 +624,14 @@
       HeapTestHelper::Scavenge(thread);
     }
 
-    ClassHeapStats* stats = ClassHeapStatsTestHelper::GetHeapStatsForCid(
-        isolate->class_table(), kArrayCid);
-    EXPECT_LE(
-        stats->post_gc.old_external_size + stats->recent.old_external_size,
-        heap->old_space()->ExternalInWords() * kWordSize);
-    EXPECT_LE(
-        stats->post_gc.new_external_size + stats->recent.new_external_size,
-        heap->new_space()->ExternalInWords() * kWordSize);
+    CountObjectsVisitor visitor(thread, isolate->class_table()->NumCids());
+    HeapIterationScope iter(thread);
+    iter.IterateObjects(&visitor);
+    isolate->VisitWeakPersistentHandles(&visitor);
+    EXPECT_LE(visitor.old_external_size_[kArrayCid],
+              heap->old_space()->ExternalInWords() * kWordSize);
+    EXPECT_LE(visitor.new_external_size_[kArrayCid],
+              heap->new_space()->ExternalInWords() * kWordSize);
   }
 }
 #endif  // !defined(PRODUCT)
diff --git a/runtime/vm/heap/marker.cc b/runtime/vm/heap/marker.cc
index ae2ecce..7b451bd 100644
--- a/runtime/vm/heap/marker.cc
+++ b/runtime/vm/heap/marker.cc
@@ -394,16 +394,6 @@
     RawObject* raw_obj = handle->raw();
     if (IsUnreachable(raw_obj)) {
       handle->UpdateUnreachable(thread()->isolate());
-    } else {
-#ifndef PRODUCT
-      intptr_t cid = raw_obj->GetClassIdMayBeSmi();
-      intptr_t size = handle->external_size();
-      if (raw_obj->IsSmiOrOldObject()) {
-        class_table_->UpdateLiveOldExternal(cid, size);
-      } else {
-        class_table_->UpdateLiveNewExternal(cid, size);
-      }
-#endif  // !PRODUCT
     }
   }
 
@@ -700,7 +690,6 @@
       }
     }
 
-    isolate_->ScheduleInterrupts(Thread::kVMInterrupt);
     // Exit isolate cleanly *before* notifying it, to avoid shutdown race.
     Thread::ExitIsolateAsHelper(true);
     // This marker task is done. Notify the original isolate.
@@ -732,18 +721,6 @@
     MutexLocker ml(&stats_mutex_);
     marked_bytes_ += visitor->marked_bytes();
     marked_micros_ += visitor->marked_micros();
-#ifndef PRODUCT
-    // Class heap stats are not themselves thread-safe yet, so we update the
-    // stats while holding stats_mutex_.
-    auto table = heap_->isolate()->shared_class_table();
-    for (intptr_t i = 0; i < table->NumCids(); ++i) {
-      const intptr_t count = visitor->live_count(i);
-      if (count > 0) {
-        const intptr_t size = visitor->live_size(i);
-        table->UpdateLiveOld(i, size, count);
-      }
-    }
-#endif  // !PRODUCT
   }
   visitor->Finalize();
 }
diff --git a/runtime/vm/heap/pages.cc b/runtime/vm/heap/pages.cc
index 60a3fd7..7047236 100644
--- a/runtime/vm/heap/pages.cc
+++ b/runtime/vm/heap/pages.cc
@@ -536,9 +536,6 @@
 void PageSpace::AllocateExternal(intptr_t cid, intptr_t size) {
   intptr_t size_in_words = size >> kWordSizeLog2;
   usage_.external_in_words += size_in_words;
-  NOT_IN_PRODUCT(
-      heap_->isolate()->shared_class_table()->UpdateAllocatedExternalOld(cid,
-                                                                         size));
 }
 
 void PageSpace::PromoteExternal(intptr_t cid, intptr_t size) {
@@ -931,7 +928,7 @@
   }
 }
 
-bool PageSpace::ShouldPerformIdleMarkSweep(int64_t deadline) {
+bool PageSpace::ShouldStartIdleMarkSweep(int64_t deadline) {
   // To make a consistent decision, we should not yield for a safepoint in the
   // middle of deciding whether to perform an idle GC.
   NoSafepointScope no_safepoint;
@@ -950,8 +947,11 @@
     }
   }
 
+  // This uses the size of new-space because the pause time to start concurrent
+  // marking is related to the size of the root set, which is mostly new-space.
   int64_t estimated_mark_completion =
-      OS::GetCurrentMonotonicMicros() + UsedInWords() / mark_words_per_micro_;
+      OS::GetCurrentMonotonicMicros() +
+      heap_->new_space()->UsedInWords() / mark_words_per_micro_;
   return estimated_mark_completion <= deadline;
 }
 
@@ -1094,7 +1094,6 @@
     return;
   }
 
-  NOT_IN_PRODUCT(isolate->shared_class_table()->ResetCountersOld());
   marker_->MarkObjects(this);
   usage_.used_in_words = marker_->marked_words() + allocated_black_in_words_;
   allocated_black_in_words_ = 0;
diff --git a/runtime/vm/heap/pages.h b/runtime/vm/heap/pages.h
index 92472c8..5c705f0 100644
--- a/runtime/vm/heap/pages.h
+++ b/runtime/vm/heap/pages.h
@@ -358,7 +358,7 @@
   void WriteProtect(bool read_only);
   void WriteProtectCode(bool read_only);
 
-  bool ShouldPerformIdleMarkSweep(int64_t deadline);
+  bool ShouldStartIdleMarkSweep(int64_t deadline);
   bool ShouldPerformIdleMarkCompact(int64_t deadline);
 
   void AddGCTime(int64_t micros) { gc_time_micros_ += micros; }
diff --git a/runtime/vm/heap/scavenger.cc b/runtime/vm/heap/scavenger.cc
index 9ee2adb..01a8a96 100644
--- a/runtime/vm/heap/scavenger.cc
+++ b/runtime/vm/heap/scavenger.cc
@@ -245,7 +245,16 @@
     }
     // Update the reference.
     RawObject* new_obj = RawObject::FromAddr(new_addr);
-    *p = new_obj;
+    if (new_obj->IsOldObject()) {
+      // Setting the mark bit above must not be ordered after a publishing store
+      // of this object. Note this could be a publishing store even if the
+      // object was promoted by an early invocation of ScavengePointer. Compare
+      // Object::Allocate.
+      reinterpret_cast<std::atomic<RawObject*>*>(p)->store(
+          new_obj, std::memory_order_release);
+    } else {
+      *p = new_obj;
+    }
     // Update the store buffer as needed.
     if (visiting_old_object_ != NULL) {
       UpdateStoreBuffer(p, new_obj);
@@ -283,15 +292,6 @@
       handle->UpdateUnreachable(thread()->isolate());
     } else {
       handle->UpdateRelocated(thread()->isolate());
-#ifndef PRODUCT
-      intptr_t cid = (*p)->GetClassIdMayBeSmi();
-      intptr_t size = handle->external_size();
-      if ((*p)->IsSmiOrOldObject()) {
-        class_table_->UpdateLiveOldExternal(cid, size);
-      } else {
-        class_table_->UpdateLiveNewExternal(cid, size);
-      }
-#endif  // !PRODUCT
     }
   }
 
@@ -481,8 +481,6 @@
 }
 
 SemiSpace* Scavenger::Prologue(Isolate* isolate) {
-  NOT_IN_PRODUCT(isolate->shared_class_table()->ResetCountersNew());
-
   isolate->ReleaseStoreBuffers();
   AbandonTLABs(isolate);
 
@@ -587,8 +585,6 @@
   if (heap_ != NULL) {
     heap_->UpdateGlobalMaxUsed();
   }
-
-  NOT_IN_PRODUCT(isolate->shared_class_table()->UpdatePromoted());
 }
 
 bool Scavenger::ShouldPerformIdleScavenge(int64_t deadline) {
@@ -703,7 +699,6 @@
 
 void Scavenger::ProcessToSpace(ScavengerVisitor* visitor) {
   Thread* thread = Thread::Current();
-  NOT_IN_PRODUCT(auto class_table = visitor->isolate()->shared_class_table());
 
   // Iterate until all work has been drained.
   while ((resolved_top_ < top_) || PromotedStackHasMore()) {
@@ -717,7 +712,6 @@
         RawWeakProperty* raw_weak = reinterpret_cast<RawWeakProperty*>(raw_obj);
         size = ProcessWeakProperty(raw_weak, visitor);
       }
-      NOT_IN_PRODUCT(class_table->UpdateLiveNewGC(class_id, size));
       resolved_top_ += size;
     }
     {
@@ -730,12 +724,7 @@
         // objects to be resolved in the to space.
         ASSERT(!raw_object->IsRemembered());
         visitor->VisitingOldObject(raw_object);
-        intptr_t size = raw_object->VisitPointersNonvirtual(visitor);
-#if defined(PRODUCT)
-        USE(size);
-#else
-        class_table->UpdateAllocatedOldGC(raw_object->GetClassId(), size);
-#endif
+        raw_object->VisitPointersNonvirtual(visitor);
         if (raw_object->IsMarked()) {
           // Complete our promise from ScavengePointer. Note that marker cannot
           // visit this object until it pops a block from the mark stack, which
@@ -1155,9 +1144,6 @@
 void Scavenger::AllocateExternal(intptr_t cid, intptr_t size) {
   ASSERT(size >= 0);
   external_size_ += size;
-  NOT_IN_PRODUCT(
-      heap_->isolate()->shared_class_table()->UpdateAllocatedExternalNew(cid,
-                                                                         size));
 }
 
 void Scavenger::FreeExternal(intptr_t size) {
diff --git a/runtime/vm/image_snapshot.cc b/runtime/vm/image_snapshot.cc
index c1217a2..5adf25a 100644
--- a/runtime/vm/image_snapshot.cc
+++ b/runtime/vm/image_snapshot.cc
@@ -183,7 +183,7 @@
     case kCompressedStackMapsCid: {
       RawCompressedStackMaps* raw_maps =
           static_cast<RawCompressedStackMaps*>(raw_object);
-      return CompressedStackMapsSizeInSnapshot(raw_maps->ptr()->payload_size_);
+      return CompressedStackMapsSizeInSnapshot(raw_maps->ptr()->payload_size());
     }
     case kOneByteStringCid:
     case kTwoByteStringCid: {
@@ -381,9 +381,9 @@
       marked_tags = RawObject::SizeTag::update(size_in_bytes * 2, marked_tags);
 
       stream->WriteTargetWord(marked_tags);
-      stream->WriteFixed<uint32_t>(payload_size);
       // We do not need to align the stream to a word boundary on 64-bit because
       // sizeof(RawCompressedStackMaps) is 12, even there.
+      stream->WriteFixed<uint32_t>(map.raw()->ptr()->flags_and_size_);
       stream->WriteBytes(map.raw()->ptr()->data(), payload_size);
       stream->Align(compiler::target::ObjectAlignment::kObjectAlignment);
     } else if (obj.IsString()) {
diff --git a/runtime/vm/interpreter.cc b/runtime/vm/interpreter.cc
index aedda0b..80ef2bf 100644
--- a/runtime/vm/interpreter.cc
+++ b/runtime/vm/interpreter.cc
@@ -275,9 +275,6 @@
   const intptr_t remaining = thread->end() - start;
   if (LIKELY(remaining >= instance_size)) {
     thread->set_top(start + instance_size);
-#ifndef PRODUCT
-    table->UpdateAllocatedNew(class_id, instance_size);
-#endif
     *result = InitializeHeader(start, class_id, instance_size);
     return true;
   }
@@ -1238,6 +1235,65 @@
   return InvokeRuntime(thread, this, DRT_TypeCheck, native_args);
 }
 
+template <bool is_getter>
+bool Interpreter::AssertAssignableField(Thread* thread,
+                                        const KBCInstr* pc,
+                                        RawObject** FP,
+                                        RawObject** SP,
+                                        RawInstance* instance,
+                                        RawField* field,
+                                        RawInstance* value) {
+  RawAbstractType* field_type = field->ptr()->type_;
+  // Perform type test of value if field type is not one of dynamic, object,
+  // or void, and if the value is not null.
+  // TODO(regis): Revisit when type checking mode is not kUnaware anymore.
+  if (field_type->GetClassId() == kTypeCid) {
+    classid_t cid = Smi::Value(reinterpret_cast<RawSmi*>(
+        Type::RawCast(field_type)->ptr()->type_class_id_));
+    if (cid == kDynamicCid || cid == kInstanceCid || cid == kVoidCid) {
+      return true;
+    }
+  }
+  RawObject* null_value = Object::null();
+  if (value == null_value) {
+    return true;
+  }
+
+  RawSubtypeTestCache* cache = field->ptr()->type_test_cache_;
+  if (UNLIKELY(cache == null_value)) {
+    // Allocate new cache.
+    SP[1] = instance;    // Preserve.
+    SP[2] = field;       // Preserve.
+    SP[3] = value;       // Preserve.
+    SP[4] = null_value;  // Result slot.
+
+    Exit(thread, FP, SP + 5, pc);
+    if (!InvokeRuntime(thread, this, DRT_AllocateSubtypeTestCache,
+                       NativeArguments(thread, 0, /* argv */ SP + 4,
+                                       /* retval */ SP + 4))) {
+      return false;
+    }
+
+    // Reload objects after the call which may trigger GC.
+    instance = reinterpret_cast<RawInstance*>(SP[1]);
+    field = reinterpret_cast<RawField*>(SP[2]);
+    value = reinterpret_cast<RawInstance*>(SP[3]);
+    cache = reinterpret_cast<RawSubtypeTestCache*>(SP[4]);
+    field_type = field->ptr()->type_;
+    field->ptr()->type_test_cache_ = cache;
+  }
+
+  // Push arguments of type test.
+  SP[1] = value;
+  SP[2] = field_type;
+  // Provide type arguments of instance as instantiator.
+  SP[3] = InterpreterHelpers::GetTypeArguments(thread, instance);
+  SP[4] = null_value;  // Implicit setters cannot be generic.
+  SP[5] = is_getter ? Symbols::FunctionResult().raw() : field->ptr()->name_;
+  return AssertAssignable(thread, pc, FP, /* argv */ SP + 5,
+                          /* reval */ SP + 1, cache);
+}
+
 RawObject* Interpreter::Call(const Function& function,
                              const Array& arguments_descriptor,
                              const Array& arguments,
@@ -2253,6 +2309,21 @@
   }
 
   {
+    BYTECODE(PushUninitializedSentinel, 0);
+    *++SP = Object::sentinel().raw();
+    DISPATCH();
+  }
+
+  {
+    BYTECODE(JumpIfInitialized, T);
+    SP -= 1;
+    if (SP[1] != Object::sentinel().raw()) {
+      LOAD_JUMP_TARGET();
+    }
+    DISPATCH();
+  }
+
+  {
     BYTECODE(StoreStaticTOS, D);
     RawField* field = reinterpret_cast<RawField*>(LOAD_CONSTANT(rD));
     RawInstance* value = static_cast<RawInstance*>(*SP--);
@@ -3064,8 +3135,8 @@
     const intptr_t kArgc = 1;
     RawInstance* instance =
         reinterpret_cast<RawInstance*>(FrameArguments(FP, kArgc)[0]);
-    RawObject* value =
-        reinterpret_cast<RawObject**>(instance->ptr())[offset_in_words];
+    RawInstance* value =
+        reinterpret_cast<RawInstance**>(instance->ptr())[offset_in_words];
 
     if (UNLIKELY(value == Object::sentinel().raw())) {
       SP[1] = 0;  // Result slot.
@@ -3080,11 +3151,24 @@
       instance = reinterpret_cast<RawInstance*>(SP[2]);
       field = reinterpret_cast<RawField*>(SP[3]);
       offset_in_words = Smi::Value(field->ptr()->value_.offset_);
-      value = reinterpret_cast<RawObject**>(instance->ptr())[offset_in_words];
+      value = reinterpret_cast<RawInstance**>(instance->ptr())[offset_in_words];
     }
 
     *++SP = value;
 
+#if !defined(PRODUCT)
+    if (UNLIKELY(Field::NeedsLoadGuardBit::decode(field->ptr()->kind_bits_))) {
+      if (!AssertAssignableField<true>(thread, pc, FP, SP, instance, field,
+                                       value)) {
+        HANDLE_EXCEPTION;
+      }
+      // Reload objects after the call which may trigger GC.
+      field = reinterpret_cast<RawField*>(FrameFunction(FP)->ptr()->data_);
+      instance = reinterpret_cast<RawInstance*>(FrameArguments(FP, kArgc)[0]);
+      value = reinterpret_cast<RawInstance**>(instance->ptr())[offset_in_words];
+    }
+#endif
+
     const bool unboxing =
         (field->ptr()->is_nullable_ != kNullCid) &&
         Field::UnboxingCandidateBit::decode(field->ptr()->kind_bits_);
@@ -3131,60 +3215,17 @@
     const intptr_t kArgc = 2;
     RawInstance* instance =
         reinterpret_cast<RawInstance*>(FrameArguments(FP, kArgc)[0]);
-    RawObject* value = FrameArguments(FP, kArgc)[1];
+    RawInstance* value =
+        reinterpret_cast<RawInstance*>(FrameArguments(FP, kArgc)[1]);
 
-    RawAbstractType* field_type = field->ptr()->type_;
-    classid_t cid;
-    if (field_type->GetClassId() == kTypeCid) {
-      cid = Smi::Value(reinterpret_cast<RawSmi*>(
-          Type::RawCast(field_type)->ptr()->type_class_id_));
-    } else {
-      cid = kIllegalCid;  // Not really illegal, but not a Type to skip.
+    if (!AssertAssignableField<false>(thread, pc, FP, SP, instance, field,
+                                      value)) {
+      HANDLE_EXCEPTION;
     }
-    // Perform type test of value if field type is not one of dynamic, object,
-    // or void, and if the value is not null.
-    RawObject* null_value = Object::null();
-    // TODO(regis): Revisit when type checking mode is not kUnaware anymore.
-    if (cid != kDynamicCid && cid != kInstanceCid && cid != kVoidCid &&
-        value != null_value) {
-      RawSubtypeTestCache* cache = field->ptr()->type_test_cache_;
-      if (cache->GetClassId() != kSubtypeTestCacheCid) {
-        // Allocate new cache.
-        SP[1] = null_value;  // Result.
-
-        Exit(thread, FP, SP + 2, pc);
-        if (!InvokeRuntime(thread, this, DRT_AllocateSubtypeTestCache,
-                           NativeArguments(thread, 0, /* argv */ SP + 1,
-                                           /* retval */ SP + 1))) {
-          HANDLE_EXCEPTION;
-        }
-
-        // Reload objects after the call which may trigger GC.
-        field = reinterpret_cast<RawField*>(FrameFunction(FP)->ptr()->data_);
-        field_type = field->ptr()->type_;
-        instance = reinterpret_cast<RawInstance*>(FrameArguments(FP, kArgc)[0]);
-        value = FrameArguments(FP, kArgc)[1];
-        cache = reinterpret_cast<RawSubtypeTestCache*>(SP[1]);
-        field->ptr()->type_test_cache_ = cache;
-      }
-
-      // Push arguments of type test.
-      SP[1] = value;
-      SP[2] = field_type;
-      // Provide type arguments of instance as instantiator.
-      SP[3] = InterpreterHelpers::GetTypeArguments(thread, instance);
-      SP[4] = null_value;  // Implicit setters cannot be generic.
-      SP[5] = field->ptr()->name_;
-      if (!AssertAssignable(thread, pc, FP, /* argv */ SP + 5,
-                            /* reval */ SP + 1, cache)) {
-        HANDLE_EXCEPTION;
-      }
-
-      // Reload objects after the call which may trigger GC.
-      field = reinterpret_cast<RawField*>(FrameFunction(FP)->ptr()->data_);
-      instance = reinterpret_cast<RawInstance*>(FrameArguments(FP, kArgc)[0]);
-      value = FrameArguments(FP, kArgc)[1];
-    }
+    // Reload objects after the call which may trigger GC.
+    field = reinterpret_cast<RawField*>(FrameFunction(FP)->ptr()->data_);
+    instance = reinterpret_cast<RawInstance*>(FrameArguments(FP, kArgc)[0]);
+    value = reinterpret_cast<RawInstance*>(FrameArguments(FP, kArgc)[1]);
 
     if (InterpreterHelpers::FieldNeedsGuardUpdate(field, value)) {
       SP[1] = 0;  // Unused result of runtime call.
@@ -3200,7 +3241,7 @@
       // Reload objects after the call which may trigger GC.
       field = reinterpret_cast<RawField*>(FrameFunction(FP)->ptr()->data_);
       instance = reinterpret_cast<RawInstance*>(FrameArguments(FP, kArgc)[0]);
-      value = FrameArguments(FP, kArgc)[1];
+      value = reinterpret_cast<RawInstance*>(FrameArguments(FP, kArgc)[1]);
     }
 
     const bool unboxing =
@@ -3231,7 +3272,7 @@
       raw_value.writeTo(box->ptr()->value_);
     } else {
       instance->StorePointer(
-          reinterpret_cast<RawObject**>(instance->ptr()) + offset_in_words,
+          reinterpret_cast<RawInstance**>(instance->ptr()) + offset_in_words,
           value, thread);
     }
 
@@ -3269,6 +3310,16 @@
     // Field was initialized. Return its value.
     *++SP = value;
 
+#if !defined(PRODUCT)
+    if (UNLIKELY(Field::NeedsLoadGuardBit::decode(field->ptr()->kind_bits_))) {
+      if (!AssertAssignableField<true>(
+              thread, pc, FP, SP, reinterpret_cast<RawInstance*>(null_value),
+              field, value)) {
+        HANDLE_EXCEPTION;
+      }
+    }
+#endif
+
     DISPATCH();
   }
 
@@ -3396,7 +3447,6 @@
 
     // Function 'call' could not be resolved for argdesc_.
     // Invoke noSuchMethod.
-    RawObject* null_value = Object::null();
     SP[1] = null_value;
     SP[2] = receiver;
     SP[3] = argdesc_;
diff --git a/runtime/vm/interpreter.h b/runtime/vm/interpreter.h
index c7e3445..03d913a 100644
--- a/runtime/vm/interpreter.h
+++ b/runtime/vm/interpreter.h
@@ -13,21 +13,23 @@
 
 namespace dart {
 
-class Isolate;
-class RawObject;
-class InterpreterSetjmpBuffer;
-class Thread;
-class Code;
 class Array;
+class Code;
+class InterpreterSetjmpBuffer;
+class Isolate;
+class ObjectPointerVisitor;
+class RawArray;
+class RawField;
+class RawFunction;
 class RawICData;
 class RawImmutableArray;
-class RawArray;
+class RawInstance;
+class RawObject;
 class RawObjectPool;
-class RawFunction;
 class RawString;
 class RawSubtypeTestCache;
 class RawTypeArguments;
-class ObjectPointerVisitor;
+class Thread;
 
 class LookupCache : public ValueObject {
  public:
@@ -198,6 +200,14 @@
                         RawObject** call_top,
                         RawObject** args,
                         RawSubtypeTestCache* cache);
+  template <bool is_getter>
+  bool AssertAssignableField(Thread* thread,
+                             const KBCInstr* pc,
+                             RawObject** FP,
+                             RawObject** SP,
+                             RawInstance* instance,
+                             RawField* field,
+                             RawInstance* value);
 
   bool AllocateMint(Thread* thread,
                     int64_t value,
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index f1ea56d..a63c300 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -208,9 +208,13 @@
     : embedder_data_(embedder_data),
       isolates_rwlock_(new RwLock()),
       isolates_(),
+#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
+      last_reload_timestamp_(OS::GetCurrentTimeMillis()),
+#endif
       source_(std::move(source)),
       thread_registry_(new ThreadRegistry()),
-      safepoint_handler_(new SafepointHandler(this)) {}
+      safepoint_handler_(new SafepointHandler(this)) {
+}
 
 IsolateGroup::~IsolateGroup() {}
 
@@ -517,7 +521,7 @@
 
 void Isolate::RegisterClass(const Class& cls) {
 #if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
-  if (IsReloading()) {
+  if (group()->IsReloading()) {
     reload_context()->RegisterClass(cls);
     return;
   }
@@ -1242,7 +1246,6 @@
       ISOLATE_METRIC_LIST(ISOLATE_METRIC_CONSTRUCTORS)
 #undef ISOLATE_METRIC_CONSTRUCTORS
           reload_every_n_stack_overflow_checks_(FLAG_reload_every),
-      last_reload_timestamp_(OS::GetCurrentTimeMillis()),
 #endif  // !defined(PRODUCT)
       start_time_micros_(OS::GetCurrentMonotonicMicros()),
       random_(),
@@ -1592,52 +1595,85 @@
 #if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
 bool Isolate::CanReload() const {
   return !Isolate::IsVMInternalIsolate(this) && is_runnable() &&
-         !IsReloading() && (no_reload_scope_depth_ == 0) &&
+         !group()->IsReloading() && (no_reload_scope_depth_ == 0) &&
          IsolateCreationEnabled() &&
          OSThread::Current()->HasStackHeadroom(64 * KB);
 }
 
-bool Isolate::ReloadSources(JSONStream* js,
-                            bool force_reload,
-                            const char* root_script_url,
-                            const char* packages_url,
-                            bool dont_delete_reload_context) {
+bool IsolateGroup::ReloadSources(JSONStream* js,
+                                 bool force_reload,
+                                 const char* root_script_url,
+                                 const char* packages_url,
+                                 bool dont_delete_reload_context) {
   ASSERT(!IsReloading());
-  SetHasAttemptedReload(true);
-  reload_context_ = new IsolateReloadContext(this, js);
-  reload_context_->Reload(force_reload, root_script_url, packages_url,
-                          /* kernel_buffer= */ nullptr,
-                          /* kernel_buffer_size= */ 0);
-  bool success = !reload_context_->reload_aborted();
+
+  // TODO(dartbug.com/36097): Support multiple isolates within an isolate group.
+  RELEASE_ASSERT(!FLAG_enable_isolate_groups);
+  RELEASE_ASSERT(isolates_.First() == isolates_.Last());
+  RELEASE_ASSERT(isolates_.First() == Isolate::Current());
+
+  auto shared_class_table = Isolate::Current()->shared_class_table();
+  std::shared_ptr<IsolateGroupReloadContext> group_reload_context(
+      new IsolateGroupReloadContext(this, shared_class_table, js));
+  group_reload_context_ = group_reload_context;
+
+  ForEachIsolate([&](Isolate* isolate) {
+    isolate->SetHasAttemptedReload(true);
+    isolate->reload_context_ =
+        new IsolateReloadContext(group_reload_context_, isolate);
+  });
+  const bool success =
+      group_reload_context_->Reload(force_reload, root_script_url, packages_url,
+                                    /*kernel_buffer=*/nullptr,
+                                    /*kernel_buffer_size=*/0);
   if (!dont_delete_reload_context) {
+    ForEachIsolate([&](Isolate* isolate) { isolate->DeleteReloadContext(); });
     DeleteReloadContext();
   }
   return success;
 }
 
-bool Isolate::ReloadKernel(JSONStream* js,
-                           bool force_reload,
-                           const uint8_t* kernel_buffer,
-                           intptr_t kernel_buffer_size,
-                           bool dont_delete_reload_context) {
+bool IsolateGroup::ReloadKernel(JSONStream* js,
+                                bool force_reload,
+                                const uint8_t* kernel_buffer,
+                                intptr_t kernel_buffer_size,
+                                bool dont_delete_reload_context) {
   ASSERT(!IsReloading());
-  SetHasAttemptedReload(true);
-  reload_context_ = new IsolateReloadContext(this, js);
-  reload_context_->Reload(force_reload,
-                          /* root_script_url= */ nullptr,
-                          /* packages_url= */ nullptr, kernel_buffer,
-                          kernel_buffer_size);
-  bool success = !reload_context_->reload_aborted();
+
+  // TODO(dartbug.com/36097): Support multiple isolates within an isolate group.
+  RELEASE_ASSERT(!FLAG_enable_isolate_groups);
+  RELEASE_ASSERT(isolates_.First() == isolates_.Last());
+  RELEASE_ASSERT(isolates_.First() == Isolate::Current());
+
+  auto shared_class_table = Isolate::Current()->shared_class_table();
+  std::shared_ptr<IsolateGroupReloadContext> group_reload_context(
+      new IsolateGroupReloadContext(this, shared_class_table, js));
+  group_reload_context_ = group_reload_context;
+
+  ForEachIsolate([&](Isolate* isolate) {
+    isolate->SetHasAttemptedReload(true);
+    isolate->reload_context_ =
+        new IsolateReloadContext(group_reload_context_, isolate);
+  });
+  const bool success = group_reload_context_->Reload(
+      force_reload,
+      /*root_script_url=*/nullptr,
+      /*packages_url=*/nullptr, kernel_buffer, kernel_buffer_size);
   if (!dont_delete_reload_context) {
+    ForEachIsolate([&](Isolate* isolate) { isolate->DeleteReloadContext(); });
     DeleteReloadContext();
   }
   return success;
 }
 
+void IsolateGroup::DeleteReloadContext() {
+  SafepointOperationScope safepoint_scope(Thread::Current());
+  group_reload_context_.reset();
+}
+
 void Isolate::DeleteReloadContext() {
   // Another thread may be in the middle of GetClassForHeapWalkAt.
-  Thread* thread = Thread::Current();
-  SafepointOperationScope safepoint_scope(thread);
+  SafepointOperationScope safepoint_scope(Thread::Current());
 
   delete reload_context_;
   reload_context_ = nullptr;
@@ -2334,6 +2370,7 @@
   // Visit objects that are being used for isolate reload.
   if (reload_context() != nullptr) {
     reload_context()->VisitObjectPointers(visitor);
+    reload_context()->group_reload_context()->VisitObjectPointers(visitor);
   }
 #endif  // !defined(DART_PRECOMPILED_RUNTIME)
   if (ServiceIsolate::IsServiceIsolate(this)) {
@@ -2393,6 +2430,14 @@
   ASSERT(!Thread::Current()->is_marking());
 }
 
+void IsolateGroup::ForEachIsolate(
+    std::function<void(Isolate* isolate)> function) {
+  ReadRwLocker wl(ThreadState::Current(), isolates_rwlock_.get());
+  for (Isolate* isolate : isolates_) {
+    function(isolate);
+  }
+}
+
 void IsolateGroup::RunWithStoppedMutators(
     std::function<void()> single_current_mutator,
     std::function<void()> otherwise,
@@ -2420,7 +2465,7 @@
 RawClass* Isolate::GetClassForHeapWalkAt(intptr_t cid) {
   RawClass* raw_class = nullptr;
 #if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
-  if (IsReloading()) {
+  if (group()->IsReloading()) {
     raw_class = reload_context()->GetClassForHeapWalkAt(cid);
   } else {
     raw_class = class_table()->At(cid);
@@ -2435,8 +2480,8 @@
 
 intptr_t Isolate::GetClassSizeForHeapWalkAt(intptr_t cid) {
 #if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
-  if (IsReloading()) {
-    return reload_context()->GetClassSizeForHeapWalkAt(cid);
+  if (group()->IsReloading()) {
+    return group()->reload_context()->GetClassSizeForHeapWalkAt(cid);
   } else {
     return class_table()->SizeAt(cid);
   }
@@ -2525,7 +2570,7 @@
   jsobj.AddProperty("livePorts", message_handler()->live_ports());
   jsobj.AddProperty("pauseOnExit", message_handler()->should_pause_on_exit());
 #if !defined(DART_PRECOMPILED_RUNTIME)
-  jsobj.AddProperty("_isReloading", IsReloading());
+  jsobj.AddProperty("_isReloading", group()->IsReloading());
 #endif  // !defined(DART_PRECOMPILED_RUNTIME)
 
   if (!is_runnable()) {
@@ -2957,7 +3002,9 @@
 #if !defined(DART_PRECOMPILED_RUNTIME)
   const bool had_isolate_reload_context = reload_context() != nullptr;
   const int64_t start_time_micros =
-      !had_isolate_reload_context ? 0 : reload_context()->start_time_micros();
+      !had_isolate_reload_context
+          ? 0
+          : reload_context()->group_reload_context()->start_time_micros();
 #endif  // !defined(DART_PRECOMPILED_RUNTIME)
   bool resume = false;
   bool handle_non_service_messages = false;
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index 9c83e6b..b5913f8 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -302,6 +302,12 @@
     library_tag_handler_ = handler;
   }
 
+  // Runs the given [function] on every isolate in the isolate group.
+  //
+  // During the duration of this function, no new isolates can be added to the
+  // isolate group.
+  void ForEachIsolate(std::function<void(Isolate* isolate)> function);
+
   // Ensures mutators are stopped during execution of the provided function.
   //
   // If the current thread is the only mutator in the isolate group,
@@ -329,6 +335,36 @@
   void PrintMemoryUsageJSON(JSONStream* stream);
 #endif
 
+#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
+  // By default the reload context is deleted. This parameter allows
+  // the caller to delete is separately if it is still needed.
+  bool ReloadSources(JSONStream* js,
+                     bool force_reload,
+                     const char* root_script_url = nullptr,
+                     const char* packages_url = nullptr,
+                     bool dont_delete_reload_context = false);
+
+  // If provided, the VM takes ownership of kernel_buffer.
+  bool ReloadKernel(JSONStream* js,
+                    bool force_reload,
+                    const uint8_t* kernel_buffer = nullptr,
+                    intptr_t kernel_buffer_size = 0,
+                    bool dont_delete_reload_context = false);
+
+  void set_last_reload_timestamp(int64_t value) {
+    last_reload_timestamp_ = value;
+  }
+  int64_t last_reload_timestamp() const { return last_reload_timestamp_; }
+
+  IsolateGroupReloadContext* reload_context() {
+    return group_reload_context_.get();
+  }
+
+  void DeleteReloadContext();
+
+  bool IsReloading() const { return group_reload_context_ != nullptr; }
+#endif  // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
+
   uint64_t id() { return id_; }
 
   static void Init();
@@ -352,6 +388,11 @@
   bool initial_spawn_successful_ = false;
   Dart_LibraryTagHandler library_tag_handler_ = nullptr;
 
+#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
+  int64_t last_reload_timestamp_;
+  std::shared_ptr<IsolateGroupReloadContext> group_reload_context_;
+#endif
+
   std::unique_ptr<IsolateGroupSource> source_;
   std::unique_ptr<ThreadRegistry> thread_registry_;
   std::unique_ptr<SafepointHandler> safepoint_handler_;
@@ -528,23 +569,6 @@
 
   void ScheduleInterrupts(uword interrupt_bits);
 
-#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
-  // By default the reload context is deleted. This parameter allows
-  // the caller to delete is separately if it is still needed.
-  bool ReloadSources(JSONStream* js,
-                     bool force_reload,
-                     const char* root_script_url = nullptr,
-                     const char* packages_url = nullptr,
-                     bool dont_delete_reload_context = false);
-
-  // If provided, the VM takes ownership of kernel_buffer.
-  bool ReloadKernel(JSONStream* js,
-                    bool force_reload,
-                    const uint8_t* kernel_buffer = nullptr,
-                    intptr_t kernel_buffer_size = 0,
-                    bool dont_delete_reload_context = false);
-#endif  // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
-
   const char* MakeRunnable();
   void Run();
 
@@ -765,8 +789,6 @@
   VMTagCounters* vm_tag_counters() { return &vm_tag_counters_; }
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
-  bool IsReloading() const { return reload_context_ != nullptr; }
-
   IsolateReloadContext* reload_context() { return reload_context_; }
 
   void DeleteReloadContext();
@@ -779,11 +801,6 @@
   }
 
   bool CanReload() const;
-
-  void set_last_reload_timestamp(int64_t value) {
-    last_reload_timestamp_ = value;
-  }
-  int64_t last_reload_timestamp() const { return last_reload_timestamp_; }
 #else
   bool IsReloading() const { return false; }
   bool HasAttemptedReload() const { return false; }
@@ -1147,10 +1164,7 @@
   V(HasAttemptedReload)                                                        \
   V(HasAttemptedStepping)                                                      \
   V(ShouldPausePostServiceRequest)                                             \
-  V(EnableTypeChecks)                                                          \
   V(EnableAsserts)                                                             \
-  V(ErrorOnBadType)                                                            \
-  V(ErrorOnBadOverride)                                                        \
   V(UseFieldGuards)                                                            \
   V(UseOsr)                                                                    \
   V(Obfuscate)                                                                 \
@@ -1216,7 +1230,6 @@
   // Per-isolate copy of FLAG_reload_every.
   intptr_t reload_every_n_stack_overflow_checks_;
   IsolateReloadContext* reload_context_ = nullptr;
-  int64_t last_reload_timestamp_;
   // Ring buffer of objects assigned an id.
   ObjectIdRing* object_id_ring_ = nullptr;
 #endif  // !defined(PRODUCT)
@@ -1323,6 +1336,7 @@
   friend class Thread;
   friend class Timeline;
   friend class NoReloadScope;  // reload_block
+  friend class IsolateGroup;   // reload_context_
 
   DISALLOW_COPY_AND_ASSIGN(Isolate);
 };
diff --git a/runtime/vm/isolate_reload.cc b/runtime/vm/isolate_reload.cc
index 4b7914b..7cb3ca6 100644
--- a/runtime/vm/isolate_reload.cc
+++ b/runtime/vm/isolate_reload.cc
@@ -54,50 +54,75 @@
             check_reloaded,
             false,
             "Assert that an isolate has reloaded at least once.")
+DEFINE_FLAG(bool, gc_during_reload, false, "Cause explicit GC during reload.");
 
 DECLARE_FLAG(bool, trace_deoptimization);
 
 #define I (isolate())
-#define Z (thread->zone())
+#define Z zone_
 
 #define TIMELINE_SCOPE(name)                                                   \
   TimelineDurationScope tds##name(Thread::Current(),                           \
                                   Timeline::GetIsolateStream(), #name)
 
-InstanceMorpher::InstanceMorpher(Zone* zone, const Class& from, const Class& to)
-    : from_(Class::Handle(zone, from.raw())),
-      to_(Class::Handle(zone, to.raw())),
-      mapping_(zone, 0) {
-  before_ = new (zone) ZoneGrowableArray<const Instance*>(zone, 0);
-  after_ = new (zone) ZoneGrowableArray<const Instance*>(zone, 0);
-  new_fields_ = new (zone) ZoneGrowableArray<const Field*>(zone, 0);
-  ASSERT(from_.id() == to_.id());
-  cid_ = from_.id();
-  ComputeMapping();
+// The ObjectLocator is used for collecting instances that
+// needs to be morphed.
+class ObjectLocator : public ObjectVisitor {
+ public:
+  explicit ObjectLocator(IsolateGroupReloadContext* context)
+      : context_(context), count_(0) {}
+
+  void VisitObject(RawObject* obj) {
+    InstanceMorpher* morpher =
+        context_->instance_morpher_by_cid_.LookupValue(obj->GetClassId());
+    if (morpher != NULL) {
+      morpher->AddObject(obj);
+      count_++;
+    }
+  }
+
+  // Return the number of located objects for morphing.
+  intptr_t count() { return count_; }
+
+ private:
+  IsolateGroupReloadContext* context_;
+  intptr_t count_;
+};
+
+static bool HasNoTasks(Heap* heap) {
+  MonitorLocker ml(heap->old_space()->tasks_lock());
+  return heap->old_space()->tasks() == 0;
 }
 
-void InstanceMorpher::AddObject(RawObject* object) const {
-  ASSERT(object->GetClassId() == cid());
-  const Instance& instance = Instance::Cast(Object::Handle(object));
-  before_->Add(&instance);
-}
+// TODO(dartbug.com/36097): Once classes are split up into a read-only
+// descriptor which can be shared across isolates, we can make this function
+// take descriptors instead of the isolate-specific [Class] objects.
+//
+// (The information we access from [from]/[to] *must* be the same across
+// isolates.)
+InstanceMorpher* InstanceMorpher::CreateFromClassDescriptors(
+    Zone* zone,
+    SharedClassTable* shared_class_table,
+    const Class& from,
+    const Class& to) {
+  auto mapping = new (zone) ZoneGrowableArray<intptr_t>();
+  auto new_fields_offsets = new (zone) ZoneGrowableArray<intptr_t>();
 
-void InstanceMorpher::ComputeMapping() {
-  if (from_.NumTypeArguments() > 0) {
+  if (from.NumTypeArguments() > 0) {
     // Add copying of the optional type argument field.
-    intptr_t from_offset = from_.type_arguments_field_offset();
+    intptr_t from_offset = from.type_arguments_field_offset();
     ASSERT(from_offset != Class::kNoTypeArguments);
-    intptr_t to_offset = to_.type_arguments_field_offset();
+    intptr_t to_offset = to.type_arguments_field_offset();
     ASSERT(to_offset != Class::kNoTypeArguments);
-    mapping_.Add(from_offset);
-    mapping_.Add(to_offset);
+    mapping->Add(from_offset);
+    mapping->Add(to_offset);
   }
 
   // Add copying of the instance fields if matching by name.
   // Note: currently the type of the fields are ignored.
   const Array& from_fields =
-      Array::Handle(from_.OffsetToFieldMap(true /* original classes */));
-  const Array& to_fields = Array::Handle(to_.OffsetToFieldMap());
+      Array::Handle(from.OffsetToFieldMap(true /* original classes */));
+  const Array& to_fields = Array::Handle(to.OffsetToFieldMap());
   Field& from_field = Field::Handle();
   Field& to_field = Field::Handle();
   String& from_name = String::Handle();
@@ -127,8 +152,8 @@
       from_name = from_field.name();
       if (from_name.Equals(to_name)) {
         // Success
-        mapping_.Add(from_field.Offset());
-        mapping_.Add(to_field.Offset());
+        mapping->Add(from_field.Offset());
+        mapping->Add(to_field.Offset());
         // Field did exist in old class deifnition.
         new_field = false;
       }
@@ -136,91 +161,97 @@
 
     if (new_field) {
       const Field& field = Field::Handle(to_field.raw());
-      new_fields_->Add(&field);
-
       field.set_needs_load_guard(true);
       field.set_is_unboxing_candidate(false);
+      new_fields_offsets->Add(field.Offset());
     }
   }
+
+  ASSERT(from.id() == to.id());
+  return new (zone) InstanceMorpher(zone, to.id(), shared_class_table, mapping,
+                                    new_fields_offsets);
+}
+
+InstanceMorpher::InstanceMorpher(
+    Zone* zone,
+    classid_t cid,
+    SharedClassTable* shared_class_table,
+    ZoneGrowableArray<intptr_t>* mapping,
+    ZoneGrowableArray<intptr_t>* new_fields_offsets)
+    : zone_(zone),
+      cid_(cid),
+      shared_class_table_(shared_class_table),
+      mapping_(mapping),
+      new_fields_offsets_(new_fields_offsets),
+      before_(zone, 16),
+      after_(zone, 16) {}
+
+void InstanceMorpher::AddObject(RawObject* object) {
+  ASSERT(object->GetClassId() == cid_);
+  const Instance& instance = Instance::Cast(Object::Handle(Z, object));
+  before_.Add(&instance);
 }
 
 RawInstance* InstanceMorpher::Morph(const Instance& instance) const {
-  const Instance& result = Instance::Handle(Instance::New(to_));
+  const auto& result = Instance::Handle(
+      Z, Instance::NewFromCidAndSize(shared_class_table_, cid_));
+
+#if defined(HASH_IN_OBJECT_HEADER)
+  const uint32_t hash = Object::GetCachedHash(instance.raw());
+  Object::SetCachedHash(result.raw(), hash);
+#endif
+
   // Morph the context from instance to result using mapping_.
-  for (intptr_t i = 0; i < mapping_.length(); i += 2) {
-    intptr_t from_offset = mapping_.At(i);
-    intptr_t to_offset = mapping_.At(i + 1);
-    const Object& value =
-        Object::Handle(instance.RawGetFieldAtOffset(from_offset));
+  Object& value = Object::Handle(Z);
+  for (intptr_t i = 0; i < mapping_->length(); i += 2) {
+    intptr_t from_offset = mapping_->At(i);
+    intptr_t to_offset = mapping_->At(i + 1);
+    ASSERT(from_offset > 0);
+    ASSERT(to_offset > 0);
+    value = instance.RawGetFieldAtOffset(from_offset);
     result.RawSetFieldAtOffset(to_offset, value);
   }
-  for (intptr_t i = 0; i < new_fields_->length(); i++) {
-    // Create a function that returns the expression.
-    const Field* field = new_fields_->At(i);
-    ASSERT(field->needs_load_guard());
-    result.RawSetFieldAtOffset(field->Offset(), Object::sentinel());
+
+  for (intptr_t i = 0; i < new_fields_offsets_->length(); i++) {
+    const intptr_t field_offset = new_fields_offsets_->At(i);
+    result.RawSetFieldAtOffset(field_offset, Object::sentinel());
   }
+
   // Convert the instance into a filler object.
   Become::MakeDummyObject(instance);
   return result.raw();
 }
 
-void InstanceMorpher::CreateMorphedCopies() const {
-  for (intptr_t i = 0; i < before()->length(); i++) {
-    const Instance& copy = Instance::Handle(Morph(*before()->At(i)));
-    after()->Add(&copy);
+void InstanceMorpher::CreateMorphedCopies() {
+  for (intptr_t i = 0; i < before_.length(); i++) {
+    const Instance& copy = Instance::Handle(Z, Morph(*before_.At(i)));
+    after_.Add(&copy);
   }
 }
 
-void InstanceMorpher::DumpFormatFor(const Class& cls) const {
-  THR_Print("%s\n", cls.ToCString());
-  if (cls.NumTypeArguments() > 0) {
-    intptr_t field_offset = cls.type_arguments_field_offset();
-    ASSERT(field_offset != Class::kNoTypeArguments);
-    THR_Print("  - @%" Pd " <type arguments>\n", field_offset);
-  }
-  const Array& fields = Array::Handle(cls.OffsetToFieldMap());
-  Field& field = Field::Handle();
-  String& name = String::Handle();
-  for (intptr_t i = 0; i < fields.Length(); i++) {
-    if (fields.At(i) != Field::null()) {
-      field = Field::RawCast(fields.At(i));
-      ASSERT(field.is_instance());
-      name = field.name();
-      THR_Print("  - @%" Pd " %s\n", field.Offset(), name.ToCString());
-    }
-  }
-
-  THR_Print("Mapping: ");
-  for (int i = 0; i < mapping_.length(); i += 2) {
-    THR_Print(" %" Pd "->%" Pd, mapping_.At(i), mapping_.At(i + 1));
-  }
-  THR_Print("\n");
-}
-
 void InstanceMorpher::Dump() const {
   LogBlock blocker;
-  THR_Print("Morphing from ");
-  DumpFormatFor(from_);
-  THR_Print("To ");
-  DumpFormatFor(to_);
+  THR_Print("Morphing objects with cid: %d via this mapping: ", cid_);
+  for (int i = 0; i < mapping_->length(); i += 2) {
+    THR_Print(" %" Pd "->%" Pd, mapping_->At(i), mapping_->At(i + 1));
+  }
   THR_Print("\n");
 }
 
 void InstanceMorpher::AppendTo(JSONArray* array) {
   JSONObject jsobj(array);
   jsobj.AddProperty("type", "ShapeChangeMapping");
-  jsobj.AddProperty("class", to_);
-  jsobj.AddProperty("instanceCount", before()->length());
+  jsobj.AddProperty64("class-id", cid_);
+  jsobj.AddProperty("instanceCount", before_.length());
   JSONArray map(&jsobj, "fieldOffsetMappings");
-  for (int i = 0; i < mapping_.length(); i += 2) {
+  for (int i = 0; i < mapping_->length(); i += 2) {
     JSONArray pair(&map);
-    pair.AddValue(mapping_.At(i));
-    pair.AddValue(mapping_.At(i + 1));
+    pair.AddValue(mapping_->At(i));
+    pair.AddValue(mapping_->At(i + 1));
   }
 }
 
-void ReasonForCancelling::Report(IsolateReloadContext* context) {
+void ReasonForCancelling::Report(IsolateGroupReloadContext* context) {
   const Error& error = Error::Handle(ToError());
   context->ReportError(error);
 }
@@ -258,8 +289,8 @@
   jsobj.AddProperty("message", message.ToCString());
 }
 
-RawError* IsolateReloadContext::error() const {
-  ASSERT(reload_aborted());
+RawError* IsolateGroupReloadContext::error() const {
+  ASSERT(!reasons_to_cancel_reload_.is_empty());
   // Report the first error to the surroundings.
   return reasons_to_cancel_reload_.At(0)->ToError();
 }
@@ -347,23 +378,6 @@
   }
 };
 
-bool IsolateReloadContext::IsSameField(const Field& a, const Field& b) {
-  if (a.is_static() != b.is_static()) {
-    return false;
-  }
-  const Class& a_cls = Class::Handle(a.Owner());
-  const Class& b_cls = Class::Handle(b.Owner());
-
-  if (!IsSameClass(a_cls, b_cls)) {
-    return false;
-  }
-
-  const String& a_name = String::Handle(a.name());
-  const String& b_name = String::Handle(b.name());
-
-  return a_name.Equals(b_name);
-}
-
 bool IsolateReloadContext::IsSameClass(const Class& a, const Class& b) {
   if (a.is_patch() != b.is_patch()) {
     // TODO(johnmccutchan): Should we just check the class kind bits?
@@ -398,24 +412,32 @@
   return a_lib_url.Equals(b_lib_url);
 }
 
-IsolateReloadContext::IsolateReloadContext(Isolate* isolate, JSONStream* js)
+IsolateGroupReloadContext::IsolateGroupReloadContext(
+    IsolateGroup* isolate_group,
+    SharedClassTable* shared_class_table,
+    JSONStream* js)
     : zone_(Thread::Current()->zone()),
+      isolate_group_(isolate_group),
+      shared_class_table_(shared_class_table),
       start_time_micros_(OS::GetCurrentMonotonicMicros()),
       reload_timestamp_(OS::GetCurrentTimeMillis()),
-      isolate_(isolate),
-      reload_skipped_(false),
-      reload_aborted_(false),
-      reload_finalized_(false),
       js_(js),
-      saved_num_cids_(-1),
-      saved_class_table_(nullptr),
-      num_saved_libs_(-1),
+      saved_size_table_(nullptr),
       instance_morphers_(zone_, 0),
       reasons_to_cancel_reload_(zone_, 0),
-      cid_mapper_(),
-      modified_libs_(NULL),
-      script_url_(String::null()),
-      error_(Error::null()),
+      instance_morpher_by_cid_(zone_),
+      root_lib_url_(String::Handle(Z, String::null())),
+      root_url_prefix_(String::null()),
+      old_root_url_prefix_(String::null()) {}
+IsolateGroupReloadContext::~IsolateGroupReloadContext() {}
+
+IsolateReloadContext::IsolateReloadContext(
+    std::shared_ptr<IsolateGroupReloadContext> group_reload_context,
+    Isolate* isolate)
+    : zone_(Thread::Current()->zone()),
+      group_reload_context_(group_reload_context),
+      isolate_(isolate),
+      saved_class_table_(nullptr),
       old_classes_set_storage_(Array::null()),
       class_map_storage_(Array::null()),
       removed_class_set_storage_(Array::null()),
@@ -424,9 +446,7 @@
       become_map_storage_(Array::null()),
       become_enum_mappings_(GrowableObjectArray::null()),
       saved_root_library_(Library::null()),
-      saved_libraries_(GrowableObjectArray::null()),
-      root_url_prefix_(String::null()),
-      old_root_url_prefix_(String::null()) {
+      saved_libraries_(GrowableObjectArray::null()) {
   // NOTE: DO NOT ALLOCATE ANY RAW OBJECTS HERE. The IsolateReloadContext is not
   // associated with the isolate yet and if a GC is triggered here the raw
   // objects will not be properly accounted for.
@@ -438,23 +458,27 @@
   ASSERT(saved_class_table_.load(std::memory_order_relaxed) == nullptr);
 }
 
-void IsolateReloadContext::ReportError(const Error& error) {
-  if (!FLAG_support_service || Isolate::IsVMInternalIsolate(I)) {
+void IsolateGroupReloadContext::ReportError(const Error& error) {
+  // TODO(dartbug.com/36097): We need to change the "reloadSources" service-api
+  // call to accept an isolate group instead of an isolate.
+  Isolate* isolate = Isolate::Current();
+  if (!FLAG_support_service || Isolate::IsVMInternalIsolate(isolate)) {
     return;
   }
-  if (FLAG_trace_reload) {
-    THR_Print("ISO-RELOAD: Error: %s\n", error.ToErrorCString());
-  }
-  ServiceEvent service_event(I, ServiceEvent::kIsolateReload);
+  TIR_Print("ISO-RELOAD: Error: %s\n", error.ToErrorCString());
+  ServiceEvent service_event(isolate, ServiceEvent::kIsolateReload);
   service_event.set_reload_error(&error);
   Service::HandleEvent(&service_event);
 }
 
-void IsolateReloadContext::ReportSuccess() {
-  if (!FLAG_support_service || Isolate::IsVMInternalIsolate(I)) {
+void IsolateGroupReloadContext::ReportSuccess() {
+  // TODO(dartbug.com/36097): We need to change the "reloadSources" service-api
+  // call to accept an isolate group instead of an isolate.
+  Isolate* isolate = Isolate::Current();
+  if (!FLAG_support_service || Isolate::IsVMInternalIsolate(isolate)) {
     return;
   }
-  ServiceEvent service_event(I, ServiceEvent::kIsolateReload);
+  ServiceEvent service_event(isolate, ServiceEvent::kIsolateReload);
   Service::HandleEvent(&service_event);
 }
 
@@ -502,45 +526,36 @@
   }
 }
 
-// NOTE: This function returns *after* FinalizeLoading is called.
 // If [root_script_url] is null, attempt to load from [kernel_buffer].
-void IsolateReloadContext::Reload(bool force_reload,
-                                  const char* root_script_url,
-                                  const char* packages_url_,
-                                  const uint8_t* kernel_buffer,
-                                  intptr_t kernel_buffer_size) {
+bool IsolateGroupReloadContext::Reload(bool force_reload,
+                                       const char* root_script_url,
+                                       const char* packages_url,
+                                       const uint8_t* kernel_buffer,
+                                       intptr_t kernel_buffer_size) {
   TIMELINE_SCOPE(Reload);
+
   Thread* thread = Thread::Current();
-  ASSERT(isolate() == thread->isolate());
+
+  // All isolates have the same sources, so all of them have the same libraries.
+  // We use the [first_isolate_] here to determine which of libraries have
+  // changed.
+  ASSERT(first_isolate_ == nullptr);
+  first_isolate_ = thread->isolate();
+
+  // All isolates within an isolate group need to share one heap.
+  // TODO(dartbug.com/36097): Remove this assert once the shared heap CL has
+  // landed.
+  RELEASE_ASSERT(!FLAG_enable_isolate_groups);
+  Heap* heap = first_isolate_->heap();
+
+  num_old_libs_ = GrowableObjectArray::Handle(
+                      Z, first_isolate_->object_store()->libraries())
+                      .Length();
 
   // Grab root library before calling CheckpointBeforeReload.
-  const Library& old_root_lib = Library::Handle(object_store()->root_library());
-  ASSERT(!old_root_lib.IsNull());
-  const String& old_root_lib_url = String::Handle(old_root_lib.url());
-  // Root library url.
-  const String& root_lib_url =
-      (root_script_url == NULL) ? old_root_lib_url
-                                : String::Handle(String::New(root_script_url));
+  GetRootLibUrl(root_script_url);
 
-  // Check to see if the base url of the loaded libraries has moved.
-  if (!old_root_lib_url.Equals(root_lib_url)) {
-    const char* old_root_library_url_c = old_root_lib_url.ToCString();
-    const char* root_library_url_c = root_lib_url.ToCString();
-    const intptr_t common_suffix_length =
-        CommonSuffixLength(root_library_url_c, old_root_library_url_c);
-    root_url_prefix_ = String::SubString(
-        root_lib_url, 0, root_lib_url.Length() - common_suffix_length + 1);
-    old_root_url_prefix_ =
-        String::SubString(old_root_lib_url, 0,
-                          old_root_lib_url.Length() - common_suffix_length + 1);
-  }
-
-  Object& result = Object::Handle(thread->zone());
   std::unique_ptr<kernel::Program> kernel_program;
-  String& packages_url = String::Handle();
-  if (packages_url_ != NULL) {
-    packages_url = String::New(packages_url_);
-  }
 
   // Reset stats.
   num_received_libs_ = 0;
@@ -552,10 +567,6 @@
   bool skip_reload = false;
   {
     // Load the kernel program and figure out the modified libraries.
-    const GrowableObjectArray& libs =
-        GrowableObjectArray::Handle(object_store()->libraries());
-    intptr_t num_libs = libs.Length();
-    modified_libs_ = new (Z) BitVector(Z, num_libs);
     intptr_t* p_num_received_classes = nullptr;
     intptr_t* p_num_received_procedures = nullptr;
 
@@ -570,70 +581,44 @@
       p_num_received_classes = &num_received_classes_;
       p_num_received_procedures = &num_received_procedures_;
     } else {
-      Dart_KernelCompilationResult retval = {};
-      if (kernel_buffer != NULL && kernel_buffer_size != 0) {
-        retval.kernel = const_cast<uint8_t*>(kernel_buffer);
-        retval.kernel_size = kernel_buffer_size;
-        retval.status = Dart_KernelCompilationStatus_Ok;
-      } else {
-        Dart_SourceFile* modified_scripts = NULL;
-        intptr_t modified_scripts_count = 0;
-
-        FindModifiedSources(thread, force_reload, &modified_scripts,
-                            &modified_scripts_count, packages_url_);
-
-        {
-          TransitionVMToNative transition(thread);
-          retval = KernelIsolate::CompileToKernel(
-              root_lib_url.ToCString(), NULL, 0, modified_scripts_count,
-              modified_scripts, true, NULL);
-          did_kernel_compilation = true;
+      if (kernel_buffer == NULL || kernel_buffer_size == 0) {
+        char* error = CompileToKernel(force_reload, packages_url,
+                                      &kernel_buffer, &kernel_buffer_size);
+        did_kernel_compilation = true;
+        if (error != nullptr) {
+          TIR_Print("---- LOAD FAILED, ABORTING RELOAD\n");
+          const auto& error_str = String::Handle(Z, String::New(error));
+          free(error);
+          const ApiError& error = ApiError::Handle(Z, ApiError::New(error_str));
+          AddReasonForCancelling(new Aborted(Z, error));
+          ReportReasonsForCancelling();
+          CommonFinalizeTail(num_old_libs_);
+          return false;
         }
       }
-
-      if (retval.status != Dart_KernelCompilationStatus_Ok) {
-        TIR_Print("---- LOAD FAILED, ABORTING RELOAD\n");
-        const String& error_str = String::Handle(String::New(retval.error));
-        free(retval.error);
-        const ApiError& error = ApiError::Handle(ApiError::New(error_str));
-        if (retval.kernel != NULL) {
-          free(const_cast<uint8_t*>(retval.kernel));
-        }
-        AddReasonForCancelling(new Aborted(zone_, error));
-        ReportReasonsForCancelling();
-        CommonFinalizeTail();
-        return;
-      }
-
-      // The ownership of the kernel buffer goes now to the VM.
-      const ExternalTypedData& typed_data = ExternalTypedData::Handle(
-          Z,
-          ExternalTypedData::New(kExternalTypedDataUint8ArrayCid, retval.kernel,
-                                 retval.kernel_size, Heap::kOld));
-      typed_data.AddFinalizer(
-          retval.kernel,
-          [](void* isolate_callback_data, Dart_WeakPersistentHandle handle,
-             void* data) { free(data); },
-          retval.kernel_size);
-
-      // TODO(dartbug.com/33973): Change the heap objects to have a proper
-      // retaining path to the kernel blob and ensure the finalizer will free it
-      // once there are no longer references to it.
-      // (The [ExternalTypedData] currently referenced by e.g. functions point
-      // into the middle of c-allocated buffer and don't have a finalizer).
-      I->RetainKernelBlob(typed_data);
-
+      const auto& typed_data = ExternalTypedData::Handle(
+          Z, MakeRetainedTypedData(kernel_buffer, kernel_buffer_size));
       kernel_program = kernel::Program::ReadFromTypedData(typed_data);
     }
 
+    modified_libs_ = new (Z) BitVector(Z, num_old_libs_);
     kernel::KernelLoader::FindModifiedLibraries(
-        kernel_program.get(), I, modified_libs_, force_reload, &skip_reload,
-        p_num_received_classes, p_num_received_procedures);
+        kernel_program.get(), first_isolate_, modified_libs_, force_reload,
+        &skip_reload, p_num_received_classes, p_num_received_procedures);
+
+    ASSERT(num_saved_libs_ == -1);
+    num_saved_libs_ = 0;
+    for (intptr_t i = 0; i < modified_libs_->length(); i++) {
+      if (!modified_libs_->Contains(i)) {
+        num_saved_libs_++;
+      }
+    }
   }
+
   if (skip_reload) {
     ASSERT(modified_libs_->IsEmpty());
     reload_skipped_ = true;
-    ReportOnJSON(js_);
+    ReportOnJSON(js_, num_old_libs_);
 
     // If we use the CFE and performed a compilation, we need to notify that
     // we have accepted the compilation to clear some state in the incremental
@@ -642,11 +627,340 @@
       AcceptCompilation(thread);
     }
     TIR_Print("---- SKIPPING RELOAD (No libraries were modified)\n");
-    return;
+    return false;
   }
 
   TIR_Print("---- STARTING RELOAD\n");
 
+  intptr_t number_of_isolates = 0;
+  isolate_group_->ForEachIsolate(
+      [&](Isolate* isolate) { number_of_isolates++; });
+
+  // Disable the background compiler while we are performing the reload.
+  ForEachIsolate(
+      [&](Isolate* isolate) { BackgroundCompiler::Disable(isolate); });
+
+  // Wait for any concurrent marking tasks to finish and turn off the
+  // concurrent marker during reload as we might be allocating new instances
+  // (constants) when loading the new kernel file and this could cause
+  // inconsistency between the saved class table and the new class table.
+  const bool old_concurrent_mark_flag =
+      heap->old_space()->enable_concurrent_mark();
+  if (old_concurrent_mark_flag) {
+    heap->WaitForMarkerTasks(thread);
+    heap->old_space()->set_enable_concurrent_mark(false);
+  }
+
+  // Ensure all functions on the stack have unoptimized code.
+  // Deoptimize all code that had optimizing decisions that are dependent on
+  // assumptions from field guards or CHA.
+  // TODO(johnmccutchan): Deoptimizing dependent code here (before the reload)
+  // is paranoid. This likely can be moved to the commit phase.
+  ForEachIsolate([&](Isolate* isolate) {
+    isolate->reload_context()->EnsuredUnoptimizedCodeForStack();
+    isolate->reload_context()->DeoptimizeDependentCode();
+    isolate->reload_context()->ReloadPhase1AllocateStorageMapsAndCheckpoint();
+  });
+  // Renumbering the libraries has invalidated this.
+  modified_libs_ = nullptr;
+
+  if (FLAG_gc_during_reload) {
+    // We use kLowMemory to force the GC to compact, which is more likely to
+    // discover untracked pointers (and other issues, like incorrect class
+    // table).
+    heap->CollectAllGarbage(Heap::kLowMemory);
+  }
+
+  // Copy the size table for isolate group & class tables for each isolate.
+  {
+    TIMELINE_SCOPE(CheckpointClasses);
+    CheckpointSharedClassTable();
+    ForEachIsolate([&](Isolate* isolate) {
+      isolate->reload_context()->CheckpointClasses();
+    });
+  }
+
+  if (FLAG_gc_during_reload) {
+    // We use kLowMemory to force the GC to compact, which is more likely to
+    // discover untracked pointers (and other issues, like incorrect class
+    // table).
+    heap->CollectAllGarbage(Heap::kLowMemory);
+  }
+
+  // We synchronously load the hot-reload kernel diff (which includes changed
+  // libraries and any libraries transitively depending on them).
+  //
+  // If loading the hot-reload diff succeeded we'll finalize the loading, which
+  // will either commit or reject the reload request.
+  const auto& results = Array::Handle(Z, Array::New(number_of_isolates));
+  intptr_t isolateIndex = 0;
+  intptr_t load_errors = 0;
+
+  auto& tmp = Object::Handle(Z);
+  ForEachIsolate([&](Isolate* isolate) {
+    tmp = isolate->reload_context()->ReloadPhase2LoadKernel(
+        kernel_program.get(), root_lib_url_);
+    if (tmp.IsError()) {
+      results.SetAt(isolateIndex, tmp);
+      load_errors++;
+    }
+    isolateIndex++;
+  });
+
+  const auto& result = Object::Handle(results.At(0));
+
+  if (load_errors > 0) {
+    TIR_Print("---- LOAD FAILED, ABORTING RELOAD\n");
+
+    const auto& error = Error::Cast(result);
+    AddReasonForCancelling(new Aborted(Z, error));
+
+    DiscardSavedClassTable(/*is_rollback=*/true);
+    ForEachIsolate([&](Isolate* isolate) {
+      isolate->reload_context()->ReloadPhase4Rollback();
+    });
+    CommonFinalizeTail(num_old_libs_);
+  } else {
+    ASSERT(!reload_skipped_ && !reload_finalized_);
+    TIR_Print("---- LOAD SUCCEEDED\n");
+
+    ForEachIsolate([&](Isolate* isolate) {
+      isolate->reload_context()->ReloadPhase3FinalizeLoading();
+    });
+
+    if (FLAG_gc_during_reload) {
+      // We use kLowMemory to force the GC to compact, which is more likely to
+      // discover untracked pointers (and other issues, like incorrect class
+      // table).
+      heap->CollectAllGarbage(Heap::kLowMemory);
+    }
+
+    if (!FLAG_reload_force_rollback && !HasReasonsForCancelling()) {
+      TIR_Print("---- COMMITTING RELOAD\n");
+      ForEachIsolate([&](Isolate* isolate) {
+        isolate->reload_context()->ReloadPhase4CommitPrepare();
+      });
+      bool discard_class_tables = true;
+      if (HasInstanceMorphers()) {
+        // Find all objects that need to be morphed (reallocated to a new size).
+        ObjectLocator locator(this);
+        {
+          HeapIterationScope iteration(Thread::Current());
+          iteration.IterateObjects(&locator);
+        }
+
+        // We are still using the old class table at this point.
+        if (FLAG_gc_during_reload) {
+          // We use kLowMemory to force the GC to compact, which is more likely
+          // to discover untracked pointers (and other issues, like incorrect
+          // class table).
+          heap->CollectAllGarbage(Heap::kLowMemory);
+        }
+        const intptr_t count = locator.count();
+        if (count > 0) {
+          TIMELINE_SCOPE(MorphInstances);
+
+          // While we are reallocating instances to their new size, the heap
+          // will contain a mix of instances with the old and new sizes that
+          // have the same cid. This makes the heap unwalkable until the
+          // "become" operation below replaces all the instances of the old
+          // size with forwarding corpses. Force heap growth to prevent size
+          // confusion during this period.
+          NoHeapGrowthControlScope scope;
+          // The HeapIterationScope above ensures no other GC tasks can be
+          // active.
+          ASSERT(HasNoTasks(heap));
+
+          const Array& before = Array::Handle(Z, Array::New(count));
+          const Array& after = Array::Handle(Z, Array::New(count));
+
+          MorphInstancesPhase1Allocate(&locator, before, after);
+          {
+            // Apply the new class table before "become". Become will replace
+            // all the instances of the old size with forwarding corpses, then
+            // perform a heap walk to fix references to the forwarding corpses.
+            // During this heap walk, it will encounter instances of the new
+            // size, so it requires the new class table.
+            ASSERT(HasNoTasks(heap));
+
+            // We accepted the hot-reload and morphed instances. So now we can
+            // commit to the changed class table and deleted the saved one.
+            DiscardSavedClassTable(/*is_rollback=*/false);
+            ForEachIsolate([&](Isolate* isolate) {
+              isolate->reload_context()->DiscardSavedClassTable(
+                  /*is_rollback=*/false);
+            });
+          }
+          MorphInstancesPhase2Become(before, after);
+
+          discard_class_tables = false;
+        }
+        // We are using the new class table now.
+        if (FLAG_gc_during_reload) {
+          // We use kLowMemory to force the GC to compact, which is more likely
+          // to discover untracked pointers (and other issues, like incorrect
+          // class table).
+          heap->CollectAllGarbage(Heap::kLowMemory);
+        }
+      }
+      if (discard_class_tables) {
+        DiscardSavedClassTable(/*is_rollback=*/false);
+        ForEachIsolate([&](Isolate* isolate) {
+          isolate->reload_context()->DiscardSavedClassTable(
+              /*is_rollback=*/false);
+        });
+      }
+      ForEachIsolate([&](Isolate* isolate) {
+        isolate->reload_context()->ReloadPhase4CommitFinish();
+      });
+      TIR_Print("---- DONE COMMIT\n");
+      isolate_group_->set_last_reload_timestamp(reload_timestamp_);
+    } else {
+      TIR_Print("---- ROLLING BACK");
+      DiscardSavedClassTable(/*is_rollback=*/true);
+      ForEachIsolate([&](Isolate* isolate) {
+        isolate->reload_context()->ReloadPhase4Rollback();
+      });
+    }
+
+    // ValidateReload mutates the direct subclass information and does
+    // not remove dead subclasses.  Rebuild the direct subclass
+    // information from scratch.
+    ForEachIsolate([&](Isolate* isolate) {
+      isolate->reload_context()->RebuildDirectSubclasses();
+    });
+    const intptr_t final_library_count =
+        GrowableObjectArray::Handle(Z,
+                                    first_isolate_->object_store()->libraries())
+            .Length();
+    CommonFinalizeTail(final_library_count);
+
+    // If we use the CFE and performed a compilation, we need to notify that
+    // we have accepted the compilation to clear some state in the incremental
+    // compiler.
+    if (did_kernel_compilation) {
+      AcceptCompilation(thread);
+    }
+  }
+
+  // Re-enable the background compiler. Do this before propagating any errors.
+  ForEachIsolate(
+      [&](Isolate* isolate) { BackgroundCompiler::Enable(isolate); });
+
+  // Reenable concurrent marking if it was initially on.
+  if (old_concurrent_mark_flag) {
+    heap->old_space()->set_enable_concurrent_mark(true);
+  }
+
+  bool success;
+  if (load_errors == 0 || HasReasonsForCancelling()) {
+    ReportSuccess();
+    success = true;
+  } else {
+    ReportReasonsForCancelling();
+    success = false;
+  }
+
+  // Once we --enable-isolate-groups in JIT again, we have to ensure unwind
+  // errors will be propagated to all isolates.
+  if (result.IsUnwindError()) {
+    const auto& error = Error::Cast(result);
+    if (thread->top_exit_frame_info() == 0) {
+      // We can only propagate errors when there are Dart frames on the stack.
+      // In this case there are no Dart frames on the stack and we set the
+      // thread's sticky error. This error will be returned to the message
+      // handler.
+      thread->set_sticky_error(error);
+    } else {
+      // If the tag handler returns with an UnwindError error, propagate it and
+      // give up.
+      Exceptions::PropagateError(error);
+      UNREACHABLE();
+    }
+  }
+
+  return success;
+}
+
+void IsolateGroupReloadContext::GetRootLibUrl(const char* root_script_url) {
+  const auto& old_root_lib =
+      Library::Handle(first_isolate_->object_store()->root_library());
+  ASSERT(!old_root_lib.IsNull());
+  const auto& old_root_lib_url = String::Handle(old_root_lib.url());
+
+  // Root library url.
+  if (root_script_url != nullptr) {
+    root_lib_url_ = String::New(root_script_url);
+  } else {
+    root_lib_url_ = old_root_lib_url.raw();
+  }
+
+  // Check to see if the base url of the loaded libraries has moved.
+  if (!old_root_lib_url.Equals(root_lib_url_)) {
+    const char* old_root_library_url_c = old_root_lib_url.ToCString();
+    const char* root_library_url_c = root_lib_url_.ToCString();
+    const intptr_t common_suffix_length =
+        CommonSuffixLength(root_library_url_c, old_root_library_url_c);
+    root_url_prefix_ = String::SubString(
+        root_lib_url_, 0, root_lib_url_.Length() - common_suffix_length + 1);
+    old_root_url_prefix_ =
+        String::SubString(old_root_lib_url, 0,
+                          old_root_lib_url.Length() - common_suffix_length + 1);
+  }
+}
+
+char* IsolateGroupReloadContext::CompileToKernel(bool force_reload,
+                                                 const char* packages_url,
+                                                 const uint8_t** kernel_buffer,
+                                                 intptr_t* kernel_buffer_size) {
+  Dart_SourceFile* modified_scripts = nullptr;
+  intptr_t modified_scripts_count = 0;
+  FindModifiedSources(force_reload, &modified_scripts, &modified_scripts_count,
+                      packages_url);
+
+  Dart_KernelCompilationResult retval = {};
+  {
+    TransitionVMToNative transition(Thread::Current());
+    retval = KernelIsolate::CompileToKernel(root_lib_url_.ToCString(), nullptr,
+                                            0, modified_scripts_count,
+                                            modified_scripts, true, nullptr);
+  }
+  if (retval.status != Dart_KernelCompilationStatus_Ok) {
+    if (retval.kernel != nullptr) {
+      free(retval.kernel);
+    }
+    return retval.error;
+  }
+  *kernel_buffer = retval.kernel;
+  *kernel_buffer_size = retval.kernel_size;
+  return nullptr;
+}
+
+RawExternalTypedData* IsolateGroupReloadContext::MakeRetainedTypedData(
+    const uint8_t* kernel_buffer,
+    intptr_t kernel_buffer_size) {
+  // The ownership of the kernel buffer goes now to the VM.
+  const auto& typed_data = ExternalTypedData::Handle(
+      Z, ExternalTypedData::New(kExternalTypedDataUint8ArrayCid,
+                                const_cast<uint8_t*>(kernel_buffer),
+                                kernel_buffer_size, Heap::kOld));
+  typed_data.AddFinalizer(
+      const_cast<uint8_t*>(kernel_buffer),
+      [](void* isolate_callback_data, Dart_WeakPersistentHandle handle,
+         void* data) { free(data); },
+      kernel_buffer_size);
+
+  // TODO(dartbug.com/33973): Change the heap objects to have a proper
+  // retaining path to the kernel blob and ensure the finalizer will free it
+  // once there are no longer references to it.
+  // (The [ExternalTypedData] currently referenced by e.g. functions point
+  // into the middle of c-allocated buffer and don't have a finalizer).
+  first_isolate_->RetainKernelBlob(typed_data);
+
+  return typed_data.raw();
+}
+
+void IsolateReloadContext::ReloadPhase1AllocateStorageMapsAndCheckpoint() {
   // Preallocate storage for maps.
   old_classes_set_storage_ =
       HashTables::New<UnorderedHashSet<ClassMapTraits> >(4);
@@ -662,89 +976,54 @@
   // hashCode on the instances.
   become_enum_mappings_ = GrowableObjectArray::New(Heap::kOld);
 
-  // Disable the background compiler while we are performing the reload.
-  BackgroundCompiler::Disable(I);
-
-  // Wait for any concurrent marking tasks to finish and turn off the
-  // concurrent marker during reload as we might be allocating new instances
-  // (constants) when loading the new kernel file and this could cause
-  // inconsistency between the saved class table and the new class table.
-  Heap* heap = thread->heap();
-  const bool old_concurrent_mark_flag =
-      heap->old_space()->enable_concurrent_mark();
-  if (old_concurrent_mark_flag) {
-    heap->WaitForMarkerTasks(thread);
-    heap->old_space()->set_enable_concurrent_mark(false);
-  }
-
-  // Ensure all functions on the stack have unoptimized code.
-  EnsuredUnoptimizedCodeForStack();
-  // Deoptimize all code that had optimizing decisions that are dependent on
-  // assumptions from field guards or CHA.
-  // TODO(johnmccutchan): Deoptimizing dependent code here (before the reload)
-  // is paranoid. This likely can be moved to the commit phase.
-  DeoptimizeDependentCode();
-  Checkpoint();
-
-  // We synchronously load the hot-reload kernel diff (which includes changed
-  // libraries and any libraries transitively depending on them).
-  //
-  // If loading the hot-reload diff succeeded we'll finalize the loading, which
-  // will either commit or reject the reload request.
+  // While reloading everything we do must be reversible so that we can abort
+  // safely if the reload fails. This function stashes things to the side and
+  // prepares the isolate for the reload attempt.
   {
-    const Object& tmp =
-        kernel::KernelLoader::LoadEntireProgram(kernel_program.get());
-    if (!tmp.IsError()) {
-      Library& lib = Library::Handle(thread->zone());
-      lib ^= tmp.raw();
-      // If main method disappeared or were not there to begin with then
-      // KernelLoader will return null. In this case lookup library by
-      // URL.
-      if (lib.IsNull()) {
-        lib = Library::LookupLibrary(thread, root_lib_url);
-      }
-      isolate()->object_store()->set_root_library(lib);
-      FinalizeLoading();
-      result = Object::null();
+    TIMELINE_SCOPE(Checkpoint);
+    CheckpointLibraries();
+  }
+}
 
-      // If we use the CFE and performed a compilation, we need to notify that
-      // we have accepted the compilation to clear some state in the incremental
-      // compiler.
-      if (did_kernel_compilation) {
-        AcceptCompilation(thread);
-      }
-    } else {
-      result = tmp.raw();
-    }
+RawObject* IsolateReloadContext::ReloadPhase2LoadKernel(
+    kernel::Program* program,
+    const String& root_lib_url) {
+  Thread* thread = Thread::Current();
+
+  const Object& tmp = kernel::KernelLoader::LoadEntireProgram(program);
+  if (tmp.IsError()) {
+    return tmp.raw();
   }
 
-  // Re-enable the background compiler. Do this before propagating any errors.
-  BackgroundCompiler::Enable(I);
-
-  // Reenable concurrent marking if it was initially on.
-  heap->old_space()->set_enable_concurrent_mark(old_concurrent_mark_flag);
-
-  if (result.IsUnwindError()) {
-    if (thread->top_exit_frame_info() == 0) {
-      // We can only propagate errors when there are Dart frames on the stack.
-      // In this case there are no Dart frames on the stack and we set the
-      // thread's sticky error. This error will be returned to the message
-      // handler.
-      thread->set_sticky_error(Error::Cast(result));
-    } else {
-      // If the tag handler returns with an UnwindError error, propagate it and
-      // give up.
-      Exceptions::PropagateError(Error::Cast(result));
-      UNREACHABLE();
-    }
+  // If main method disappeared or were not there to begin with then
+  // KernelLoader will return null. In this case lookup library by
+  // URL.
+  auto& lib = Library::Handle(Library::RawCast(tmp.raw()));
+  if (lib.IsNull()) {
+    lib = Library::LookupLibrary(thread, root_lib_url);
   }
+  isolate_->object_store()->set_root_library(lib);
+  return Object::null();
+}
 
-  // Other errors (e.g. a parse error) are captured by the reload system.
-  if (result.IsError()) {
-    FinalizeFailedLoad(Error::Cast(result));
-  } else {
-    ReportSuccess();
-  }
+void IsolateReloadContext::ReloadPhase3FinalizeLoading() {
+  BuildLibraryMapping();
+  BuildRemovedClassesSet();
+  ValidateReload();
+}
+
+void IsolateReloadContext::ReloadPhase4CommitPrepare() {
+  CommitBeforeInstanceMorphing();
+}
+
+void IsolateReloadContext::ReloadPhase4CommitFinish() {
+  CommitAfterInstanceMorphing();
+  PostCommit();
+}
+
+void IsolateReloadContext::ReloadPhase4Rollback() {
+  RollbackClasses();
+  RollbackLibraries();
 }
 
 void IsolateReloadContext::RegisterClass(const Class& new_cls) {
@@ -764,7 +1043,7 @@
   }
   VTIR_Print("Registering class: %s\n", new_cls.ToCString());
   new_cls.set_id(old_cls.id());
-  isolate()->class_table()->SetAt(old_cls.id(), new_cls.raw());
+  I->class_table()->SetAt(old_cls.id(), new_cls.raw());
   if (!old_cls.is_enum_class()) {
     new_cls.CopyCanonicalConstants(old_cls);
   }
@@ -773,47 +1052,15 @@
   AddClassMapping(new_cls, old_cls);
 }
 
-void IsolateReloadContext::FinalizeLoading() {
-  if (reload_skipped_ || reload_finalized_) {
-    return;
-  }
-  BuildLibraryMapping();
-  BuildRemovedClassesSet();
-
-  TIR_Print("---- LOAD SUCCEEDED\n");
-  if (ValidateReload()) {
-    Commit();
-    PostCommit();
-    isolate()->set_last_reload_timestamp(reload_timestamp_);
-  } else {
-    ReportReasonsForCancelling();
-    Rollback();
-  }
-  // ValidateReload mutates the direct subclass information and does
-  // not remove dead subclasses.  Rebuild the direct subclass
-  // information from scratch.
-  RebuildDirectSubclasses();
-  CommonFinalizeTail();
-}
-
-// FinalizeFailedLoad will be called *before* Reload() returns and will only
-// be called if the embedder fails to load sources.
-void IsolateReloadContext::FinalizeFailedLoad(const Error& error) {
-  TIR_Print("---- LOAD FAILED, ABORTING RELOAD\n");
-  AddReasonForCancelling(new Aborted(zone_, error));
-  ReportReasonsForCancelling();
-  if (!reload_finalized_) {
-    Rollback();
-  }
-  CommonFinalizeTail();
-}
-
-void IsolateReloadContext::CommonFinalizeTail() {
-  ReportOnJSON(js_);
+void IsolateGroupReloadContext::CommonFinalizeTail(
+    intptr_t final_library_count) {
+  RELEASE_ASSERT(!reload_finalized_);
+  ReportOnJSON(js_, final_library_count);
   reload_finalized_ = true;
 }
 
-void IsolateReloadContext::ReportOnJSON(JSONStream* stream) {
+void IsolateGroupReloadContext::ReportOnJSON(JSONStream* stream,
+                                             intptr_t final_library_count) {
   JSONObject jsobj(stream);
   jsobj.AddProperty("type", "ReloadReport");
   jsobj.AddProperty("success", reload_skipped_ || !HasReasonsForCancelling());
@@ -829,9 +1076,6 @@
     }
 
     JSONObject details(&jsobj, "details");
-    const GrowableObjectArray& libs =
-        GrowableObjectArray::Handle(object_store()->libraries());
-    const intptr_t final_library_count = libs.Length();
     details.AddProperty("finalLibraryCount", final_library_count);
     details.AddProperty("receivedLibraryCount", num_received_libs_);
     details.AddProperty("receivedLibrariesBytes", bytes_received_libs_);
@@ -910,8 +1154,23 @@
   DeoptimizeTypeTestingStubs();
 }
 
+void IsolateGroupReloadContext::CheckpointSharedClassTable() {
+  // Copy the size table for isolate group.
+  intptr_t* saved_size_table = nullptr;
+  shared_class_table_->CopyBeforeHotReload(&saved_size_table, &saved_num_cids_);
+  {
+    NoSafepointScope no_safepoint_scope(Thread::Current());
+
+    // The saved_size_table_ will now become source of truth for GC.
+    saved_size_table_.store(saved_size_table, std::memory_order_release);
+
+    // We can therefore wipe out all of the old entries (if that table is used
+    // for GC during the hot-reload we have a bug).
+    shared_class_table_->ResetBeforeHotReload();
+  }
+}
+
 void IsolateReloadContext::CheckpointClasses() {
-  TIMELINE_SCOPE(CheckpointClasses);
   TIR_Print("---- CHECKPOINTING CLASSES\n");
   // Checkpoint classes before a reload. We need to copy the following:
   // 1) The size of the class table.
@@ -919,12 +1178,9 @@
   // For efficiency, we build a set of classes before the reload. This set
   // is used to pair new classes with old classes.
 
+  // Copy the class table for isolate.
   ClassTable* class_table = I->class_table();
-
-  // Copy the size of the class table.
-  saved_num_cids_ = I->class_table()->NumCids();
-
-  ClassAndSize* saved_class_table = nullptr;
+  RawClass** saved_class_table = nullptr;
   class_table->CopyBeforeHotReload(&saved_class_table, &saved_num_cids_);
 
   // Copy classes into saved_class_table_ first. Make sure there are no
@@ -958,17 +1214,19 @@
   TIR_Print("---- System had %" Pd " classes\n", saved_num_cids_);
 }
 
-Dart_FileModifiedCallback IsolateReloadContext::file_modified_callback_ = NULL;
+Dart_FileModifiedCallback IsolateGroupReloadContext::file_modified_callback_ =
+    nullptr;
 
-bool IsolateReloadContext::ScriptModifiedSince(const Script& script,
-                                               int64_t since) {
-  if (file_modified_callback_ == NULL) {
+bool IsolateGroupReloadContext::ScriptModifiedSince(const Script& script,
+                                                    int64_t since) {
+  if (IsolateGroupReloadContext::file_modified_callback_ == NULL) {
     return true;
   }
   // We use the resolved url to determine if the script has been modified.
   const String& url = String::Handle(script.resolved_url());
   const char* url_chars = url.ToCString();
-  return (*file_modified_callback_)(url_chars, since);
+  return (*IsolateGroupReloadContext::file_modified_callback_)(url_chars,
+                                                               since);
 }
 
 static bool ContainsScriptUri(const GrowableArray<const char*>& seen_uris,
@@ -985,21 +1243,19 @@
   return false;
 }
 
-void IsolateReloadContext::FindModifiedSources(
-    Thread* thread,
+void IsolateGroupReloadContext::FindModifiedSources(
     bool force_reload,
     Dart_SourceFile** modified_sources,
     intptr_t* count,
     const char* packages_url) {
-  Zone* zone = thread->zone();
-  int64_t last_reload = I->last_reload_timestamp();
+  const int64_t last_reload = isolate_group_->last_reload_timestamp();
   GrowableArray<const char*> modified_sources_uris;
-  const GrowableObjectArray& libs =
-      GrowableObjectArray::Handle(object_store()->libraries());
-  Library& lib = Library::Handle(zone);
-  Array& scripts = Array::Handle(zone);
-  Script& script = Script::Handle(zone);
-  String& uri = String::Handle(zone);
+  const auto& libs =
+      GrowableObjectArray::Handle(first_isolate_->object_store()->libraries());
+  Library& lib = Library::Handle(Z);
+  Array& scripts = Array::Handle(Z);
+  Script& script = Script::Handle(Z);
+  String& uri = String::Handle(Z);
 
   for (intptr_t lib_idx = 0; lib_idx < libs.Length(); lib_idx++) {
     lib ^= libs.At(lib_idx);
@@ -1025,8 +1281,9 @@
   // In addition to all sources, we need to check if the .packages file
   // contents have been modified.
   if (packages_url != NULL) {
-    if (file_modified_callback_ == NULL ||
-        (*file_modified_callback_)(packages_url, last_reload)) {
+    if (IsolateGroupReloadContext::file_modified_callback_ == NULL ||
+        (*IsolateGroupReloadContext::file_modified_callback_)(packages_url,
+                                                              last_reload)) {
       modified_sources_uris.Add(packages_url);
     }
   }
@@ -1036,7 +1293,7 @@
     return;
   }
 
-  *modified_sources = zone_->Alloc<Dart_SourceFile>(*count);
+  *modified_sources = Z->Alloc<Dart_SourceFile>(*count);
   for (intptr_t i = 0; i < *count; ++i) {
     (*modified_sources)[i].uri = modified_sources_uris[i];
     (*modified_sources)[i].source = NULL;
@@ -1048,12 +1305,12 @@
   TIR_Print("---- CHECKPOINTING LIBRARIES\n");
   // Save the root library in case we abort the reload.
   const Library& root_lib = Library::Handle(object_store()->root_library());
-  set_saved_root_library(root_lib);
+  saved_root_library_ = root_lib.raw();
 
   // Save the old libraries array in case we abort the reload.
   const GrowableObjectArray& libs =
       GrowableObjectArray::Handle(object_store()->libraries());
-  set_saved_libraries(libs);
+  saved_libraries_ = libs.raw();
 
   // Make a filtered copy of the old libraries array. Keep "clean" libraries
   // that we will use instead of reloading.
@@ -1062,23 +1319,20 @@
   Library& lib = Library::Handle();
   UnorderedHashSet<LibraryMapTraits> old_libraries_set(
       old_libraries_set_storage_);
-  num_saved_libs_ = 0;
   for (intptr_t i = 0; i < libs.Length(); i++) {
     lib ^= libs.At(i);
-    if (modified_libs_->Contains(i)) {
+    if (group_reload_context_->modified_libs_->Contains(i)) {
       // We are going to reload this library. Clear the index.
       lib.set_index(-1);
     } else {
       // We are preserving this library across the reload, assign its new index
       lib.set_index(new_libs.Length());
       new_libs.Add(lib, Heap::kOld);
-      num_saved_libs_++;
     }
     // Add old library to old libraries set.
     bool already_present = old_libraries_set.Insert(lib);
     ASSERT(!already_present);
   }
-  modified_libs_ = NULL;  // Renumbering the libraries has invalidated this.
   old_libraries_set_storage_ = old_libraries_set.Release().raw();
 
   // Reset the registered libraries to the filtered array.
@@ -1087,15 +1341,6 @@
   object_store()->set_root_library(Library::Handle());
 }
 
-// While reloading everything we do must be reversible so that we can abort
-// safely if the reload fails. This function stashes things to the side and
-// prepares the isolate for the reload attempt.
-void IsolateReloadContext::Checkpoint() {
-  TIMELINE_SCOPE(Checkpoint);
-  CheckpointClasses();
-  CheckpointLibraries();
-}
-
 void IsolateReloadContext::RollbackClasses() {
   TIR_Print("---- ROLLING BACK CLASS TABLE\n");
   ASSERT(saved_num_cids_ > 0);
@@ -1108,8 +1353,7 @@
   TIR_Print("---- ROLLING BACK LIBRARY CHANGES\n");
   Thread* thread = Thread::Current();
   Library& lib = Library::Handle();
-  GrowableObjectArray& saved_libs =
-      GrowableObjectArray::Handle(Z, saved_libraries());
+  const auto& saved_libs = GrowableObjectArray::Handle(Z, saved_libraries_);
   if (!saved_libs.IsNull()) {
     for (intptr_t i = 0; i < saved_libs.Length(); i++) {
       lib = Library::RawCast(saved_libs.At(i));
@@ -1121,19 +1365,13 @@
     Library::RegisterLibraries(thread, saved_libs);
   }
 
-  Library& saved_root_lib = Library::Handle(Z, saved_root_library());
+  Library& saved_root_lib = Library::Handle(Z, saved_root_library_);
   if (!saved_root_lib.IsNull()) {
     object_store()->set_root_library(saved_root_lib);
   }
 
-  set_saved_root_library(Library::Handle());
-  set_saved_libraries(GrowableObjectArray::Handle());
-}
-
-void IsolateReloadContext::Rollback() {
-  TIR_Print("---- ROLLING BACK");
-  RollbackClasses();
-  RollbackLibraries();
+  saved_root_library_ = Library::null();
+  saved_libraries_ = GrowableObjectArray::null();
 }
 
 #ifdef DEBUG
@@ -1172,9 +1410,8 @@
 }
 #endif
 
-void IsolateReloadContext::Commit() {
+void IsolateReloadContext::CommitBeforeInstanceMorphing() {
   TIMELINE_SCOPE(Commit);
-  TIR_Print("---- COMMITTING RELOAD\n");
 
 #ifdef DEBUG
   VerifyMaps();
@@ -1270,13 +1507,13 @@
     for (intptr_t i = 0; i < libs.Length(); i++) {
       lib = Library::RawCast(libs.At(i));
       // Mark the library dirty if it comes after the libraries we saved.
-      library_infos_[i].dirty = i >= num_saved_libs_;
+      library_infos_[i].dirty = i >= group_reload_context_->num_saved_libs_;
     }
   }
+}
 
+void IsolateReloadContext::CommitAfterInstanceMorphing() {
   {
-    MorphInstancesAndApplyNewClassTable();
-
     const GrowableObjectArray& become_enum_mappings =
         GrowableObjectArray::Handle(become_enum_mappings_);
     UnorderedHashMap<BecomeMapTraits> become_map(become_map_storage_);
@@ -1326,8 +1563,7 @@
       TIR_Print("Identity reload failed! B#C=%" Pd " A#C=%" Pd "\n",
                 saved_num_cids_, I->class_table()->NumCids());
     }
-    const GrowableObjectArray& saved_libs =
-        GrowableObjectArray::Handle(saved_libraries());
+    const auto& saved_libs = GrowableObjectArray::Handle(saved_libraries_);
     const GrowableObjectArray& libs =
         GrowableObjectArray::Handle(I->object_store()->libraries());
     if (saved_libs.Length() != libs.Length()) {
@@ -1349,65 +1585,41 @@
 
 void IsolateReloadContext::PostCommit() {
   TIMELINE_SCOPE(PostCommit);
-  set_saved_root_library(Library::Handle());
-  set_saved_libraries(GrowableObjectArray::Handle());
+  saved_root_library_ = Library::null();
+  saved_libraries_ = GrowableObjectArray::null();
   InvalidateWorld();
-  TIR_Print("---- DONE COMMIT\n");
 }
 
-void IsolateReloadContext::AddReasonForCancelling(ReasonForCancelling* reason) {
-  reload_aborted_ = true;
+void IsolateGroupReloadContext::AddReasonForCancelling(
+    ReasonForCancelling* reason) {
   reasons_to_cancel_reload_.Add(reason);
 }
 
-void IsolateReloadContext::AddInstanceMorpher(InstanceMorpher* morpher) {
-  instance_morphers_.Add(morpher);
-  cid_mapper_.Insert(morpher);
+void IsolateGroupReloadContext::EnsureHasInstanceMorpherFor(
+    classid_t cid,
+    InstanceMorpher* instance_morpher) {
+  for (intptr_t i = 0; i < instance_morphers_.length(); ++i) {
+    if (instance_morphers_[i]->cid() == cid) {
+      return;
+    }
+  }
+  instance_morphers_.Add(instance_morpher);
+  instance_morpher_by_cid_.Insert(instance_morpher);
+  ASSERT(instance_morphers_[instance_morphers_.length() - 1]->cid() == cid);
 }
 
-void IsolateReloadContext::ReportReasonsForCancelling() {
+void IsolateGroupReloadContext::ReportReasonsForCancelling() {
   ASSERT(FLAG_reload_force_rollback || HasReasonsForCancelling());
   for (int i = 0; i < reasons_to_cancel_reload_.length(); i++) {
     reasons_to_cancel_reload_.At(i)->Report(this);
   }
 }
 
-// The ObjectLocator is used for collecting instances that
-// needs to be morphed.
-class ObjectLocator : public ObjectVisitor {
- public:
-  explicit ObjectLocator(IsolateReloadContext* context)
-      : context_(context), count_(0) {}
-
-  void VisitObject(RawObject* obj) {
-    InstanceMorpher* morpher =
-        context_->cid_mapper_.LookupValue(obj->GetClassId());
-    if (morpher != NULL) {
-      morpher->AddObject(obj);
-      count_++;
-    }
-  }
-
-  // Return the number of located objects for morphing.
-  intptr_t count() { return count_; }
-
- private:
-  IsolateReloadContext* context_;
-  intptr_t count_;
-};
-
-static bool HasNoTasks(Heap* heap) {
-  MonitorLocker ml(heap->old_space()->tasks_lock());
-  return heap->old_space()->tasks() == 0;
-}
-
-void IsolateReloadContext::MorphInstancesAndApplyNewClassTable() {
-  TIMELINE_SCOPE(MorphInstances);
-  if (!HasInstanceMorphers()) {
-    // Fast path: no class had a shape change.
-    DiscardSavedClassTable(/*is_rollback=*/false);
-    return;
-  }
+void IsolateGroupReloadContext::MorphInstancesPhase1Allocate(
+    ObjectLocator* locator,
+    const Array& before,
+    const Array& after) {
+  ASSERT(HasInstanceMorphers());
 
   if (FLAG_trace_reload) {
     LogBlock blocker;
@@ -1417,40 +1629,16 @@
     }
   }
 
-  // Find all objects that need to be morphed (reallocated to a new size).
-  ObjectLocator locator(this);
-  {
-    HeapIterationScope iteration(Thread::Current());
-    iteration.IterateObjects(&locator);
-  }
-
-  intptr_t count = locator.count();
-  if (count == 0) {
-    // Fast path: classes with shape change have no instances.
-    DiscardSavedClassTable(/*is_rollback=*/false);
-    return;
-  }
-
+  const intptr_t count = locator->count();
   TIR_Print("Found %" Pd " object%s subject to morphing.\n", count,
             (count > 1) ? "s" : "");
 
-  // While we are reallocating instances to their new size, the heap will
-  // contain a mix of instances with the old and new sizes that have the same
-  // cid. This makes the heap unwalkable until the "become" operation below
-  // replaces all the instances of the old size with forwarding corpses. Force
-  // heap growth to prevent size confusion during this period.
-  NoHeapGrowthControlScope scope;
-  // The HeapIterationScope above ensures no other GC tasks can be active.
-  ASSERT(HasNoTasks(I->heap()));
-
   for (intptr_t i = 0; i < instance_morphers_.length(); i++) {
     instance_morphers_.At(i)->CreateMorphedCopies();
   }
 
   // Create the inputs for Become.
   intptr_t index = 0;
-  const Array& before = Array::Handle(Array::New(count));
-  const Array& after = Array::Handle(Array::New(count));
   for (intptr_t i = 0; i < instance_morphers_.length(); i++) {
     InstanceMorpher* morpher = instance_morphers_.At(i);
     for (intptr_t j = 0; j < morpher->before()->length(); j++) {
@@ -1460,31 +1648,24 @@
     }
   }
   ASSERT(index == count);
+}
 
-  // Apply the new class table before "become". Become will replace all the
-  // instances of the old size with forwarding corpses, then perform a heap walk
-  // to fix references to the forwarding corpses. During this heap walk, it will
-  // encounter instances of the new size, so it requires the new class table.
-  ASSERT(HasNoTasks(I->heap()));
-#if defined(DEBUG)
-  for (intptr_t i = 0; i < saved_num_cids_; i++) {
-    saved_class_table_.load(std::memory_order_relaxed)[i] =
-        ClassAndSize(nullptr, -1);
-  }
-#endif
-
-  // We accepted the hot-reload and morphed instances. So now we can commit to
-  // the changed class table and deleted the saved one.
-  DiscardSavedClassTable(/*is_rollback=*/false);
+void IsolateGroupReloadContext::MorphInstancesPhase2Become(const Array& before,
+                                                           const Array& after) {
+  ASSERT(HasInstanceMorphers());
 
   Become::ElementsForwardIdentity(before, after);
   // The heap now contains only instances with the new size. Ordinary GC is safe
   // again.
 }
 
-bool IsolateReloadContext::ValidateReload() {
+void IsolateGroupReloadContext::ForEachIsolate(
+    std::function<void(Isolate*)> callback) {
+  isolate_group_->ForEachIsolate(callback);
+}
+
+void IsolateReloadContext::ValidateReload() {
   TIMELINE_SCOPE(ValidateReload);
-  if (reload_aborted()) return false;
 
   TIR_Print("---- VALIDATING RELOAD\n");
 
@@ -1523,73 +1704,58 @@
     }
     map.Release();
   }
-
-  return !FLAG_reload_force_rollback && !HasReasonsForCancelling();
-}
-
-RawClass* IsolateReloadContext::FindOriginalClass(const Class& cls) {
-  return MappedClass(cls);
 }
 
 RawClass* IsolateReloadContext::GetClassForHeapWalkAt(intptr_t cid) {
-  ClassAndSize* class_table =
-      saved_class_table_.load(std::memory_order_acquire);
+  RawClass** class_table = saved_class_table_.load(std::memory_order_acquire);
   if (class_table != NULL) {
     ASSERT(cid > 0);
     ASSERT(cid < saved_num_cids_);
-    return class_table[cid].get_raw_class();
+    return class_table[cid];
   } else {
     return isolate_->class_table()->At(cid);
   }
 }
 
-intptr_t IsolateReloadContext::GetClassSizeForHeapWalkAt(intptr_t cid) {
-  ClassAndSize* class_table =
-      saved_class_table_.load(std::memory_order_acquire);
-  if (class_table != NULL) {
+intptr_t IsolateGroupReloadContext::GetClassSizeForHeapWalkAt(classid_t cid) {
+  intptr_t* size_table = saved_size_table_.load(std::memory_order_acquire);
+  if (size_table != nullptr) {
     ASSERT(cid > 0);
     ASSERT(cid < saved_num_cids_);
-    return class_table[cid].size();
+    return size_table[cid];
   } else {
-    return isolate_->class_table()->SizeAt(cid);
+    return shared_class_table_->SizeAt(cid);
   }
 }
 
 void IsolateReloadContext::DiscardSavedClassTable(bool is_rollback) {
-  ClassAndSize* local_saved_class_table =
+  RawClass** local_saved_class_table =
       saved_class_table_.load(std::memory_order_relaxed);
   I->class_table()->ResetAfterHotReload(local_saved_class_table,
                                         saved_num_cids_, is_rollback);
   saved_class_table_.store(nullptr, std::memory_order_release);
 }
 
-RawLibrary* IsolateReloadContext::saved_root_library() const {
-  return saved_root_library_;
+void IsolateGroupReloadContext::DiscardSavedClassTable(bool is_rollback) {
+  intptr_t* local_saved_size_table = saved_size_table_;
+  shared_class_table_->ResetAfterHotReload(local_saved_size_table,
+                                           saved_num_cids_, is_rollback);
+  saved_size_table_.store(nullptr, std::memory_order_release);
 }
 
-void IsolateReloadContext::set_saved_root_library(const Library& value) {
-  saved_root_library_ = value.raw();
-}
-
-RawGrowableObjectArray* IsolateReloadContext::saved_libraries() const {
-  return saved_libraries_;
-}
-
-void IsolateReloadContext::set_saved_libraries(
-    const GrowableObjectArray& value) {
-  saved_libraries_ = value.raw();
+void IsolateGroupReloadContext::VisitObjectPointers(
+    ObjectPointerVisitor* visitor) {
+  visitor->VisitPointers(from(), to());
 }
 
 void IsolateReloadContext::VisitObjectPointers(ObjectPointerVisitor* visitor) {
   visitor->VisitPointers(from(), to());
 
-  ClassAndSize* saved_class_table =
+  RawClass** saved_class_table =
       saved_class_table_.load(std::memory_order_relaxed);
-  if (saved_class_table != nullptr) {
-    for (intptr_t i = 0; i < saved_num_cids_; i++) {
-      visitor->VisitPointer(
-          reinterpret_cast<RawObject**>(&(saved_class_table[i].class_)));
-    }
+  if (saved_class_table != NULL) {
+    auto class_table = reinterpret_cast<RawObject**>(&(saved_class_table[0]));
+    visitor->VisitPointers(class_table, saved_num_cids_);
   }
 }
 
@@ -1645,23 +1811,32 @@
  public:
   InvalidationCollector(Zone* zone,
                         GrowableArray<const Function*>* functions,
-                        GrowableArray<const KernelProgramInfo*>* kernel_infos)
-      : zone_(zone), functions_(functions), kernel_infos_(kernel_infos) {}
+                        GrowableArray<const KernelProgramInfo*>* kernel_infos,
+                        GrowableArray<const Field*>* fields,
+                        GrowableArray<const Instance*>* instances)
+      : zone_(zone),
+        functions_(functions),
+        kernel_infos_(kernel_infos),
+        fields_(fields),
+        instances_(instances) {}
   virtual ~InvalidationCollector() {}
 
-  virtual void VisitObject(RawObject* obj) {
-    if (obj->IsPseudoObject()) {
-      return;  // Cannot be wrapped in handles.
-    }
-    const Object& handle = Object::Handle(zone_, obj);
-    if (handle.IsFunction()) {
-      const auto& func = Function::Cast(handle);
+  void VisitObject(RawObject* obj) {
+    intptr_t cid = obj->GetClassId();
+    if (cid == kFunctionCid) {
+      const Function& func =
+          Function::Handle(zone_, static_cast<RawFunction*>(obj));
       if (!func.ForceOptimize()) {
         // Force-optimized functions cannot deoptimize.
         functions_->Add(&func);
       }
-    } else if (handle.IsKernelProgramInfo()) {
-      kernel_infos_->Add(&KernelProgramInfo::Cast(handle));
+    } else if (cid == kKernelProgramInfoCid) {
+      kernel_infos_->Add(&KernelProgramInfo::Handle(
+          zone_, static_cast<RawKernelProgramInfo*>(obj)));
+    } else if (cid == kFieldCid) {
+      fields_->Add(&Field::Handle(zone_, static_cast<RawField*>(obj)));
+    } else if (cid > kNumPredefinedCids) {
+      instances_->Add(&Instance::Handle(zone_, static_cast<RawInstance*>(obj)));
     }
   }
 
@@ -1669,18 +1844,19 @@
   Zone* const zone_;
   GrowableArray<const Function*>* const functions_;
   GrowableArray<const KernelProgramInfo*>* const kernel_infos_;
+  GrowableArray<const Field*>* const fields_;
+  GrowableArray<const Instance*>* const instances_;
 };
 
 typedef UnorderedHashMap<SmiTraits> IntHashMap;
 
 void IsolateReloadContext::RunInvalidationVisitors() {
-  TIMELINE_SCOPE(MarkAllFunctionsForRecompilation);
   TIR_Print("---- RUNNING INVALIDATION HEAP VISITORS\n");
   Thread* thread = Thread::Current();
   StackZone stack_zone(thread);
   Zone* zone = stack_zone.GetZone();
 
-  Thread* mutator_thread = isolate()->mutator_thread();
+  Thread* mutator_thread = I->mutator_thread();
   if (mutator_thread != nullptr) {
     Interpreter* interpreter = mutator_thread->interpreter();
     if (interpreter != nullptr) {
@@ -1690,13 +1866,27 @@
 
   GrowableArray<const Function*> functions(4 * KB);
   GrowableArray<const KernelProgramInfo*> kernel_infos(KB);
+  GrowableArray<const Field*> fields(4 * KB);
+  GrowableArray<const Instance*> instances(4 * KB);
 
   {
     HeapIterationScope iteration(thread);
-    InvalidationCollector visitor(zone, &functions, &kernel_infos);
+    InvalidationCollector visitor(zone, &functions, &kernel_infos, &fields,
+                                  &instances);
     iteration.IterateObjects(&visitor);
   }
 
+  InvalidateKernelInfos(zone, kernel_infos);
+  InvalidateFunctions(zone, functions);
+  InvalidateFields(zone, fields, instances);
+}
+
+void IsolateReloadContext::InvalidateKernelInfos(
+    Zone* zone,
+    const GrowableArray<const KernelProgramInfo*>& kernel_infos) {
+  TIMELINE_SCOPE(InvalidateKernelInfos);
+  HANDLESCOPE(Thread::Current());
+
   Array& data = Array::Handle(zone);
   Object& key = Object::Handle(zone);
   Smi& value = Smi::Handle(zone);
@@ -1723,6 +1913,13 @@
       kernel::BytecodeReader::ResetObjectTable(info);
     }
   }
+}
+
+void IsolateReloadContext::InvalidateFunctions(
+    Zone* zone,
+    const GrowableArray<const Function*>& functions) {
+  TIMELINE_SCOPE(InvalidateFunctions);
+  HANDLESCOPE(Thread::Current());
 
   CallSiteResetter resetter(zone);
 
@@ -1781,7 +1978,196 @@
   }
 }
 
+// Finds fields that are initialized or have a value that does not conform to
+// the field's static type, setting Field::needs_load_guard(). Accessors for
+// such fields are compiled with additional checks to handle lazy initialization
+// and to preserve type soundness.
+class FieldInvalidator {
+ public:
+  explicit FieldInvalidator(Zone* zone)
+      : cls_(Class::Handle(zone)),
+        cls_fields_(Array::Handle(zone)),
+        entry_(Object::Handle(zone)),
+        value_(Instance::Handle(zone)),
+        type_(AbstractType::Handle(zone)),
+        cache_(SubtypeTestCache::Handle(zone)),
+        entries_(Array::Handle(zone)),
+        instantiator_type_arguments_(TypeArguments::Handle(zone)),
+        function_type_arguments_(TypeArguments::Handle(zone)),
+        instance_cid_or_function_(Object::Handle(zone)),
+        instance_type_arguments_(TypeArguments::Handle(zone)),
+        parent_function_type_arguments_(TypeArguments::Handle(zone)),
+        delayed_function_type_arguments_(TypeArguments::Handle(zone)) {}
+
+  void CheckStatics(const GrowableArray<const Field*>& fields) {
+    HANDLESCOPE(Thread::Current());
+    instantiator_type_arguments_ = TypeArguments::null();
+    for (intptr_t i = 0; i < fields.length(); i++) {
+      const Field& field = *fields[i];
+      if (!field.is_static()) {
+        continue;
+      }
+      if (field.needs_load_guard()) {
+        continue;  // Already guarding.
+      }
+      value_ = field.StaticValue();
+      CheckValueType(value_, field);
+    }
+  }
+
+  void CheckInstances(const GrowableArray<const Instance*>& instances) {
+    for (intptr_t i = 0; i < instances.length(); i++) {
+      // This handle scope does run very frequently, but is a net-win by
+      // preventing us from spending too much time in malloc for new handle
+      // blocks.
+      HANDLESCOPE(Thread::Current());
+      CheckInstance(*instances[i]);
+    }
+  }
+
+ private:
+  DART_FORCE_INLINE
+  void CheckInstance(const Instance& instance) {
+    cls_ = instance.clazz();
+    if (cls_.NumTypeArguments() > 0) {
+      instantiator_type_arguments_ = instance.GetTypeArguments();
+    } else {
+      instantiator_type_arguments_ = TypeArguments::null();
+    }
+    cls_fields_ = cls_.OffsetToFieldMap();
+    for (intptr_t i = 0; i < cls_fields_.Length(); i++) {
+      entry_ = cls_fields_.At(i);
+      if (!entry_.IsField()) {
+        continue;
+      }
+      const Field& field = Field::Cast(entry_);
+      CheckInstanceField(instance, field);
+    }
+  }
+
+  DART_FORCE_INLINE
+  void CheckInstanceField(const Instance& instance, const Field& field) {
+    if (field.needs_load_guard()) {
+      return;  // Already guarding.
+    }
+    value_ ^= instance.GetField(field);
+    if (value_.raw() == Object::sentinel().raw()) {
+      // Needs guard for initialization.
+      ASSERT(!FLAG_identity_reload);
+      field.set_needs_load_guard(true);
+      return;
+    }
+    CheckValueType(value_, field);
+  }
+
+  DART_FORCE_INLINE
+  void CheckValueType(const Instance& value, const Field& field) {
+    if (value.IsNull()) {
+      return;  // TODO(nnbd): Implement.
+    }
+    type_ = field.type();
+    if (type_.IsDynamicType()) {
+      return;
+    }
+
+    cls_ = value.clazz();
+    const intptr_t cid = cls_.id();
+    if (cid == kClosureCid) {
+      instance_cid_or_function_ = Closure::Cast(value).function();
+      instance_type_arguments_ =
+          Closure::Cast(value).instantiator_type_arguments();
+      parent_function_type_arguments_ =
+          Closure::Cast(value).function_type_arguments();
+      delayed_function_type_arguments_ =
+          Closure::Cast(value).delayed_type_arguments();
+    } else {
+      instance_cid_or_function_ = Smi::New(cid);
+      if (cls_.NumTypeArguments() > 0) {
+        instance_type_arguments_ = value_.GetTypeArguments();
+      } else {
+        instance_type_arguments_ = TypeArguments::null();
+      }
+      parent_function_type_arguments_ = TypeArguments::null();
+      delayed_function_type_arguments_ = TypeArguments::null();
+    }
+
+    cache_ = field.type_test_cache();
+    if (cache_.IsNull()) {
+      cache_ = SubtypeTestCache::New();
+      field.set_type_test_cache(cache_);
+    }
+    entries_ = cache_.cache();
+
+    bool cache_hit = false;
+    for (intptr_t i = 0; entries_.At(i) != Object::null();
+         i += SubtypeTestCache::kTestEntryLength) {
+      if ((entries_.At(i + SubtypeTestCache::kInstanceClassIdOrFunction) ==
+           instance_cid_or_function_.raw()) &&
+          (entries_.At(i + SubtypeTestCache::kInstanceTypeArguments) ==
+           instance_type_arguments_.raw()) &&
+          (entries_.At(i + SubtypeTestCache::kInstantiatorTypeArguments) ==
+           instantiator_type_arguments_.raw()) &&
+          (entries_.At(i + SubtypeTestCache::kFunctionTypeArguments) ==
+           function_type_arguments_.raw()) &&
+          (entries_.At(
+               i + SubtypeTestCache::kInstanceParentFunctionTypeArguments) ==
+           parent_function_type_arguments_.raw()) &&
+          (entries_.At(
+               i + SubtypeTestCache::kInstanceDelayedFunctionTypeArguments) ==
+           delayed_function_type_arguments_.raw())) {
+        cache_hit = true;
+        if (entries_.At(i + SubtypeTestCache::kTestResult) !=
+            Bool::True().raw()) {
+          ASSERT(!FLAG_identity_reload);
+          field.set_needs_load_guard(true);
+        }
+        break;
+      }
+    }
+
+    if (!cache_hit) {
+      // TODO(regis): Make type check nullability aware.
+      if (!value.IsInstanceOf(NNBDMode::kLegacy, type_,
+                              instantiator_type_arguments_,
+                              function_type_arguments_)) {
+        ASSERT(!FLAG_identity_reload);
+        field.set_needs_load_guard(true);
+      } else {
+        cache_.AddCheck(instance_cid_or_function_, instance_type_arguments_,
+                        instantiator_type_arguments_, function_type_arguments_,
+                        parent_function_type_arguments_,
+                        delayed_function_type_arguments_, Bool::True());
+      }
+    }
+  }
+
+  Class& cls_;
+  Array& cls_fields_;
+  Object& entry_;
+  Instance& value_;
+  AbstractType& type_;
+  SubtypeTestCache& cache_;
+  Array& entries_;
+  TypeArguments& instantiator_type_arguments_;
+  TypeArguments& function_type_arguments_;
+  Object& instance_cid_or_function_;
+  TypeArguments& instance_type_arguments_;
+  TypeArguments& parent_function_type_arguments_;
+  TypeArguments& delayed_function_type_arguments_;
+};
+
+void IsolateReloadContext::InvalidateFields(
+    Zone* zone,
+    const GrowableArray<const Field*>& fields,
+    const GrowableArray<const Instance*>& instances) {
+  TIMELINE_SCOPE(InvalidateFields);
+  FieldInvalidator invalidator(zone);
+  invalidator.CheckStatics(fields);
+  invalidator.CheckInstances(instances);
+}
+
 void IsolateReloadContext::InvalidateWorld() {
+  TIMELINE_SCOPE(InvalidateWorld);
   TIR_Print("---- INVALIDATING WORLD\n");
   ResetMegamorphicCaches();
   if (FLAG_trace_deoptimization) {
@@ -1792,20 +2178,6 @@
   RunInvalidationVisitors();
 }
 
-RawClass* IsolateReloadContext::MappedClass(const Class& replacement_or_new) {
-  UnorderedHashMap<ClassMapTraits> map(class_map_storage_);
-  Class& cls = Class::Handle();
-  cls ^= map.GetOrNull(replacement_or_new);
-  // No need to update storage address because no mutation occurred.
-  map.Release();
-  return cls.raw();
-}
-
-RawLibrary* IsolateReloadContext::MappedLibrary(
-    const Library& replacement_or_new) {
-  return Library::null();
-}
-
 RawClass* IsolateReloadContext::OldClassOrNull(
     const Class& replacement_or_new) {
   UnorderedHashSet<ClassMapTraits> old_classes_set(old_classes_set_storage_);
@@ -1836,8 +2208,10 @@
   Library& lib = Library::Handle();
   lib ^= old_libraries_set.GetOrNull(replacement_or_new);
   old_libraries_set.Release();
-  if (lib.IsNull() && (root_url_prefix_ != String::null()) &&
-      (old_root_url_prefix_ != String::null())) {
+
+  if (lib.IsNull() &&
+      (group_reload_context_->root_url_prefix_ != String::null()) &&
+      (group_reload_context_->old_root_url_prefix_ != String::null())) {
     return OldLibraryOrNullBaseMoved(replacement_or_new);
   }
   return lib.raw();
@@ -1847,8 +2221,10 @@
 // the base url prefix has moved.
 RawLibrary* IsolateReloadContext::OldLibraryOrNullBaseMoved(
     const Library& replacement_or_new) {
-  const String& url_prefix = String::Handle(root_url_prefix_);
-  const String& old_url_prefix = String::Handle(old_root_url_prefix_);
+  const String& url_prefix =
+      String::Handle(group_reload_context_->root_url_prefix_);
+  const String& old_url_prefix =
+      String::Handle(group_reload_context_->old_root_url_prefix_);
   const intptr_t prefix_length = url_prefix.Length();
   const intptr_t old_prefix_length = old_url_prefix.Length();
   const String& new_url = String::Handle(replacement_or_new.url());
@@ -1860,8 +2236,7 @@
   Library& old = Library::Handle();
   String& old_url = String::Handle();
   String& old_suffix = String::Handle();
-  GrowableObjectArray& saved_libs =
-      GrowableObjectArray::Handle(saved_libraries());
+  const auto& saved_libs = GrowableObjectArray::Handle(saved_libraries_);
   ASSERT(!saved_libs.IsNull());
   for (intptr_t i = 0; i < saved_libs.Length(); i++) {
     old = Library::RawCast(saved_libs.At(i));
@@ -1888,7 +2263,8 @@
 
   Library& replacement_or_new = Library::Handle();
   Library& old = Library::Handle();
-  for (intptr_t i = num_saved_libs_; i < libs.Length(); i++) {
+  for (intptr_t i = group_reload_context_->num_saved_libs_; i < libs.Length();
+       i++) {
     replacement_or_new = Library::RawCast(libs.At(i));
     old = OldLibraryOrNull(replacement_or_new);
     if (old.IsNull()) {
diff --git a/runtime/vm/isolate_reload.h b/runtime/vm/isolate_reload.h
index a8c0d0a..bd3f86d 100644
--- a/runtime/vm/isolate_reload.h
+++ b/runtime/vm/isolate_reload.h
@@ -5,6 +5,9 @@
 #ifndef RUNTIME_VM_ISOLATE_RELOAD_H_
 #define RUNTIME_VM_ISOLATE_RELOAD_H_
 
+#include <functional>
+#include <memory>
+
 #include "include/dart_tools_api.h"
 
 #include "vm/globals.h"
@@ -42,6 +45,7 @@
 class GrowableObjectArray;
 class Isolate;
 class Library;
+class ObjectLocator;
 class ObjectPointerVisitor;
 class ObjectStore;
 class RawError;
@@ -54,45 +58,54 @@
 
 class InstanceMorpher : public ZoneAllocated {
  public:
-  InstanceMorpher(Zone* zone, const Class& from, const Class& to);
+  // Creates a new [InstanceMorpher] based on the [from]/[to] class
+  // descriptions.
+  static InstanceMorpher* CreateFromClassDescriptors(
+      Zone* zone,
+      SharedClassTable* shared_class_table,
+      const Class& from,
+      const Class& to);
+
+  InstanceMorpher(Zone* zone,
+                  classid_t cid,
+                  SharedClassTable* shared_class_table,
+                  ZoneGrowableArray<intptr_t>* mapping,
+                  ZoneGrowableArray<intptr_t>* new_fields_offsets);
   virtual ~InstanceMorpher() {}
 
   // Called on each instance that needs to be morphed.
   RawInstance* Morph(const Instance& instance) const;
 
   // Adds an object to be morphed.
-  void AddObject(RawObject* object) const;
+  void AddObject(RawObject* object);
 
   // Create the morphed objects based on the before() list.
-  void CreateMorphedCopies() const;
-
-  // Dump the state of the morpher.
-  void Dump() const;
+  void CreateMorphedCopies();
 
   // Append the morper info to JSON array.
   void AppendTo(JSONArray* array);
 
   // Returns the list of objects that need to be morphed.
-  ZoneGrowableArray<const Instance*>* before() const { return before_; }
+  const GrowableArray<const Instance*>* before() const { return &before_; }
+
   // Returns the list of morphed objects (matches order in before()).
-  ZoneGrowableArray<const Instance*>* after() const { return after_; }
-  // Returns the list of new fields.
-  ZoneGrowableArray<const Field*>* new_fields() const { return new_fields_; }
+  const GrowableArray<const Instance*>* after() const { return &after_; }
 
   // Returns the cid associated with the from_ and to_ class.
   intptr_t cid() const { return cid_; }
 
- private:
-  const Class& from_;
-  const Class& to_;
-  ZoneGrowableArray<intptr_t> mapping_;
-  ZoneGrowableArray<const Instance*>* before_;
-  ZoneGrowableArray<const Instance*>* after_;
-  ZoneGrowableArray<const Field*>* new_fields_;
-  intptr_t cid_;
+  // Dumps the field mappings for the [cid()] class.
+  void Dump() const;
 
-  void ComputeMapping();
-  void DumpFormatFor(const Class& cls) const;
+ private:
+  Zone* zone_;
+  classid_t cid_;
+  SharedClassTable* shared_class_table_;
+  ZoneGrowableArray<intptr_t>* mapping_;
+  ZoneGrowableArray<intptr_t>* new_fields_offsets_;
+
+  GrowableArray<const Instance*> before_;
+  GrowableArray<const Instance*> after_;
 };
 
 class ReasonForCancelling : public ZoneAllocated {
@@ -101,7 +114,7 @@
   virtual ~ReasonForCancelling() {}
 
   // Reports a reason for cancelling reload.
-  void Report(IsolateReloadContext* context);
+  void Report(IsolateGroupReloadContext* context);
 
   // Conversion to a VM error object.
   // Default implementation calls ToString.
@@ -128,13 +141,15 @@
   const Class& to_;
 };
 
-class IsolateReloadContext {
+class IsolateGroupReloadContext {
  public:
-  explicit IsolateReloadContext(Isolate* isolate, JSONStream* js);
-  ~IsolateReloadContext();
+  IsolateGroupReloadContext(IsolateGroup* isolate,
+                            SharedClassTable* shared_class_table,
+                            JSONStream* js);
+  ~IsolateGroupReloadContext();
 
   // If kernel_buffer is provided, the VM takes ownership when Reload is called.
-  void Reload(bool force_reload,
+  bool Reload(bool force_reload,
               const char* root_script_url = NULL,
               const char* packages_url = NULL,
               const uint8_t* kernel_buffer = NULL,
@@ -143,13 +158,15 @@
   // All zone allocated objects must be allocated from this zone.
   Zone* zone() const { return zone_; }
 
-  bool UseSavedClassTableForGC() const {
-    return saved_class_table_.load(std::memory_order_relaxed) != nullptr;
+  bool UseSavedSizeTableForGC() const {
+    return saved_size_table_.load(std::memory_order_relaxed) != nullptr;
   }
 
+  IsolateGroup* isolate_group() const { return isolate_group_; }
+  bool reload_aborted() const { return HasReasonsForCancelling(); }
   bool reload_skipped() const { return reload_skipped_; }
-  bool reload_aborted() const { return reload_aborted_; }
   RawError* error() const;
+  int64_t start_time_micros() const { return start_time_micros_; }
   int64_t reload_timestamp() const { return reload_timestamp_; }
 
   static Dart_FileModifiedCallback file_modified_callback() {
@@ -159,32 +176,10 @@
     file_modified_callback_ = callback;
   }
 
-  static bool IsSameField(const Field& a, const Field& b);
-  static bool IsSameLibrary(const Library& a_lib, const Library& b_lib);
-  static bool IsSameClass(const Class& a, const Class& b);
-
  private:
-  RawLibrary* saved_root_library() const;
-
-  RawGrowableObjectArray* saved_libraries() const;
-
-  RawClass* FindOriginalClass(const Class& cls);
-
-  bool IsDirty(const Library& lib);
-
-  // Prefers old classes when we are in the middle of a reload.
-  RawClass* GetClassForHeapWalkAt(intptr_t cid);
-  intptr_t GetClassSizeForHeapWalkAt(intptr_t cid);
+  intptr_t GetClassSizeForHeapWalkAt(classid_t cid);
   void DiscardSavedClassTable(bool is_rollback);
 
-  void RegisterClass(const Class& new_cls);
-
-  // Finds the library private key for |replacement_or_new| or return null
-  // if |replacement_or_new| is new.
-  RawString* FindLibraryPrivateKey(const Library& replacement_or_new);
-
-  int64_t start_time_micros() const { return start_time_micros_; }
-
   // Tells whether there are reasons for cancelling the reload.
   bool HasReasonsForCancelling() const {
     return !reasons_to_cancel_reload_.is_empty();
@@ -197,106 +192,70 @@
   void ReportReasonsForCancelling();
 
   // Reports the details of a reload operation.
-  void ReportOnJSON(JSONStream* stream);
+  void ReportOnJSON(JSONStream* stream, intptr_t final_library_count);
 
-  // Store morphing operation.
-  void AddInstanceMorpher(InstanceMorpher* morpher);
+  // Ensures there is a instance morpher for [cid], if not it will use
+  // [instance_morpher]
+  void EnsureHasInstanceMorpherFor(classid_t cid,
+                                   InstanceMorpher* instance_morpher);
 
   // Tells whether instance in the heap must be morphed.
   bool HasInstanceMorphers() const { return !instance_morphers_.is_empty(); }
 
-  // NOTE: FinalizeLoading will be called *before* Reload() returns. This
-  // function will not be called if the embedder does not call
-  // Dart_FinalizeLoading.
-  void FinalizeLoading();
-
-  // NOTE: FinalizeFailedLoad will be called *before* Reload returns. This
-  // function will not be called if the embedder calls Dart_FinalizeLoading.
-  void FinalizeFailedLoad(const Error& error);
-
   // Called by both FinalizeLoading and FinalizeFailedLoad.
-  void CommonFinalizeTail();
+  void CommonFinalizeTail(intptr_t final_library_count);
 
   // Report back through the observatory channels.
   void ReportError(const Error& error);
   void ReportSuccess();
 
-  void set_saved_root_library(const Library& value);
-
-  void set_saved_libraries(const GrowableObjectArray& value);
-
   void VisitObjectPointers(ObjectPointerVisitor* visitor);
 
-  Isolate* isolate() { return isolate_; }
-  ObjectStore* object_store();
-
-  void EnsuredUnoptimizedCodeForStack();
-  void DeoptimizeDependentCode();
-
-  void Checkpoint();
-
-  void CheckpointClasses();
-
-  bool ScriptModifiedSince(const Script& script, int64_t since);
-  void FindModifiedSources(Thread* thread,
-                           bool force_reload,
+  void GetRootLibUrl(const char* root_script_url);
+  char* CompileToKernel(bool force_reload,
+                        const char* packages_url,
+                        const uint8_t** kernel_buffer,
+                        intptr_t* kernel_buffer_size);
+  RawExternalTypedData* MakeRetainedTypedData(const uint8_t* kernel_buffer,
+                                              intptr_t kernel_buffer_size);
+  void FindModifiedSources(bool force_reload,
                            Dart_SourceFile** modified_sources,
                            intptr_t* count,
                            const char* packages_url);
+  bool ScriptModifiedSince(const Script& script, int64_t since);
 
-  void CheckpointLibraries();
+  void CheckpointSharedClassTable();
 
-  void MorphInstancesAndApplyNewClassTable();
+  void MorphInstancesPhase1Allocate(ObjectLocator* locator,
+                                    const Array& before,
+                                    const Array& after);
+  void MorphInstancesPhase2Become(const Array& before, const Array& after);
 
-  bool ValidateReload();
-
-  void Rollback();
-
-  void RollbackClasses();
-  void RollbackLibraries();
-
-#ifdef DEBUG
-  void VerifyMaps();
-#endif
-
-  void Commit();
-
-  void PostCommit();
-
-  void ClearReplacedObjectBits();
-
-  // atomic_install:
-  void RunInvalidationVisitors();
-  void ResetUnoptimizedICsOnStack();
-  void ResetMegamorphicCaches();
-  void InvalidateWorld();
+  void ForEachIsolate(std::function<void(Isolate*)> callback);
 
   // The zone used for all reload related allocations.
   Zone* zone_;
 
-  int64_t start_time_micros_;
-  int64_t reload_timestamp_;
-  Isolate* isolate_;
-  bool reload_skipped_;
-  bool reload_aborted_;
-  bool reload_finalized_;
+  IsolateGroup* isolate_group_;
+  SharedClassTable* shared_class_table_;
+
+  int64_t start_time_micros_ = -1;
+  int64_t reload_timestamp_ = -1;
+  Isolate* first_isolate_ = nullptr;
+  bool reload_skipped_ = false;
+  bool reload_finalized_ = false;
   JSONStream* js_;
+  intptr_t num_old_libs_ = -1;
 
-  intptr_t saved_num_cids_;
-  std::atomic<ClassAndSize*> saved_class_table_;
-  intptr_t num_saved_libs_;
-  intptr_t num_received_libs_;
-  intptr_t bytes_received_libs_;
-  intptr_t num_received_classes_;
-  intptr_t num_received_procedures_;
+  intptr_t saved_num_cids_ = -1;
+  std::atomic<intptr_t*> saved_size_table_;
+  intptr_t num_received_libs_ = -1;
+  intptr_t bytes_received_libs_ = -1;
+  intptr_t num_received_classes_ = -1;
+  intptr_t num_received_procedures_ = -1;
+  intptr_t num_saved_libs_ = -1;
 
-  // Collect the necessary instance transformation for schema changes.
-  ZoneGrowableArray<InstanceMorpher*> instance_morphers_;
-
-  // Collects the reasons for cancelling the reload.
-  ZoneGrowableArray<ReasonForCancelling*> reasons_to_cancel_reload_;
-
-  // Required trait for the cid_mapper_;
+  // Required trait for the instance_morpher_by_cid_;
   struct MorpherTrait {
     typedef InstanceMorpher* Value;
     typedef intptr_t Key;
@@ -308,53 +267,22 @@
     static bool IsKeyEqual(Pair kv, Key key) { return kv->cid() == key; }
   };
 
-  // Hash map from cid to InstanceMorpher.
-  DirectChainedHashMap<MorpherTrait> cid_mapper_;
+  // Collect the necessary instance transformation for schema changes.
+  GrowableArray<InstanceMorpher*> instance_morphers_;
 
-  struct LibraryInfo {
-    bool dirty;
-  };
-  MallocGrowableArray<LibraryInfo> library_infos_;
+  // Collects the reasons for cancelling the reload.
+  GrowableArray<ReasonForCancelling*> reasons_to_cancel_reload_;
+
+  // Hash map from cid to InstanceMorpher.
+  DirectChainedHashMap<MorpherTrait> instance_morpher_by_cid_;
 
   // A bit vector indicating which of the original libraries were modified.
-  BitVector* modified_libs_;
+  BitVector* modified_libs_ = nullptr;
 
-  RawClass* OldClassOrNull(const Class& replacement_or_new);
-
-  RawLibrary* OldLibraryOrNull(const Library& replacement_or_new);
-
-  RawLibrary* OldLibraryOrNullBaseMoved(const Library& replacement_or_new);
-
-  void BuildLibraryMapping();
-  void BuildRemovedClassesSet();
-
-  void AddClassMapping(const Class& replacement_or_new, const Class& original);
-
-  void AddLibraryMapping(const Library& replacement_or_new,
-                         const Library& original);
-
-  void AddStaticFieldMapping(const Field& old_field, const Field& new_field);
-
-  void AddBecomeMapping(const Object& old, const Object& neu);
-  void AddEnumBecomeMapping(const Object& old, const Object& neu);
-
-  void RebuildDirectSubclasses();
-
-  RawClass* MappedClass(const Class& replacement_or_new);
-  RawLibrary* MappedLibrary(const Library& replacement_or_new);
-
-  RawObject** from() { return reinterpret_cast<RawObject**>(&script_url_); }
-  RawString* script_url_;
-  RawError* error_;
-  RawArray* old_classes_set_storage_;
-  RawArray* class_map_storage_;
-  RawArray* removed_class_set_storage_;
-  RawArray* old_libraries_set_storage_;
-  RawArray* library_map_storage_;
-  RawArray* become_map_storage_;
-  RawGrowableObjectArray* become_enum_mappings_;
-  RawLibrary* saved_root_library_;
-  RawGrowableObjectArray* saved_libraries_;
+  String& root_lib_url_;
+  RawObject** from() {
+    return reinterpret_cast<RawObject**>(&root_url_prefix_);
+  }
   RawString* root_url_prefix_;
   RawString* old_root_url_prefix_;
   RawObject** to() {
@@ -367,10 +295,136 @@
   friend class ObjectLocator;
   friend class MarkFunctionsForRecompilation;  // IsDirty.
   friend class ReasonForCancelling;
+  friend class IsolateReloadContext;
+  friend class Instance;  // GetClassSizeForHeapWalkAt
 
   static Dart_FileModifiedCallback file_modified_callback_;
 };
 
+class IsolateReloadContext {
+ public:
+  IsolateReloadContext(
+      std::shared_ptr<IsolateGroupReloadContext> group_reload_context,
+      Isolate* isolate);
+  ~IsolateReloadContext();
+
+  // All zone allocated objects must be allocated from this zone.
+  Zone* zone() const { return zone_; }
+
+  IsolateGroupReloadContext* group_reload_context() {
+    return group_reload_context_.get();
+  }
+
+  static bool IsSameLibrary(const Library& a_lib, const Library& b_lib);
+  static bool IsSameClass(const Class& a, const Class& b);
+
+ private:
+  bool IsDirty(const Library& lib);
+
+  // Prefers old classes when we are in the middle of a reload.
+  RawClass* GetClassForHeapWalkAt(intptr_t cid);
+  void DiscardSavedClassTable(bool is_rollback);
+
+  void RegisterClass(const Class& new_cls);
+
+  // Finds the library private key for |replacement_or_new| or return null
+  // if |replacement_or_new| is new.
+  RawString* FindLibraryPrivateKey(const Library& replacement_or_new);
+
+  void VisitObjectPointers(ObjectPointerVisitor* visitor);
+
+  Isolate* isolate() { return isolate_; }
+  ObjectStore* object_store();
+
+  void EnsuredUnoptimizedCodeForStack();
+  void DeoptimizeDependentCode();
+
+  void ReloadPhase1AllocateStorageMapsAndCheckpoint();
+  void CheckpointClasses();
+  RawObject* ReloadPhase2LoadKernel(kernel::Program* program,
+                                    const String& root_lib_url);
+  void ReloadPhase3FinalizeLoading();
+  void ReloadPhase4CommitPrepare();
+  void ReloadPhase4CommitFinish();
+  void ReloadPhase4Rollback();
+
+  void CheckpointLibraries();
+
+  void RollbackClasses();
+  void RollbackLibraries();
+
+#ifdef DEBUG
+  void VerifyMaps();
+#endif
+
+  void CommitBeforeInstanceMorphing();
+  void CommitAfterInstanceMorphing();
+  void PostCommit();
+
+  void RunInvalidationVisitors();
+  void InvalidateKernelInfos(
+      Zone* zone,
+      const GrowableArray<const KernelProgramInfo*>& kernel_infos);
+  void InvalidateFunctions(Zone* zone,
+                           const GrowableArray<const Function*>& functions);
+  void InvalidateFields(Zone* zone,
+                        const GrowableArray<const Field*>& fields,
+                        const GrowableArray<const Instance*>& instances);
+  void ResetUnoptimizedICsOnStack();
+  void ResetMegamorphicCaches();
+  void InvalidateWorld();
+
+  struct LibraryInfo {
+    bool dirty;
+  };
+
+  // The zone used for all reload related allocations.
+  Zone* zone_;
+  std::shared_ptr<IsolateGroupReloadContext> group_reload_context_;
+  Isolate* isolate_;
+  intptr_t saved_num_cids_ = -1;
+  std::atomic<RawClass**> saved_class_table_;
+  MallocGrowableArray<LibraryInfo> library_infos_;
+
+  RawClass* OldClassOrNull(const Class& replacement_or_new);
+  RawLibrary* OldLibraryOrNull(const Library& replacement_or_new);
+  RawLibrary* OldLibraryOrNullBaseMoved(const Library& replacement_or_new);
+
+  void BuildLibraryMapping();
+  void BuildRemovedClassesSet();
+  void ValidateReload();
+
+  void AddClassMapping(const Class& replacement_or_new, const Class& original);
+  void AddLibraryMapping(const Library& replacement_or_new,
+                         const Library& original);
+  void AddStaticFieldMapping(const Field& old_field, const Field& new_field);
+  void AddBecomeMapping(const Object& old, const Object& neu);
+  void AddEnumBecomeMapping(const Object& old, const Object& neu);
+  void RebuildDirectSubclasses();
+
+  RawObject** from() {
+    return reinterpret_cast<RawObject**>(&old_classes_set_storage_);
+  }
+  RawArray* old_classes_set_storage_;
+  RawArray* class_map_storage_;
+  RawArray* removed_class_set_storage_;
+  RawArray* old_libraries_set_storage_;
+  RawArray* library_map_storage_;
+  RawArray* become_map_storage_;
+  RawGrowableObjectArray* become_enum_mappings_;
+  RawLibrary* saved_root_library_;
+  RawGrowableObjectArray* saved_libraries_;
+  RawObject** to() { return reinterpret_cast<RawObject**>(&saved_libraries_); }
+
+  friend class Isolate;
+  friend class Class;  // AddStaticFieldMapping, AddEnumBecomeMapping.
+  friend class Library;
+  friend class ObjectLocator;
+  friend class MarkFunctionsForRecompilation;  // IsDirty.
+  friend class ReasonForCancelling;
+  friend class IsolateGroupReloadContext;
+};
+
 class CallSiteResetter : public ValueObject {
  public:
   explicit CallSiteResetter(Zone* zone);
diff --git a/runtime/vm/isolate_reload_test.cc b/runtime/vm/isolate_reload_test.cc
index 575c061..79325d8 100644
--- a/runtime/vm/isolate_reload_test.cc
+++ b/runtime/vm/isolate_reload_test.cc
@@ -3617,7 +3617,7 @@
   EXPECT_ERROR(lib, "......");
 }
 
-TEST_CASE(IsolateReload_RunNewFieldInitialiazersSuperClass) {
+TEST_CASE(IsolateReload_RunNewFieldInitializersSuperClass) {
   const char* kScript =
       "class Super {\n"
       "  static var foo = 'right';\n"
@@ -3654,7 +3654,11 @@
   EXPECT_VALID(lib);
   // Verify that we ran field initializers on existing instances in the
   // correct scope.
-  EXPECT_STREQ("right", SimpleInvokeStr(lib, "main"));
+  const char* actual = SimpleInvokeStr(lib, "main");
+  EXPECT(actual != nullptr);
+  if (actual != nullptr) {
+    EXPECT_STREQ("right", actual);
+  }
 }
 
 TEST_CASE(IsolateReload_RunNewFieldInitializersWithConsts) {
@@ -3748,6 +3752,322 @@
       SimpleInvokeStr(lib, "main"));
 }
 
+TEST_CASE(IsolateReload_ExistingFieldChangesType) {
+  const char* kScript = R"(
+    class Foo {
+      int x = 42;
+    }
+    Foo value;
+    main() {
+      value = new Foo();
+      return 'Okay';
+    }
+  )";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+  EXPECT_STREQ("Okay", SimpleInvokeStr(lib, "main"));
+
+  const char* kReloadScript = R"(
+    class Foo {
+      double x = 42.0;
+    }
+    Foo value;
+    main() {
+      try {
+        return value.x.toString();
+      } catch (e) {
+        return e.toString();
+      }
+    }
+  )";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+  EXPECT_STREQ(
+      "type 'int' is not a subtype of type 'double' of 'function result'",
+      SimpleInvokeStr(lib, "main"));
+}
+
+TEST_CASE(IsolateReload_ExistingStaticFieldChangesType) {
+  const char* kScript = R"(
+    int value = init();
+    init() => 42;
+    main() {
+      return value.toString();
+    }
+  )";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+  EXPECT_STREQ("42", SimpleInvokeStr(lib, "main"));
+
+  const char* kReloadScript = R"(
+    double value = init();
+    init() => 42.0;
+    main() {
+      try {
+        return value.toString();
+      } catch (e) {
+        return e.toString();
+      }
+    }
+  )";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+  EXPECT_STREQ(
+      "type 'int' is not a subtype of type 'double' of 'function result'",
+      SimpleInvokeStr(lib, "main"));
+}
+
+TEST_CASE(IsolateReload_ExistingFieldChangesTypeIndirect) {
+  const char* kScript = R"(
+    class A {}
+    class B extends A {}
+    class Foo {
+      A x;
+      Foo(this.x);
+    }
+    Foo value;
+    main() {
+      value = new Foo(new B());
+      return 'Okay';
+    }
+  )";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+  EXPECT_STREQ("Okay", SimpleInvokeStr(lib, "main"));
+
+  // B is no longer a subtype of A.
+  const char* kReloadScript = R"(
+    class A {}
+    class B {}
+    class Foo {
+      A x;
+      Foo(this.x);
+    }
+    Foo value;
+    main() {
+      try {
+        return value.x.toString();
+      } catch (e) {
+        return e.toString();
+      }
+    }
+  )";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+  EXPECT_STREQ("type 'B' is not a subtype of type 'A' of 'function result'",
+               SimpleInvokeStr(lib, "main"));
+}
+
+TEST_CASE(IsolateReload_ExistingStaticFieldChangesTypeIndirect) {
+  const char* kScript = R"(
+    class A {}
+    class B extends A {}
+    A value = init();
+    init() => new B();
+    main() {
+      return value.toString();
+    }
+  )";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+  EXPECT_STREQ("Instance of 'B'", SimpleInvokeStr(lib, "main"));
+
+  // B is no longer a subtype of A.
+  const char* kReloadScript = R"(
+    class A {}
+    class B {}
+    A value = init();
+    init() => new A();
+    main() {
+      try {
+        return value.toString();
+      } catch (e) {
+        return e.toString();
+      }
+    }
+  )";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+  EXPECT_STREQ("type 'B' is not a subtype of type 'A' of 'function result'",
+               SimpleInvokeStr(lib, "main"));
+}
+
+TEST_CASE(IsolateReload_ExistingFieldChangesTypeIndirectGeneric) {
+  const char* kScript = R"(
+    class A {}
+    class B extends A {}
+    class Foo {
+      List<A> x;
+      Foo(this.x);
+    }
+    Foo value;
+    main() {
+      value = new Foo(new List<B>());
+      return 'Okay';
+    }
+  )";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+  EXPECT_STREQ("Okay", SimpleInvokeStr(lib, "main"));
+
+  // B is no longer a subtype of A.
+  const char* kReloadScript = R"(
+    class A {}
+    class B {}
+    class Foo {
+      List<A> x;
+      Foo(this.x);
+    }
+    Foo value;
+    main() {
+      try {
+        return value.x.toString();
+      } catch (e) {
+        return e.toString();
+      }
+    }
+  )";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+  EXPECT_STREQ(
+      "type 'List<B>' is not a subtype of type 'List<A>' of 'function result'",
+      SimpleInvokeStr(lib, "main"));
+}
+
+TEST_CASE(IsolateReload_ExistingStaticFieldChangesTypeIndirectGeneric) {
+  const char* kScript = R"(
+    class A {}
+    class B extends A {}
+    List<A> value = init();
+    init() => new List<B>();
+    main() {
+      return value.toString();
+    }
+  )";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+  EXPECT_STREQ("[]", SimpleInvokeStr(lib, "main"));
+
+  // B is no longer a subtype of A.
+  const char* kReloadScript = R"(
+    class A {}
+    class B {}
+    List<A> value = init();
+    init() => new List<A>();
+    main() {
+      try {
+        return value.toString();
+      } catch (e) {
+        return e.toString();
+      }
+    }
+  )";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+  EXPECT_STREQ(
+      "type 'List<B>' is not a subtype of type 'List<A>' of 'function result'",
+      SimpleInvokeStr(lib, "main"));
+}
+
+TEST_CASE(IsolateReload_ExistingFieldChangesTypeIndirectFunction) {
+  const char* kScript = R"(
+    class A {}
+    class B extends A {}
+    typedef bool Predicate(B b);
+    class Foo {
+      Predicate x;
+      Foo(this.x);
+    }
+    Foo value;
+    main() {
+      value = new Foo((A a) => true);
+      return 'Okay';
+    }
+  )";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+  EXPECT_STREQ("Okay", SimpleInvokeStr(lib, "main"));
+
+  // B is no longer a subtype of A.
+  const char* kReloadScript = R"(
+    class A {}
+    class B {}
+    typedef bool Predicate(B b);
+    class Foo {
+      Predicate x;
+      Foo(this.x);
+    }
+    Foo value;
+    main() {
+      try {
+        return value.x.toString();
+      } catch (e) {
+        return e.toString();
+      }
+    }
+  )";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+  EXPECT_STREQ(
+      "type '(A) => bool' is not a subtype of type '(B) => bool' of 'function "
+      "result'",
+      SimpleInvokeStr(lib, "main"));
+}
+
+TEST_CASE(IsolateReload_ExistingStaticFieldChangesTypeIndirectFunction) {
+  const char* kScript = R"(
+    class A {}
+    class B extends A {}
+    typedef bool Predicate(B b);
+    Predicate value = init();
+    init() => (A a) => true;
+    main() {
+      return value.toString();
+    }
+  )";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+  EXPECT_VALID(lib);
+  EXPECT_STREQ("Closure: (A) => bool", SimpleInvokeStr(lib, "main"));
+
+  // B is no longer a subtype of A.
+  const char* kReloadScript = R"(
+    class A {}
+    class B {}
+    typedef bool Predicate(B b);
+    Predicate value = init();
+    init() => (B a) => true;
+    main() {
+      try {
+        return value.toString();
+      } catch (e) {
+        return e.toString();
+      }
+    }
+  )";
+
+  lib = TestCase::ReloadTestScript(kReloadScript);
+  EXPECT_VALID(lib);
+  EXPECT_STREQ(
+      "type '(A) => bool' is not a subtype of type '(B) => bool' of 'function "
+      "result'",
+      SimpleInvokeStr(lib, "main"));
+}
+
 TEST_CASE(IsolateReload_TypedefToNotTypedef) {
   const char* kScript =
       "typedef bool Predicate(dynamic x);\n"
diff --git a/runtime/vm/isolate_test.cc b/runtime/vm/isolate_test.cc
index 05170a7..d4dc8f3 100644
--- a/runtime/vm/isolate_test.cc
+++ b/runtime/vm/isolate_test.cc
@@ -161,6 +161,14 @@
 };
 
 TEST_CASE(NoOOBMessageScope) {
+  // Finish any GC in progress so that no kVMInterrupt is added for GC reasons.
+  {
+    TransitionNativeToVM transition(thread);
+    GCTestHelper::CollectAllGarbage();
+    const Error& error = Error::Handle(thread->HandleInterrupts());
+    RELEASE_ASSERT(error.IsNull());
+  }
+
   // EXPECT_EQ is picky about type agreement for its arguments.
   const uword kZero = 0;
   const uword kMessageInterrupt = Thread::kMessageInterrupt;
diff --git a/runtime/vm/kernel_loader.cc b/runtime/vm/kernel_loader.cc
index 3b955ff..cfca523 100644
--- a/runtime/vm/kernel_loader.cc
+++ b/runtime/vm/kernel_loader.cc
@@ -2057,7 +2057,6 @@
   script.set_kernel_program_info(kernel_program_info_);
   script.set_line_starts(line_starts);
   script.set_debug_positions(Array::null_array());
-  script.set_yield_positions(Array::null_array());
   return script.raw();
 }
 
diff --git a/runtime/vm/native_arguments.h b/runtime/vm/native_arguments.h
index a7ff77d..67a3599 100644
--- a/runtime/vm/native_arguments.h
+++ b/runtime/vm/native_arguments.h
@@ -234,7 +234,7 @@
   class ReverseArgOrderBit
       : public BitField<intptr_t, bool, kReverseArgOrderBit, 1> {};
   friend class Api;
-  friend class BootstrapNatives;
+  friend class NativeEntry;
   friend class Interpreter;
   friend class Simulator;
 
diff --git a/runtime/vm/native_entry.cc b/runtime/vm/native_entry.cc
index 3176706..8cb8001 100644
--- a/runtime/vm/native_entry.cc
+++ b/runtime/vm/native_entry.cc
@@ -111,12 +111,40 @@
 uword NativeEntry::BootstrapNativeCallWrapperEntry() {
   uword entry =
       reinterpret_cast<uword>(NativeEntry::BootstrapNativeCallWrapper);
+#if defined(USING_SIMULATOR)
+  entry = Simulator::RedirectExternalReference(
+      entry, Simulator::kNativeCall, NativeEntry::kNumCallWrapperArguments);
+#endif
   return entry;
 }
 
 void NativeEntry::BootstrapNativeCallWrapper(Dart_NativeArguments args,
                                              Dart_NativeFunction func) {
-  func(args);
+  CHECK_STACK_ALIGNMENT;
+  if (func == LinkNativeCall) {
+    func(args);
+    return;
+  }
+
+  NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
+  // Tell MemorySanitizer 'arguments' is initialized by generated code.
+  MSAN_UNPOISON(arguments, sizeof(*arguments));
+  {
+    Thread* thread = arguments->thread();
+    ASSERT(thread == Thread::Current());
+    TransitionGeneratedToVM transition(thread);
+    StackZone zone(thread);
+    // Be careful holding return_value_unsafe without a handle here.
+    // A return of Object::sentinel means the return value has already
+    // been set.
+    RawObject* return_value_unsafe = reinterpret_cast<BootstrapNativeFunction>(
+        func)(thread, zone.GetZone(), arguments);
+    if (return_value_unsafe != Object::sentinel().raw()) {
+      ASSERT(return_value_unsafe->IsDartInstance());
+      arguments->SetReturnUnsafe(return_value_unsafe);
+    }
+    DEOPTIMIZE_ALOT;
+  }
 }
 
 uword NativeEntry::NoScopeNativeCallWrapperEntry() {
@@ -220,10 +248,6 @@
 
 uword NativeEntry::LinkNativeCallEntry() {
   uword entry = reinterpret_cast<uword>(NativeEntry::LinkNativeCall);
-#if defined(USING_SIMULATOR)
-  entry = Simulator::RedirectExternalReference(
-      entry, Simulator::kBootstrapNativeCall, NativeEntry::kNumArguments);
-#endif
   return entry;
 }
 
@@ -286,16 +310,8 @@
       const Code& current_trampoline =
           Code::Handle(zone, CodePatcher::GetNativeCallAt(
                                  caller_frame->pc(), code, &current_function));
-#if !defined(USING_SIMULATOR)
       ASSERT(current_function ==
              reinterpret_cast<NativeFunction>(LinkNativeCall));
-#else
-      ASSERT(
-          current_function ==
-          reinterpret_cast<NativeFunction>(Simulator::RedirectExternalReference(
-              reinterpret_cast<uword>(LinkNativeCall),
-              Simulator::kBootstrapNativeCall, NativeEntry::kNumArguments)));
-#endif
       ASSERT(current_trampoline.raw() == StubCode::CallBootstrapNative().raw());
     }
 #endif
@@ -321,12 +337,6 @@
       Code& trampoline = Code::Handle(zone);
       if (is_bootstrap_native) {
         trampoline = StubCode::CallBootstrapNative().raw();
-#if defined(USING_SIMULATOR)
-        patch_target_function = reinterpret_cast<NativeFunction>(
-            Simulator::RedirectExternalReference(
-                reinterpret_cast<uword>(patch_target_function),
-                Simulator::kBootstrapNativeCall, NativeEntry::kNumArguments));
-#endif  // defined USING_SIMULATOR
       } else if (is_auto_scope) {
         trampoline = StubCode::CallAutoScopeNative().raw();
       } else {
@@ -344,7 +354,8 @@
 
   // Tail-call resolved target.
   if (is_bootstrap_native) {
-    target_function(arguments);
+    NativeEntry::BootstrapNativeCallWrapper(
+        args, reinterpret_cast<Dart_NativeFunction>(target_function));
   } else if (is_auto_scope) {
     // Because this call is within a compilation unit, Clang doesn't respect
     // the ABI alignment here.
diff --git a/runtime/vm/native_entry.h b/runtime/vm/native_entry.h
index 52e83a5..d9d4264 100644
--- a/runtime/vm/native_entry.h
+++ b/runtime/vm/native_entry.h
@@ -33,37 +33,22 @@
   } while (0)
 #endif
 
+typedef RawObject* (*BootstrapNativeFunction)(Thread* thread,
+                                              Zone* zone,
+                                              NativeArguments* arguments);
+
 #define NATIVE_ENTRY_FUNCTION(name) BootstrapNatives::DN_##name
 
 #define DEFINE_NATIVE_ENTRY(name, type_argument_count, argument_count)         \
   static RawObject* DN_Helper##name(Isolate* isolate, Thread* thread,          \
                                     Zone* zone, NativeArguments* arguments);   \
-  void NATIVE_ENTRY_FUNCTION(name)(Dart_NativeArguments args) {                \
-    CHECK_STACK_ALIGNMENT;                                                     \
-    NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);     \
-    /* Tell MemorySanitizer 'arguments' is initialized by generated code. */   \
-    MSAN_UNPOISON(arguments, sizeof(*arguments));                              \
+  RawObject* NATIVE_ENTRY_FUNCTION(name)(Thread * thread, Zone * zone,         \
+                                         NativeArguments * arguments) {        \
+    TRACE_NATIVE_CALL("%s", "" #name);                                         \
     ASSERT(arguments->NativeArgCount() == argument_count);                     \
     /* Note: a longer type arguments vector may be passed */                   \
     ASSERT(arguments->NativeTypeArgCount() >= type_argument_count);            \
-    TRACE_NATIVE_CALL("%s", "" #name);                                         \
-    {                                                                          \
-      Thread* thread = arguments->thread();                                    \
-      ASSERT(thread == Thread::Current());                                     \
-      Isolate* isolate = thread->isolate();                                    \
-      TransitionGeneratedToVM transition(thread);                              \
-      StackZone zone(thread);                                                  \
-      /* Be careful holding return_value_unsafe without a handle here. */      \
-      /* A return of Object::sentinel means the return value has already */    \
-      /* been set. */                                                          \
-      RawObject* return_value_unsafe =                                         \
-          DN_Helper##name(isolate, thread, zone.GetZone(), arguments);         \
-      if (return_value_unsafe != Object::sentinel().raw()) {                   \
-        ASSERT(return_value_unsafe->IsDartInstance());                         \
-        arguments->SetReturnUnsafe(return_value_unsafe);                       \
-      }                                                                        \
-      DEOPTIMIZE_ALOT;                                                         \
-    }                                                                          \
+    return DN_Helper##name(thread->isolate(), thread, zone, arguments);        \
   }                                                                            \
   static RawObject* DN_Helper##name(Isolate* isolate, Thread* thread,          \
                                     Zone* zone, NativeArguments* arguments)
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index faf1184..b03021b 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -944,13 +944,25 @@
   cls.set_is_type_finalized();
 
   cls = dynamic_class_;
-  *dynamic_type_ = Type::NewNonParameterizedType(cls);
+  *dynamic_type_ = Type::New(cls, Object::null_type_arguments(),
+                             TokenPosition::kNoSource, Nullability::kNullable);
+  dynamic_type_->SetIsFinalized();
+  dynamic_type_->ComputeHash();
+  dynamic_type_->SetCanonical();
 
   cls = void_class_;
-  *void_type_ = Type::NewNonParameterizedType(cls);
+  *void_type_ = Type::New(cls, Object::null_type_arguments(),
+                          TokenPosition::kNoSource, Nullability::kNullable);
+  void_type_->SetIsFinalized();
+  void_type_->ComputeHash();
+  void_type_->SetCanonical();
 
   cls = never_class_;
-  *never_type_ = Type::NewNonParameterizedType(cls);
+  *never_type_ = Type::New(cls, Object::null_type_arguments(),
+                           TokenPosition::kNoSource, Nullability::kNonNullable);
+  never_type_->SetIsFinalized();
+  never_type_->ComputeHash();
+  never_type_->SetCanonical();
 
   // Since TypeArguments objects are passed as function arguments, make them
   // behave as Dart instances, although they are just VM objects.
@@ -1567,7 +1579,7 @@
     cls = object_store->array_class();  // Was allocated above.
     RegisterPrivateClass(cls, Symbols::_List(), core_lib);
     pending_classes.Add(cls);
-    // We cannot use NewNonParameterizedType(cls), because Array is
+    // We cannot use NewNonParameterizedType(), because Array is
     // parameterized.  Warning: class _List has not been patched yet. Its
     // declared number of type parameters is still 0. It will become 1 after
     // patching. The array type allocated below represents the raw type _List
@@ -1934,7 +1946,10 @@
     // name is a built-in identifier (this is wrong).  The corresponding types
     // are stored in the object store.
     cls = object_store->null_class();
-    type = Type::NewNonParameterizedType(cls);
+    type = Type::New(cls, Object::null_type_arguments(),
+                     TokenPosition::kNoSource, Nullability::kNullable);
+    type.SetIsFinalized();
+    type ^= type.Canonicalize();
     object_store->set_null_type(type);
     ASSERT(type.IsNullable());
 
@@ -2316,11 +2331,6 @@
   }
 #ifndef PRODUCT
   auto class_table = thread->isolate()->shared_class_table();
-  if (space == Heap::kNew) {
-    class_table->UpdateAllocatedNew(cls_id, size);
-  } else {
-    class_table->UpdateAllocatedOld(cls_id, size);
-  }
   if (class_table->TraceAllocationFor(cls_id)) {
     Profiler::SampleAllocation(thread, cls_id);
   }
@@ -2337,7 +2347,7 @@
     raw_obj->SetMarkBitUnsynchronized();
     // Setting the mark bit must not be ordered after a publishing store of this
     // object. Adding a barrier here is cheaper than making every store into the
-    // heap a store-release.
+    // heap a store-release. Compare Scavenger::ScavengePointer.
     std::atomic_thread_fence(std::memory_order_release);
     heap->old_space()->AllocateBlack(size);
   }
@@ -2442,6 +2452,9 @@
 }
 
 RawAbstractType* Class::RareType() const {
+  if (!IsGeneric() && !IsClosureClass() && !IsTypedefClass()) {
+    return DeclarationType();
+  }
   ASSERT(is_declaration_loaded());
   const Type& type = Type::Handle(Type::New(
       *this, Object::null_type_arguments(), TokenPosition::kNoSource));
@@ -3294,19 +3307,22 @@
 #endif
 
 bool AbstractType::InstantiateAndTestSubtype(
+    NNBDMode mode,
     AbstractType* subtype,
     AbstractType* supertype,
     const TypeArguments& instantiator_type_args,
     const TypeArguments& function_type_args) {
   if (!subtype->IsInstantiated()) {
-    *subtype = subtype->InstantiateFrom(
-        instantiator_type_args, function_type_args, kAllFree, NULL, Heap::kOld);
+    *subtype = subtype->InstantiateFrom(mode, instantiator_type_args,
+                                        function_type_args, kAllFree, NULL,
+                                        Heap::kOld);
   }
   if (!supertype->IsInstantiated()) {
-    *supertype = supertype->InstantiateFrom(
-        instantiator_type_args, function_type_args, kAllFree, NULL, Heap::kOld);
+    *supertype = supertype->InstantiateFrom(mode, instantiator_type_args,
+                                            function_type_args, kAllFree, NULL,
+                                            Heap::kOld);
   }
-  return subtype->IsSubtypeOf(*supertype, Heap::kOld);
+  return subtype->IsSubtypeOf(mode, *supertype, Heap::kOld);
 }
 
 RawArray* Class::invocation_dispatcher_cache() const {
@@ -3579,8 +3595,10 @@
                                InvocationMirror::kSetter);
     }
     parameter_type = setter.ParameterTypeAt(0);
+    // TODO(regis): Make type check nullability aware.
     if (!argument_type.IsNullType() && !parameter_type.IsDynamicType() &&
-        !value.IsInstanceOf(parameter_type, Object::null_type_arguments(),
+        !value.IsInstanceOf(NNBDMode::kLegacy, parameter_type,
+                            Object::null_type_arguments(),
                             Object::null_type_arguments())) {
       const String& argument_name =
           String::Handle(zone, setter.ParameterNameAt(0));
@@ -3602,8 +3620,10 @@
   }
 
   parameter_type = field.type();
+  // TODO(regis): Make type check nullability aware.
   if (!argument_type.IsNullType() && !parameter_type.IsDynamicType() &&
-      !value.IsInstanceOf(parameter_type, Object::null_type_arguments(),
+      !value.IsInstanceOf(NNBDMode::kLegacy, parameter_type,
+                          Object::null_type_arguments(),
                           Object::null_type_arguments())) {
     const String& argument_name = String::Handle(zone, field.name());
     return ThrowTypeError(field.token_pos(), value, parameter_type,
@@ -3650,25 +3670,27 @@
         call_args.SetAt(i + 1, temp);
       }
       call_args.SetAt(0, getter_result);
-      const Array& call_args_descriptor_array =
-          Array::Handle(zone, ArgumentsDescriptor::New(
-                                  kTypeArgsLen, call_args.Length(), arg_names));
+      const Array& call_args_descriptor_array = Array::Handle(
+          zone, ArgumentsDescriptor::New(kTypeArgsLen, call_args.Length(),
+                                         arg_names, Heap::kNew));
       // Call the closure.
       return DartEntry::InvokeClosure(call_args, call_args_descriptor_array);
     }
   }
-  const Array& args_descriptor_array = Array::Handle(
-      zone, ArgumentsDescriptor::New(kTypeArgsLen, args.Length(), arg_names));
+  const Array& args_descriptor_array =
+      Array::Handle(zone, ArgumentsDescriptor::New(kTypeArgsLen, args.Length(),
+                                                   arg_names, Heap::kNew));
   ArgumentsDescriptor args_descriptor(args_descriptor_array);
   const TypeArguments& type_args = Object::null_type_arguments();
-  if (function.IsNull() || !function.AreValidArguments(args_descriptor, NULL) ||
+  if (function.IsNull() ||
+      !function.AreValidArguments(NNBDMode::kLegacy, args_descriptor, NULL) ||
       (respect_reflectable && !function.is_reflectable())) {
     return ThrowNoSuchMethod(
         AbstractType::Handle(zone, RareType()), function_name, args, arg_names,
         InvocationMirror::kStatic, InvocationMirror::kMethod);
   }
-  RawObject* type_error =
-      function.DoArgumentTypesMatch(args, args_descriptor, type_args);
+  RawObject* type_error = function.DoArgumentTypesMatch(
+      NNBDMode::kLegacy, args, args_descriptor, type_args);
   if (type_error != Error::null()) {
     return type_error;
   }
@@ -3795,34 +3817,31 @@
   Smi& value = Smi::Handle(zone);
   String& field_name = String::Handle(zone);
 
+  static const struct {
+    const char* const field_name;
+    const intptr_t cid;
+  } cid_fields[] = {
 #define CLASS_LIST_WITH_NULL(V)                                                \
   V(Null)                                                                      \
   CLASS_LIST_NO_OBJECT(V)
-
-#define ADD_SET_FIELD(clazz)                                                   \
-  field_name = Symbols::New(thread, "cid" #clazz);                             \
-  field = Field::New(field_name, true, false, true, false, *this,              \
-                     Type::Handle(Type::IntType()), TokenPosition::kMinSource, \
-                     TokenPosition::kMinSource);                               \
-  value = Smi::New(k##clazz##Cid);                                             \
-  field.SetStaticValue(value, true);                                           \
-  AddField(field);
-
-  CLASS_LIST_WITH_NULL(ADD_SET_FIELD)
+#define ADD_SET_FIELD(clazz) {"cid" #clazz, k##clazz##Cid},
+      CLASS_LIST_WITH_NULL(ADD_SET_FIELD)
 #undef ADD_SET_FIELD
-
-#define ADD_SET_FIELD(clazz)                                                   \
-  field_name = Symbols::New(thread, "cid" #clazz "View");                      \
-  field = Field::New(field_name, true, false, true, false, *this,              \
-                     Type::Handle(Type::IntType()), TokenPosition::kMinSource, \
-                     TokenPosition::kMinSource);                               \
-  value = Smi::New(kTypedData##clazz##ViewCid);                                \
-  field.SetStaticValue(value, true);                                           \
-  AddField(field);
-
-  CLASS_LIST_TYPED_DATA(ADD_SET_FIELD)
+#define ADD_SET_FIELD(clazz) {"cid" #clazz "View", kTypedData##clazz##ViewCid},
+          CLASS_LIST_TYPED_DATA(ADD_SET_FIELD)
 #undef ADD_SET_FIELD
 #undef CLASS_LIST_WITH_NULL
+  };
+
+  const AbstractType& field_type = Type::Handle(zone, Type::IntType());
+  for (size_t i = 0; i < ARRAY_SIZE(cid_fields); i++) {
+    field_name = Symbols::New(thread, cid_fields[i].field_name);
+    field = Field::New(field_name, true, false, true, false, *this, field_type,
+                       TokenPosition::kMinSource, TokenPosition::kMinSource);
+    value = Smi::New(cid_fields[i].cid);
+    field.SetStaticValue(value, true);
+    AddField(field);
+  }
 
   return true;
 }
@@ -4329,27 +4348,51 @@
 }
 
 void Class::set_declaration_type(const Type& value) const {
+  ASSERT(!(id() >= kDynamicCid && id() <= kNeverCid));
   ASSERT(!value.IsNull() && value.IsCanonical() && value.IsOld());
   ASSERT((declaration_type() == Object::null()) ||
          (declaration_type() == value.raw()));  // Set during own finalization.
   // TODO(regis): Since declaration type is used as the runtime type of
   // instances of a non-generic class, the nullability should be set to
   // kNonNullable instead of kLegacy.
-  // For now, we set the nullability to kLegacy, except for Null.
-  ASSERT(value.IsLegacy() || (value.IsNullType() && value.IsNullable()));
+  // For now, we accept any except for Null (kNullable).
+  ASSERT(!value.IsNullType() || value.IsNullable());
+  ASSERT(value.IsNullType() || value.IsLegacy());
   StorePointer(&raw_ptr()->declaration_type_, value.raw());
 }
 
-RawType* Class::DeclarationType() const {
+RawType* Class::DeclarationType(Nullability nullability) const {
   ASSERT(is_declaration_loaded());
-  if (declaration_type() != Type::null()) {
-    return declaration_type();
+  if (IsNullClass()) {
+    // Ignore requested nullability (e.g. by mirrors).
+    return Type::NullType();
   }
-  Type& type = Type::Handle(
-      Type::New(*this, TypeArguments::Handle(type_parameters()), token_pos()));
+  if (IsDynamicClass()) {
+    return Type::DynamicType();
+  }
+  if (IsVoidClass()) {
+    return Type::VoidType();
+  }
+  if (IsNeverClass()) {
+    return Type::NeverType();
+  }
+  Type& type = Type::Handle(declaration_type());
+  if (!type.IsNull()) {
+    return type.ToNullability(nullability, Heap::kOld);
+  }
+  // TODO(regis): We should pass nullabiity to Type::New to avoid having to
+  // clone the type to the desired nullability. This however causes issues with
+  // the runtimeType intrinsic grabbing DeclarationType without checking its
+  // nullability. Indeed, when the CFE provides a non-nullable version of the
+  // type first, this non-nullable version gets cached as the declaration type.
+  // We consistenly cache the kLegacy version of a type, unless the non-nullable
+  // experiment is enabled, in which case we store the kNonNullable version.
+  // In either cases, the exception is type Null which is stored as kNullable.
+  type = Type::New(*this, TypeArguments::Handle(type_parameters()), token_pos(),
+                   Nullability::kLegacy);
   type ^= ClassFinalizer::FinalizeType(*this, type);
   set_declaration_type(type);
-  return type.raw();
+  return type.ToNullability(nullability, Heap::kOld);
 }
 
 void Class::set_allocation_stub(const Code& value) const {
@@ -4397,11 +4440,15 @@
 // type T by class 'other' parameterized with 'other_type_arguments'.
 // This class and class 'other' do not need to be finalized, however, they must
 // be resolved as well as their interfaces.
-bool Class::IsSubtypeOf(const Class& cls,
+bool Class::IsSubtypeOf(NNBDMode mode,
+                        const Class& cls,
                         const TypeArguments& type_arguments,
                         const Class& other,
                         const TypeArguments& other_type_arguments,
                         Heap::Space space) {
+  if (mode != NNBDMode::kLegacy) {
+    UNIMPLEMENTED();
+  }
   // Use the 'this_class' object as if it was the receiver of this method, but
   // instead of recursing, reset it to the super class and loop.
   Thread* thread = Thread::Current();
@@ -4420,8 +4467,8 @@
       return true;
     }
     // Apply additional subtyping rules if 'other' is 'FutureOr'.
-    if (Class::IsSubtypeOfFutureOr(zone, this_class, type_arguments, other,
-                                   other_type_arguments, space)) {
+    if (Class::IsSubtypeOfFutureOr(zone, mode, this_class, type_arguments,
+                                   other, other_type_arguments, space)) {
       return true;
     }
     // DynamicType is not more specific than any type.
@@ -4455,7 +4502,7 @@
         // above.
         return false;
       }
-      return type_arguments.IsSubtypeOf(other_type_arguments, from_index,
+      return type_arguments.IsSubtypeOf(mode, other_type_arguments, from_index,
                                         num_type_params, space);
     }
     // Check for 'direct super type' specified in the implements clause
@@ -4490,14 +4537,14 @@
         // after the type arguments of the super type of this type.
         // The index of the type parameters is adjusted upon finalization.
         interface_args = interface_args.InstantiateFrom(
-            type_arguments, Object::null_type_arguments(), kNoneFree, NULL,
-            space);
+            mode, type_arguments, Object::null_type_arguments(), kNoneFree,
+            NULL, space);
       }
       // In Dart 2, implementing Function has no meaning.
       if (interface_class.IsDartFunctionClass()) {
         continue;
       }
-      if (Class::IsSubtypeOf(interface_class, interface_args, other,
+      if (Class::IsSubtypeOf(mode, interface_class, interface_args, other,
                              other_type_arguments, space)) {
         return true;
       }
@@ -4513,6 +4560,7 @@
 }
 
 bool Class::IsSubtypeOfFutureOr(Zone* zone,
+                                NNBDMode mode,
                                 const Class& cls,
                                 const TypeArguments& type_arguments,
                                 const Class& other,
@@ -4530,12 +4578,12 @@
     if (!type_arguments.IsNull() && cls.IsFutureClass()) {
       const AbstractType& type_arg =
           AbstractType::Handle(zone, type_arguments.TypeAt(0));
-      if (type_arg.IsSubtypeOf(other_type_arg, space)) {
+      if (type_arg.IsSubtypeOf(mode, other_type_arg, space)) {
         return true;
       }
     }
     if (other_type_arg.HasTypeClass() &&
-        Class::IsSubtypeOf(cls, type_arguments,
+        Class::IsSubtypeOf(mode, cls, type_arguments,
                            Class::Handle(zone, other_type_arg.type_class()),
                            TypeArguments::Handle(other_type_arg.arguments()),
                            space)) {
@@ -5281,7 +5329,8 @@
   return true;
 }
 
-bool TypeArguments::IsSubtypeOf(const TypeArguments& other,
+bool TypeArguments::IsSubtypeOf(NNBDMode mode,
+                                const TypeArguments& other,
                                 intptr_t from_index,
                                 intptr_t len,
                                 Heap::Space space) const {
@@ -5294,7 +5343,7 @@
     type = TypeAt(from_index + i);
     other_type = other.TypeAt(from_index + i);
     if (type.IsNull() || other_type.IsNull() ||
-        !type.IsSubtypeOf(other_type, space)) {
+        !type.IsSubtypeOf(mode, other_type, space)) {
       return false;
     }
   }
@@ -5521,6 +5570,7 @@
 }
 
 RawTypeArguments* TypeArguments::InstantiateFrom(
+    NNBDMode mode,
     const TypeArguments& instantiator_type_arguments,
     const TypeArguments& function_type_arguments,
     intptr_t num_free_fun_type_params,
@@ -5547,7 +5597,7 @@
     if (!type.IsNull() &&
         !type.IsInstantiated(kAny, num_free_fun_type_params)) {
       type = type.InstantiateFrom(
-          instantiator_type_arguments, function_type_arguments,
+          mode, instantiator_type_arguments, function_type_arguments,
           num_free_fun_type_params, instantiation_trail, space);
       // A returned null type indicates a failed instantiation in dead code that
       // must be propagated up to the caller, the optimizing compiler.
@@ -5561,6 +5611,7 @@
 }
 
 RawTypeArguments* TypeArguments::InstantiateAndCanonicalizeFrom(
+    NNBDMode mode,
     const TypeArguments& instantiator_type_arguments,
     const TypeArguments& function_type_arguments) const {
   ASSERT(!IsInstantiated());
@@ -5587,8 +5638,8 @@
   }
   // Cache lookup failed. Instantiate the type arguments.
   TypeArguments& result = TypeArguments::Handle();
-  result = InstantiateFrom(instantiator_type_arguments, function_type_arguments,
-                           kAllFree, NULL, Heap::kOld);
+  result = InstantiateFrom(mode, instantiator_type_arguments,
+                           function_type_arguments, kAllFree, NULL, Heap::kOld);
   // Canonicalize type arguments.
   result = result.Canonicalize();
   // InstantiateAndCanonicalizeFrom is not reentrant. It cannot have been called
@@ -6318,8 +6369,8 @@
     const TypeArguments& signature_type_arguments =
         TypeArguments::Handle(scope_class.type_parameters());
     // Return the still unfinalized signature type.
-    type = Type::New(scope_class, signature_type_arguments, token_pos());
-    type.set_nullability(nullability);
+    type = Type::New(scope_class, signature_type_arguments, token_pos(),
+                     nullability);
     type.set_signature(*this);
     SetSignatureType(type);
   }
@@ -6854,7 +6905,8 @@
   return true;
 }
 
-bool Function::AreValidArguments(intptr_t num_type_arguments,
+bool Function::AreValidArguments(NNBDMode mode,
+                                 intptr_t num_type_arguments,
                                  intptr_t num_arguments,
                                  const Array& argument_names,
                                  String* error_message) const {
@@ -6899,7 +6951,8 @@
   return true;
 }
 
-bool Function::AreValidArguments(const ArgumentsDescriptor& args_desc,
+bool Function::AreValidArguments(NNBDMode mode,
+                                 const ArgumentsDescriptor& args_desc,
                                  String* error_message) const {
   const intptr_t num_type_arguments = args_desc.TypeArgsLen();
   const intptr_t num_arguments = args_desc.Count();
@@ -6909,6 +6962,10 @@
                               num_named_arguments, error_message)) {
     return false;
   }
+  if (mode != NNBDMode::kLegacy) {
+    // TODO(regis): Check required named arguments.
+    UNIMPLEMENTED();
+  }
   // Verify that all argument names are valid parameter names.
   Zone* zone = Thread::Current()->zone();
   String& argument_name = String::Handle(zone);
@@ -6945,6 +7002,7 @@
 }
 
 RawObject* Function::DoArgumentTypesMatch(
+    NNBDMode mode,
     const Array& args,
     const ArgumentsDescriptor& args_desc,
     const TypeArguments& instantiator_type_args) const {
@@ -6953,9 +7011,9 @@
   Function& instantiated_func = Function::Handle(zone, raw());
 
   if (!HasInstantiatedSignature()) {
-    instantiated_func = InstantiateSignatureFrom(instantiator_type_args,
+    instantiated_func = InstantiateSignatureFrom(mode, instantiator_type_args,
                                                  Object::null_type_arguments(),
-                                                 kAllFree, Heap::kOld);
+                                                 kAllFree, Heap::kNew);
   }
   AbstractType& argument_type = AbstractType::Handle(zone);
   AbstractType& parameter_type = AbstractType::Handle(zone);
@@ -6965,14 +7023,14 @@
   for (intptr_t i = args_desc.FirstArgIndex(); i < args_desc.PositionalCount();
        ++i) {
     argument ^= args.At(i);
-    argument_type = argument.GetType(Heap::kOld);
+    argument_type = argument.GetType(Heap::kNew);
     parameter_type = instantiated_func.ParameterTypeAt(i);
 
     // If the argument type is dynamic or the parameter is null, move on.
     if (parameter_type.IsDynamicType() || argument_type.IsNullType()) {
       continue;
     }
-    if (!argument.IsInstanceOf(parameter_type, instantiator_type_args,
+    if (!argument.IsInstanceOf(mode, parameter_type, instantiator_type_args,
                                Object::null_type_arguments())) {
       String& argument_name = String::Handle(zone, ParameterNameAt(i));
       return ThrowTypeError(token_pos(), argument, parameter_type,
@@ -7005,14 +7063,14 @@
       if (argument_name.Equals(parameter_name)) {
         found = true;
         argument ^= args.At(args_desc.PositionAt(i));
-        argument_type = argument.GetType(Heap::kOld);
+        argument_type = argument.GetType(Heap::kNew);
         parameter_type = instantiated_func.ParameterTypeAt(j);
 
         // If the argument type is dynamic or the parameter is null, move on.
         if (parameter_type.IsDynamicType() || argument_type.IsNullType()) {
           continue;
         }
-        if (!argument.IsInstanceOf(parameter_type, instantiator_type_args,
+        if (!argument.IsInstanceOf(mode, parameter_type, instantiator_type_args,
                                    Object::null_type_arguments())) {
           String& argument_name = String::Handle(zone, ParameterNameAt(i));
           return ThrowTypeError(token_pos(), argument, parameter_type,
@@ -7118,6 +7176,7 @@
 }
 
 RawFunction* Function::InstantiateSignatureFrom(
+    NNBDMode mode,
     const TypeArguments& instantiator_type_arguments,
     const TypeArguments& function_type_arguments,
     intptr_t num_free_fun_type_params,
@@ -7170,7 +7229,7 @@
         type_param ^= type_params.TypeAt(i);
         type = type_param.bound();
         if (!type.IsInstantiated(kAny, num_free_fun_type_params)) {
-          type = type.InstantiateFrom(instantiator_type_arguments,
+          type = type.InstantiateFrom(mode, instantiator_type_arguments,
                                       function_type_arguments,
                                       num_free_fun_type_params, NULL, space);
           // A returned null type indicates a failed instantiation in dead code
@@ -7206,7 +7265,7 @@
 
   type = result_type();
   if (!type.IsInstantiated(kAny, num_free_fun_type_params)) {
-    type = type.InstantiateFrom(instantiator_type_arguments,
+    type = type.InstantiateFrom(mode, instantiator_type_arguments,
                                 function_type_arguments,
                                 num_free_fun_type_params, NULL, space);
     // A returned null type indicates a failed instantiation in dead code that
@@ -7224,7 +7283,7 @@
   for (intptr_t i = 0; i < num_params; i++) {
     type = ParameterTypeAt(i);
     if (!type.IsInstantiated(kAny, num_free_fun_type_params)) {
-      type = type.InstantiateFrom(instantiator_type_arguments,
+      type = type.InstantiateFrom(mode, instantiator_type_arguments,
                                   function_type_arguments,
                                   num_free_fun_type_params, NULL, space);
       // A returned null type indicates a failed instantiation in dead code that
@@ -7247,7 +7306,8 @@
 // of the type of the specified parameter of the other function (i.e. check
 // parameter contravariance).
 // Note that types marked as covariant are already dealt with in the front-end.
-bool Function::IsContravariantParameter(intptr_t parameter_position,
+bool Function::IsContravariantParameter(NNBDMode mode,
+                                        intptr_t parameter_position,
                                         const Function& other,
                                         intptr_t other_parameter_position,
                                         Heap::Space space) const {
@@ -7258,7 +7318,7 @@
   }
   const AbstractType& other_param_type =
       AbstractType::Handle(other.ParameterTypeAt(other_parameter_position));
-  return other_param_type.IsSubtypeOf(param_type, space);
+  return other_param_type.IsSubtypeOf(mode, param_type, space);
 }
 
 bool Function::HasSameTypeParametersAndBounds(const Function& other) const {
@@ -7295,7 +7355,13 @@
   return true;
 }
 
-bool Function::IsSubtypeOf(const Function& other, Heap::Space space) const {
+bool Function::IsSubtypeOf(NNBDMode mode,
+                           const Function& other,
+                           Heap::Space space) const {
+  if (mode != NNBDMode::kLegacy) {
+    // TODO(regis): Check required named parameters.
+    UNIMPLEMENTED();
+  }
   const intptr_t num_fixed_params = num_fixed_parameters();
   const intptr_t num_opt_pos_params = NumOptionalPositionalParameters();
   const intptr_t num_opt_named_params = NumOptionalNamedParameters();
@@ -7328,7 +7394,7 @@
   // 'void Function()' is a subtype of 'Object Function()'.
   if (!other_res_type.IsTopType()) {
     const AbstractType& res_type = AbstractType::Handle(zone, result_type());
-    if (!res_type.IsSubtypeOf(other_res_type, space)) {
+    if (!res_type.IsSubtypeOf(mode, other_res_type, space)) {
       return false;
     }
   }
@@ -7336,7 +7402,7 @@
   for (intptr_t i = 0; i < (other_num_fixed_params - other_num_ignored_params +
                             other_num_opt_pos_params);
        i++) {
-    if (!IsContravariantParameter(i + num_ignored_params, other,
+    if (!IsContravariantParameter(mode, i + num_ignored_params, other,
                                   i + other_num_ignored_params, space)) {
       return false;
     }
@@ -7363,7 +7429,7 @@
       ASSERT(String::Handle(zone, ParameterNameAt(j)).IsSymbol());
       if (ParameterNameAt(j) == other_param_name.raw()) {
         found_param_name = true;
-        if (!IsContravariantParameter(j, other, i, space)) {
+        if (!IsContravariantParameter(mode, j, other, i, space)) {
           return false;
         }
         break;
@@ -9290,8 +9356,8 @@
   for (intptr_t i = path.length() - 2; (i >= 0) && !type.IsInstantiated();
        i--) {
     args = path[i]->arguments();
-    type = type.InstantiateFrom(args, TypeArguments::null_type_arguments(),
-                                kAllFree,
+    type = type.InstantiateFrom(NNBDMode::kLegacy, args,
+                                TypeArguments::null_type_arguments(), kAllFree,
                                 /*instantiation_trail=*/nullptr, Heap::kNew);
   }
 
@@ -9477,6 +9543,12 @@
   DeoptimizeDependentCode();
 }
 
+#if !defined(DART_PRECOMPILED_RUNTIME)
+void Field::set_type_test_cache(const SubtypeTestCache& cache) const {
+  StorePointer(&raw_ptr()->type_test_cache_, cache.raw());
+}
+#endif
+
 bool Script::HasSource() const {
   return raw_ptr()->source_ != String::null();
 }
@@ -9627,33 +9699,6 @@
   StorePointer(&raw_ptr()->debug_positions_, value.raw());
 }
 
-void Script::set_yield_positions(const Array& value) const {
-  StorePointer(&raw_ptr()->yield_positions_, value.raw());
-}
-
-RawArray* Script::yield_positions() const {
-  return raw_ptr()->yield_positions_;
-}
-
-RawGrowableObjectArray* Script::GetYieldPositions(
-    const Function& function) const {
-  if (!function.IsAsyncClosure() && !function.IsAsyncGenClosure())
-    return GrowableObjectArray::null();
-  ASSERT(!function.is_declared_in_bytecode());
-  Compiler::ComputeYieldPositions(function);
-  UnorderedHashMap<SmiTraits> function_map(raw_ptr()->yield_positions_);
-  const auto& key = Smi::Handle(Smi::New(function.token_pos().value()));
-  intptr_t entry = function_map.FindKey(key);
-  GrowableObjectArray& array = GrowableObjectArray::Handle();
-  if (entry < 0) {
-    array ^= GrowableObjectArray::null();
-  } else {
-    array ^= function_map.GetPayload(entry, 0);
-  }
-  function_map.Release();
-  return array.raw();
-}
-
 RawTypedData* Script::line_starts() const {
   return raw_ptr()->line_starts_;
 }
@@ -10201,9 +10246,10 @@
                                intptr_t bytecode_offset) const {
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
-  AddMetadata(Object::Handle(zone, field.RawOwner()),
-              String::Handle(zone, MakeFieldMetaName(thread, zone, field)),
-              token_pos, kernel_offset, bytecode_offset);
+  const auto& owner = Object::Handle(zone, field.RawOwner());
+  const auto& name =
+      String::Handle(zone, MakeFieldMetaName(thread, zone, field));
+  AddMetadata(owner, name, token_pos, kernel_offset, bytecode_offset);
 }
 
 void Library::AddFunctionMetadata(const Function& func,
@@ -10212,19 +10258,20 @@
                                   intptr_t bytecode_offset) const {
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
-  AddMetadata(Object::Handle(zone, func.RawOwner()),
-              String::Handle(zone, MakeFunctionMetaName(thread, zone, func)),
-              token_pos, kernel_offset, bytecode_offset);
+  const auto& owner = Object::Handle(zone, func.RawOwner());
+  const auto& name =
+      String::Handle(zone, MakeFunctionMetaName(thread, zone, func));
+  AddMetadata(owner, name, token_pos, kernel_offset, bytecode_offset);
 }
 
 void Library::AddTypeParameterMetadata(const TypeParameter& param,
                                        TokenPosition token_pos) const {
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
-  AddMetadata(
-      Class::Handle(zone, param.parameterized_class()),
-      String::Handle(zone, MakeTypeParameterMetaName(thread, zone, param)),
-      token_pos, 0, 0);
+  const auto& owner = Class::Handle(zone, param.parameterized_class());
+  const auto& name =
+      String::Handle(zone, MakeTypeParameterMetaName(thread, zone, param));
+  AddMetadata(owner, name, token_pos, 0, 0);
 }
 
 void Library::AddLibraryMetadata(const Object& tl_owner,
@@ -10308,9 +10355,8 @@
     // There is no metadata for this object.
     return Object::empty_array().raw();
   }
-  Object& metadata = Object::Handle();
-  metadata = field.StaticValue();
-  if (field.StaticValue() == Object::empty_array().raw()) {
+  Object& metadata = Object::Handle(field.StaticValue());
+  if (metadata.raw() == Object::empty_array().raw()) {
     if (field.is_declared_in_bytecode()) {
       metadata = kernel::BytecodeReader::ReadAnnotation(field);
     } else {
@@ -10320,9 +10366,11 @@
     }
     if (metadata.IsArray() || metadata.IsNull()) {
       ASSERT(metadata.raw() != Object::empty_array().raw());
-      field.SetStaticValue(
-          metadata.IsNull() ? Object::null_array() : Array::Cast(metadata),
-          true);
+      if (!Compiler::IsBackgroundCompilation()) {
+        field.SetStaticValue(
+            metadata.IsNull() ? Object::null_array() : Array::Cast(metadata),
+            true);
+      }
     }
   }
   if (metadata.IsNull()) {
@@ -11246,13 +11294,14 @@
   // Note "args" is already the internal arguments with the receiver as the
   // first element.
   ArgumentsDescriptor args_descriptor(args_descriptor_array);
-  if (function.IsNull() || !function.AreValidArguments(args_descriptor, NULL) ||
+  if (function.IsNull() ||
+      !function.AreValidArguments(NNBDMode::kLegacy, args_descriptor, NULL) ||
       (respect_reflectable && !function.is_reflectable())) {
     return DartEntry::InvokeNoSuchMethod(receiver, target_name, args,
                                          args_descriptor_array);
   }
-  RawObject* type_error = function.DoArgumentTypesMatch(args, args_descriptor,
-                                                        instantiator_type_args);
+  RawObject* type_error = function.DoArgumentTypesMatch(
+      NNBDMode::kLegacy, args, args_descriptor, instantiator_type_args);
   if (type_error != Error::null()) {
     return type_error;
   }
@@ -11343,7 +11392,8 @@
     }
     setter_type = field.type();
     if (!argument_type.IsNullType() && !setter_type.IsDynamicType() &&
-        !value.IsInstanceOf(setter_type, Object::null_type_arguments(),
+        !value.IsInstanceOf(NNBDMode::kLegacy, setter_type,
+                            Object::null_type_arguments(),
                             Object::null_type_arguments())) {
       return ThrowTypeError(field.token_pos(), value, setter_type, setter_name);
     }
@@ -11383,7 +11433,8 @@
 
   setter_type = setter.ParameterTypeAt(0);
   if (!argument_type.IsNullType() && !setter_type.IsDynamicType() &&
-      !value.IsInstanceOf(setter_type, Object::null_type_arguments(),
+      !value.IsInstanceOf(NNBDMode::kLegacy, setter_type,
+                          Object::null_type_arguments(),
                           Object::null_type_arguments())) {
     return ThrowTypeError(setter.token_pos(), value, setter_type, setter_name);
   }
@@ -11428,25 +11479,26 @@
       call_args.SetAt(0, getter_result);
       const Array& call_args_descriptor_array =
           Array::Handle(ArgumentsDescriptor::New(
-              kTypeArgsLen, call_args.Length(), arg_names));
+              kTypeArgsLen, call_args.Length(), arg_names, Heap::kNew));
       // Call closure.
       return DartEntry::InvokeClosure(call_args, call_args_descriptor_array);
     }
   }
 
-  const Array& args_descriptor_array = Array::Handle(
-      ArgumentsDescriptor::New(kTypeArgsLen, args.Length(), arg_names));
+  const Array& args_descriptor_array = Array::Handle(ArgumentsDescriptor::New(
+      kTypeArgsLen, args.Length(), arg_names, Heap::kNew));
   ArgumentsDescriptor args_descriptor(args_descriptor_array);
   const TypeArguments& type_args = Object::null_type_arguments();
-  if (function.IsNull() || !function.AreValidArguments(args_descriptor, NULL) ||
+  if (function.IsNull() ||
+      !function.AreValidArguments(NNBDMode::kLegacy, args_descriptor, NULL) ||
       (respect_reflectable && !function.is_reflectable())) {
     return ThrowNoSuchMethod(
         AbstractType::Handle(Class::Handle(toplevel_class()).RareType()),
         function_name, args, arg_names, InvocationMirror::kTopLevel,
         InvocationMirror::kMethod);
   }
-  RawObject* type_error =
-      function.DoArgumentTypesMatch(args, args_descriptor, type_args);
+  RawObject* type_error = function.DoArgumentTypesMatch(
+      NNBDMode::kLegacy, args, args_descriptor, type_args);
   if (type_error != Error::null()) {
     return type_error;
   }
@@ -11565,8 +11617,9 @@
       real_arguments.SetAt(i + 1, arg);
     }
 
-    const Array& args_desc = Array::Handle(
-        zone, ArgumentsDescriptor::New(num_type_args, arguments.Length()));
+    const Array& args_desc =
+        Array::Handle(zone, ArgumentsDescriptor::New(
+                                num_type_args, arguments.Length(), Heap::kNew));
     result = DartEntry::InvokeFunction(callee, real_arguments, args_desc);
   }
 
@@ -11630,7 +11683,7 @@
   Isolate* isolate = thread->isolate();
 
 #if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
-  if (FLAG_support_reload && isolate->IsReloading()) {
+  if (FLAG_support_reload && isolate->group()->IsReloading()) {
     // When reloading, we need to make sure we use the original private key
     // if this library previously existed.
     IsolateReloadContext* reload_context = isolate->reload_context();
@@ -11864,75 +11917,6 @@
   set_num_imports(num_current_imports + 1);
 }
 
-RawObject* LibraryPrefix::LookupObject(const String& name) const {
-  Array& imports = Array::Handle(this->imports());
-  Object& obj = Object::Handle();
-  Namespace& import = Namespace::Handle();
-  Library& import_lib = Library::Handle();
-  String& import_lib_url = String::Handle();
-  String& first_import_lib_url = String::Handle();
-  Object& found_obj = Object::Handle();
-  String& found_obj_name = String::Handle();
-  for (intptr_t i = 0; i < num_imports(); i++) {
-    import ^= imports.At(i);
-    obj = import.Lookup(name);
-    if (!obj.IsNull()) {
-      import_lib = import.library();
-      import_lib_url = import_lib.url();
-      if (found_obj.raw() != obj.raw()) {
-        if (first_import_lib_url.IsNull() ||
-            first_import_lib_url.StartsWith(Symbols::DartScheme())) {
-          // This is the first object we found, or the
-          // previously found object is exported from a Dart
-          // system library. The newly found object hides the one
-          // from the Dart library.
-          first_import_lib_url = import_lib.url();
-          found_obj = obj.raw();
-          found_obj_name = found_obj.DictionaryName();
-        } else if (import_lib_url.StartsWith(Symbols::DartScheme())) {
-          // The newly found object is exported from a Dart system
-          // library. It is hidden by the previously found object.
-          // We continue to search.
-        } else if (Field::IsSetterName(found_obj_name) &&
-                   !Field::IsSetterName(name)) {
-          // We are looking for an unmangled name or a getter, but
-          // the first object we found is a setter. Replace the first
-          // object with the one we just found.
-          first_import_lib_url = import_lib.url();
-          found_obj = obj.raw();
-          found_obj_name = found_obj.DictionaryName();
-        } else {
-          // We found two different objects with the same name.
-          // Note that we need to compare the names again because
-          // looking up an unmangled name can return a getter or a
-          // setter. A getter name is the same as the unmangled name,
-          // but a setter name is different from an unmangled name or a
-          // getter name.
-          if (Field::IsGetterName(found_obj_name)) {
-            found_obj_name = Field::NameFromGetter(found_obj_name);
-          }
-          String& second_obj_name = String::Handle(obj.DictionaryName());
-          if (Field::IsGetterName(second_obj_name)) {
-            second_obj_name = Field::NameFromGetter(second_obj_name);
-          }
-          if (found_obj_name.Equals(second_obj_name)) {
-            return Object::null();
-          }
-        }
-      }
-    }
-  }
-  return found_obj.raw();
-}
-
-RawClass* LibraryPrefix::LookupClass(const String& class_name) const {
-  const Object& obj = Object::Handle(LookupObject(class_name));
-  if (obj.IsClass()) {
-    return Class::Cast(obj).raw();
-  }
-  return Class::null();
-}
-
 RawLibraryPrefix* LibraryPrefix::New() {
   RawObject* raw = Object::Allocate(LibraryPrefix::kClassId,
                                     LibraryPrefix::InstanceSize(), Heap::kOld);
@@ -12817,13 +12801,14 @@
   const int addr_width = (kBitsPerWord / 4) + 2;
   // "*" in a printf format specifier tells it to read the field width from
   // the printf argument list.
-  THR_Print("%-*s\tkind    \tdeopt-id\ttok-ix\ttry-ix\n", addr_width, "pc");
+  THR_Print("%-*s\tkind    \tdeopt-id\ttok-ix\ttry-ix\tyield-idx\n", addr_width,
+            "pc");
 }
 
 const char* PcDescriptors::ToCString() const {
 // "*" in a printf format specifier tells it to read the field width from
 // the printf argument list.
-#define FORMAT "%#-*" Px "\t%s\t%" Pd "\t\t%s\t%" Pd "\n"
+#define FORMAT "%#-*" Px "\t%s\t%" Pd "\t\t%s\t%" Pd "\t%" Pd "\n"
   if (Length() == 0) {
     return "empty PcDescriptors\n";
   }
@@ -12836,7 +12821,8 @@
     while (iter.MoveNext()) {
       len += Utils::SNPrint(NULL, 0, FORMAT, addr_width, iter.PcOffset(),
                             KindAsStr(iter.Kind()), iter.DeoptId(),
-                            iter.TokenPos().ToCString(), iter.TryIndex());
+                            iter.TokenPos().ToCString(), iter.TryIndex(),
+                            iter.YieldIndex());
     }
   }
   // Allocate the buffer.
@@ -12845,10 +12831,10 @@
   intptr_t index = 0;
   Iterator iter(*this, RawPcDescriptors::kAnyKind);
   while (iter.MoveNext()) {
-    index +=
-        Utils::SNPrint((buffer + index), (len - index), FORMAT, addr_width,
-                       iter.PcOffset(), KindAsStr(iter.Kind()), iter.DeoptId(),
-                       iter.TokenPos().ToCString(), iter.TryIndex());
+    index += Utils::SNPrint((buffer + index), (len - index), FORMAT, addr_width,
+                            iter.PcOffset(), KindAsStr(iter.Kind()),
+                            iter.DeoptId(), iter.TokenPos().ToCString(),
+                            iter.TryIndex(), iter.YieldIndex());
   }
   return buffer;
 #undef FORMAT
@@ -12920,22 +12906,23 @@
   return "CodeSourceMap";
 }
 
-intptr_t CompressedStackMaps::Hash() const {
-  uint32_t hash = 0;
-  for (intptr_t i = 0; i < payload_size(); i++) {
-    uint8_t byte = Payload()[i];
+intptr_t CompressedStackMaps::Hashcode() const {
+  uint32_t hash = payload_size();
+  for (uintptr_t i = 0; i < payload_size(); i++) {
+    uint8_t byte = PayloadByte(i);
     hash = CombineHashes(hash, byte);
   }
   return FinalizeHash(hash, kHashBits);
 }
 
 RawCompressedStackMaps* CompressedStackMaps::New(
-    const GrowableArray<uint8_t>& payload) {
+    const GrowableArray<uint8_t>& payload,
+    RawCompressedStackMaps::Kind kind) {
   ASSERT(Object::compressed_stackmaps_class() != Class::null());
   auto& result = CompressedStackMaps::Handle();
 
   const uintptr_t payload_size = payload.length();
-  if (payload_size > kMaxInt32) {
+  if (!RawCompressedStackMaps::SizeField::is_valid(payload_size)) {
     FATAL1(
         "Fatal error in CompressedStackMaps::New: "
         "invalid payload size %" Pu "\n",
@@ -12949,7 +12936,7 @@
         CompressedStackMaps::InstanceSize(payload_size), Heap::kOld);
     NoSafepointScope no_safepoint;
     result ^= raw;
-    result.set_payload_size(payload_size);
+    result.set_payload_size(payload_size, kind);
   }
   result.SetPayload(payload);
 
@@ -12958,19 +12945,24 @@
 
 void CompressedStackMaps::SetPayload(
     const GrowableArray<uint8_t>& payload) const {
-  auto const array_length = payload.length();
+  const uintptr_t array_length = payload.length();
   ASSERT(array_length <= payload_size());
 
   NoSafepointScope no_safepoint;
   uint8_t* payload_start = UnsafeMutableNonPointer(raw_ptr()->data());
-  for (intptr_t i = 0; i < array_length; i++) {
+  for (uintptr_t i = 0; i < array_length; i++) {
     payload_start[i] = payload.At(i);
   }
 }
 
 const char* CompressedStackMaps::ToCString() const {
-  ZoneTextBuffer b(Thread::Current()->zone(), 100);
-  CompressedStackMapsIterator it(*this);
+  ASSERT(!IsGlobalTable());
+  auto const t = Thread::Current();
+  auto zone = t->zone();
+  ZoneTextBuffer b(zone, 100);
+  const auto& global_table = CompressedStackMaps::Handle(
+      zone, t->isolate()->object_store()->canonicalized_stack_map_entries());
+  CompressedStackMapsIterator it(*this, global_table);
   bool first_entry = true;
   while (it.MoveNext()) {
     if (first_entry) {
@@ -12979,7 +12971,7 @@
       b.AddString("\n");
     }
     b.Printf("0x%08x: ", it.pc_offset());
-    for (intptr_t i = 0, n = it.length(); i < n; i++) {
+    for (intptr_t i = 0, n = it.Length(); i < n; i++) {
       b.AddString(it.IsObject(i) ? "1" : "0");
     }
   }
@@ -13015,25 +13007,28 @@
   const RawLocalVarDescriptors::VarInfoKind kind = info.kind();
   const int32_t index = info.index();
   if (kind == RawLocalVarDescriptors::kContextLevel) {
-    return Utils::SNPrint(buffer, len, "%2" Pd
-                                       " %-13s level=%-3d"
-                                       " begin=%-3d end=%d\n",
+    return Utils::SNPrint(buffer, len,
+                          "%2" Pd
+                          " %-13s level=%-3d"
+                          " begin=%-3d end=%d\n",
                           i, LocalVarDescriptors::KindToCString(kind), index,
                           static_cast<int>(info.begin_pos.value()),
                           static_cast<int>(info.end_pos.value()));
   } else if (kind == RawLocalVarDescriptors::kContextVar) {
     return Utils::SNPrint(
-        buffer, len, "%2" Pd
-                     " %-13s level=%-3d index=%-3d"
-                     " begin=%-3d end=%-3d name=%s\n",
+        buffer, len,
+        "%2" Pd
+        " %-13s level=%-3d index=%-3d"
+        " begin=%-3d end=%-3d name=%s\n",
         i, LocalVarDescriptors::KindToCString(kind), info.scope_id, index,
         static_cast<int>(info.begin_pos.Pos()),
         static_cast<int>(info.end_pos.Pos()), var_name.ToCString());
   } else {
     return Utils::SNPrint(
-        buffer, len, "%2" Pd
-                     " %-13s scope=%-3d index=%-3d"
-                     " begin=%-3d end=%-3d name=%s\n",
+        buffer, len,
+        "%2" Pd
+        " %-13s scope=%-3d index=%-3d"
+        " begin=%-3d end=%-3d name=%s\n",
         i, LocalVarDescriptors::KindToCString(kind), info.scope_id, index,
         static_cast<int>(info.begin_pos.Pos()),
         static_cast<int>(info.end_pos.Pos()), var_name.ToCString());
@@ -14552,13 +14547,28 @@
   StorePointer(&raw_ptr()->compressed_stackmaps_, maps.raw());
 }
 
-#if !defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_PRECOMPILER)
-void Code::set_variables(const Smi& smi) const {
-  StorePointer(&raw_ptr()->catch_entry_.variables_, smi.raw());
+#if !defined(DART_PRECOMPILED_RUNTIME)
+intptr_t Code::num_variables() const {
+  ASSERT(!FLAG_precompiled_mode);
+  return Smi::Value(Smi::RawCast(raw_ptr()->catch_entry_));
 }
-#else
+void Code::set_num_variables(intptr_t num_variables) const {
+  ASSERT(!FLAG_precompiled_mode);
+  // Object::RawCast is needed for StorePointer template argument resolution.
+  StorePointer(&raw_ptr()->catch_entry_,
+               Object::RawCast(Smi::New(num_variables)));
+}
+#endif
+
+#if defined(DART_PRECOMPILED_RUNTIME) || defined(DART_PRECOMPILER)
+RawTypedData* Code::catch_entry_moves_maps() const {
+  ASSERT(FLAG_precompiled_mode);
+  return TypedData::RawCast(raw_ptr()->catch_entry_);
+}
 void Code::set_catch_entry_moves_maps(const TypedData& maps) const {
-  StorePointer(&raw_ptr()->catch_entry_.catch_entry_moves_maps_, maps.raw());
+  ASSERT(FLAG_precompiled_mode);
+  // Object::RawCast is needed for StorePointer template argument resolution.
+  StorePointer(&raw_ptr()->catch_entry_, Object::RawCast(maps.raw()));
 }
 #endif
 
@@ -15191,6 +15201,18 @@
   StoreNonPointer(&raw_ptr()->unchecked_entry_point_, raw_ptr()->entry_point_);
 }
 
+void Code::InitializeCachedEntryPointsFrom(RawCode* code,
+                                           RawInstructions* instructions) {
+  NoSafepointScope _;
+  code->ptr()->entry_point_ = Instructions::EntryPoint(instructions);
+  code->ptr()->monomorphic_entry_point_ =
+      Instructions::MonomorphicEntryPoint(instructions);
+  code->ptr()->unchecked_entry_point_ =
+      Instructions::UncheckedEntryPoint(instructions);
+  code->ptr()->monomorphic_unchecked_entry_point_ =
+      Instructions::MonomorphicUncheckedEntryPoint(instructions);
+}
+
 void Code::SetActiveInstructions(const Instructions& instructions) const {
 #if defined(DART_PRECOMPILED_RUNTIME)
   UNREACHABLE();
@@ -15199,15 +15221,7 @@
   // RawInstructions are never allocated in New space and hence a
   // store buffer update is not needed here.
   StorePointer(&raw_ptr()->active_instructions_, instructions.raw());
-  StoreNonPointer(&raw_ptr()->entry_point_,
-                  Instructions::EntryPoint(instructions.raw()));
-  StoreNonPointer(&raw_ptr()->monomorphic_entry_point_,
-                  Instructions::MonomorphicEntryPoint(instructions.raw()));
-  StoreNonPointer(&raw_ptr()->unchecked_entry_point_,
-                  Instructions::UncheckedEntryPoint(instructions.raw()));
-  StoreNonPointer(
-      &raw_ptr()->monomorphic_unchecked_entry_point_,
-      Instructions::MonomorphicUncheckedEntryPoint(instructions.raw()));
+  Code::InitializeCachedEntryPointsFrom(raw(), instructions.raw());
 #endif
 }
 
@@ -15253,7 +15267,7 @@
   reader.DumpInlineIntervals(PayloadStart());
 }
 
-void Code::DumpSourcePositions() const {
+void Code::DumpSourcePositions(bool relative_addresses) const {
   const CodeSourceMap& map = CodeSourceMap::Handle(code_source_map());
   if (map.IsNull()) {
     // Stub code.
@@ -15262,7 +15276,7 @@
   const Array& id_map = Array::Handle(inlined_id_to_function());
   const Function& root = Function::Handle(function());
   CodeSourceMapReader reader(map, id_map, root);
-  reader.DumpSourcePositions(PayloadStart());
+  reader.DumpSourcePositions(relative_addresses ? 0 : PayloadStart());
 }
 
 bool Code::VerifyBSSRelocations() const {
@@ -16308,7 +16322,7 @@
   const Array& args = Array::Handle(zone, Array::New(kNumArgs));
   args.SetAt(0, *this);
   const Array& args_descriptor = Array::Handle(
-      zone, ArgumentsDescriptor::New(kTypeArgsLen, args.Length()));
+      zone, ArgumentsDescriptor::New(kTypeArgsLen, args.Length(), Heap::kNew));
 
   return InvokeInstanceFunction(*this, function, internal_getter_name, args,
                                 args_descriptor, respect_reflectable,
@@ -16354,7 +16368,7 @@
   args.SetAt(0, *this);
   args.SetAt(1, value);
   const Array& args_descriptor = Array::Handle(
-      zone, ArgumentsDescriptor::New(kTypeArgsLen, args.Length()));
+      zone, ArgumentsDescriptor::New(kTypeArgsLen, args.Length(), Heap::kNew));
 
   return InvokeInstanceFunction(*this, setter, internal_setter_name, args,
                                 args_descriptor, respect_reflectable,
@@ -16379,8 +16393,9 @@
 
   // TODO(regis): Support invocation of generic functions with type arguments.
   const int kTypeArgsLen = 0;
-  const Array& args_descriptor = Array::Handle(
-      zone, ArgumentsDescriptor::New(kTypeArgsLen, args.Length(), arg_names));
+  const Array& args_descriptor =
+      Array::Handle(zone, ArgumentsDescriptor::New(kTypeArgsLen, args.Length(),
+                                                   arg_names, Heap::kNew));
 
   TypeArguments& type_args = TypeArguments::Handle(zone);
   if (klass.NumTypeArguments() > 0) {
@@ -16402,7 +16417,8 @@
       const Array& getter_args = Array::Handle(zone, Array::New(kNumArgs));
       getter_args.SetAt(0, *this);
       const Array& getter_args_descriptor = Array::Handle(
-          zone, ArgumentsDescriptor::New(kTypeArgsLen, getter_args.Length()));
+          zone, ArgumentsDescriptor::New(kTypeArgsLen, getter_args.Length(),
+                                         Heap::kNew));
       const Object& getter_result = Object::Handle(
           zone, InvokeInstanceFunction(*this, function, getter_name,
                                        getter_args, getter_args_descriptor,
@@ -16656,7 +16672,10 @@
     if (cls.NumTypeArguments() > 0) {
       type_arguments = GetTypeArguments();
     }
-    type = Type::New(cls, type_arguments, TokenPosition::kNoSource, space);
+    // TODO(regis): The runtime type of a non-null instance should be
+    // non-nullable instead of legacy. Revisit.
+    type = Type::New(cls, type_arguments, TokenPosition::kNoSource,
+                     Nullability::kLegacy, space);
     type.SetIsFinalized();
     type ^= type.Canonicalize();
   }
@@ -16683,12 +16702,16 @@
 }
 
 bool Instance::IsInstanceOf(
+    NNBDMode mode,
     const AbstractType& other,
     const TypeArguments& other_instantiator_type_arguments,
     const TypeArguments& other_function_type_arguments) const {
   ASSERT(other.IsFinalized());
   ASSERT(!other.IsDynamicType());
   ASSERT(!other.IsTypeRef());  // Must be dereferenced at compile time.
+  if (mode != NNBDMode::kLegacy) {
+    UNIMPLEMENTED();
+  }
   if (other.IsVoidType()) {
     return true;
   }
@@ -16703,8 +16726,8 @@
     AbstractType& instantiated_other = AbstractType::Handle(zone, other.raw());
     if (!other.IsInstantiated()) {
       instantiated_other = other.InstantiateFrom(
-          other_instantiator_type_arguments, other_function_type_arguments,
-          kAllFree, NULL, Heap::kOld);
+          mode, other_instantiator_type_arguments,
+          other_function_type_arguments, kAllFree, NULL, Heap::kOld);
       if (instantiated_other.IsTypeRef()) {
         instantiated_other = TypeRef::Cast(instantiated_other).type();
       }
@@ -16713,7 +16736,7 @@
         return true;
       }
     }
-    if (IsFutureOrInstanceOf(zone, instantiated_other)) {
+    if (IsFutureOrInstanceOf(zone, mode, instantiated_other)) {
       return true;
     }
     if (!instantiated_other.IsFunctionType()) {
@@ -16723,7 +16746,7 @@
         Function::Handle(zone, Type::Cast(instantiated_other).signature());
     const Function& sig_fun =
         Function::Handle(Closure::Cast(*this).GetInstantiatedSignature(zone));
-    return sig_fun.IsSubtypeOf(other_signature, Heap::kOld);
+    return sig_fun.IsSubtypeOf(mode, other_signature, Heap::kOld);
   }
   TypeArguments& type_arguments = TypeArguments::Handle(zone);
   if (cls.NumTypeArguments() > 0) {
@@ -16745,7 +16768,7 @@
   AbstractType& instantiated_other = AbstractType::Handle(zone, other.raw());
   if (!other.IsInstantiated()) {
     instantiated_other = other.InstantiateFrom(
-        other_instantiator_type_arguments, other_function_type_arguments,
+        mode, other_instantiator_type_arguments, other_function_type_arguments,
         kAllFree, NULL, Heap::kOld);
     if (instantiated_other.IsTypeRef()) {
       instantiated_other = TypeRef::Cast(instantiated_other).type();
@@ -16763,16 +16786,17 @@
     ASSERT(cls.IsNullClass());
     // As of Dart 2.0, the null instance and Null type are handled differently.
     // We already checked other for dynamic and void.
-    if (IsFutureOrInstanceOf(zone, instantiated_other)) {
+    if (IsFutureOrInstanceOf(zone, mode, instantiated_other)) {
       return true;
     }
     return other_class.IsNullClass() || other_class.IsObjectClass();
   }
-  return Class::IsSubtypeOf(cls, type_arguments, other_class,
+  return Class::IsSubtypeOf(mode, cls, type_arguments, other_class,
                             other_type_arguments, Heap::kOld);
 }
 
 bool Instance::IsFutureOrInstanceOf(Zone* zone,
+                                    NNBDMode mode,
                                     const AbstractType& other) const {
   if (other.IsType() &&
       Class::Handle(zone, other.type_class()).IsFutureOrClass()) {
@@ -16792,13 +16816,13 @@
       if (!type_arguments.IsNull()) {
         const AbstractType& type_arg =
             AbstractType::Handle(zone, type_arguments.TypeAt(0));
-        if (type_arg.IsSubtypeOf(other_type_arg, Heap::kOld)) {
+        if (type_arg.IsSubtypeOf(mode, other_type_arg, Heap::kOld)) {
           return true;
         }
       }
     }
     // Retry the IsInstanceOf function after unwrapping type arg of FutureOr.
-    if (IsInstanceOf(other_type_arg, Object::null_type_arguments(),
+    if (IsInstanceOf(mode, other_type_arg, Object::null_type_arguments(),
                      Object::null_type_arguments())) {
       return true;
     }
@@ -16896,6 +16920,14 @@
   return reinterpret_cast<RawInstance*>(raw);
 }
 
+RawInstance* Instance::NewFromCidAndSize(SharedClassTable* shared_class_table,
+                                         classid_t cid) {
+  const intptr_t instance_size = shared_class_table->SizeAt(cid);
+  ASSERT(instance_size > 0);
+  RawObject* raw = Object::Allocate(cid, instance_size, Heap::kNew);
+  return reinterpret_cast<RawInstance*>(raw);
+}
+
 bool Instance::IsValidFieldOffset(intptr_t offset) const {
   Thread* thread = Thread::Current();
   REUSABLE_CLASS_HANDLESCOPE(thread);
@@ -17010,7 +17042,62 @@
 Nullability AbstractType::nullability() const {
   // AbstractType is an abstract class.
   UNREACHABLE();
-  return kNullable;
+  return Nullability::kNullable;
+}
+
+RawAbstractType* AbstractType::CheckInstantiatedNullability(
+    NNBDMode mode,
+    const TypeParameter& type_param,
+    Heap::Space space) const {
+  Nullability result_nullability;
+  const Nullability arg_nullability = nullability();
+  if (mode == NNBDMode::kOptedIn) {
+    const Nullability var_nullability = type_param.nullability();
+    // Adjust nullability of result 'arg' instantiated from 'var' (x throws).
+    // arg/var ! ? * %
+    //  !      ! ? * !
+    //  ?      x ? ? ?
+    //  *      * ? * *
+    //  %      x ? * %
+    if (var_nullability == Nullability::kNonNullable &&
+        (arg_nullability == Nullability::kNullable ||
+         arg_nullability == Nullability::kUndetermined)) {
+      const String& error =
+          String::Handle(String::New("non-nullable type parameter"));
+      Exceptions::CreateAndThrowTypeError(TokenPosition::kNoSource, *this,
+                                          type_param, error);
+      UNREACHABLE();
+    }
+    if (var_nullability == Nullability::kNullable ||
+        arg_nullability == Nullability::kNullable) {
+      result_nullability = Nullability::kNullable;
+    } else if (var_nullability == Nullability::kLegacy ||
+               arg_nullability == Nullability::kLegacy) {
+      result_nullability = Nullability::kLegacy;
+    } else {
+      result_nullability = arg_nullability;
+    }
+  } else {
+    const classid_t cid = type_class_id();
+    if (cid == kDynamicCid || cid == kVoidCid || cid == kNeverCid ||
+        cid == kNullCid) {
+      // Do not force result to kLegacy.
+      return raw();
+    }
+    result_nullability = Nullability::kLegacy;
+  }
+  if (arg_nullability == result_nullability) {
+    return raw();
+  }
+  if (IsType()) {
+    return Type::Cast(*this).ToNullability(result_nullability, space);
+  }
+  if (IsTypeParameter()) {
+    return TypeParameter::Cast(*this).ToNullability(result_nullability, space);
+  }
+  // TODO(regis): TypeRefs are problematic, since changing the nullability of
+  // a type by cloning it may break the graph of a recursive type.
+  UNREACHABLE();
 }
 
 bool AbstractType::IsInstantiated(Genericity genericity,
@@ -17056,6 +17143,7 @@
 }
 
 RawAbstractType* AbstractType::InstantiateFrom(
+    NNBDMode mode,
     const TypeArguments& instantiator_type_arguments,
     const TypeArguments& function_type_arguments,
     intptr_t num_free_fun_type_params,
@@ -17192,8 +17280,21 @@
   return Symbols::FromConcatAll(thread, pieces);
 }
 
-// Keep in sync with Nullability enum in runtime/vm/object.h.
-static const char* nullability_suffix[4] = {"%", "?", "", "*"};
+static const String& NullabilitySuffix(Nullability value) {
+  // Keep in sync with Nullability enum in runtime/vm/object.h.
+  switch (value) {
+    case Nullability::kUndetermined:
+      return Symbols::Percent();
+    case Nullability::kNullable:
+      return Symbols::QuestionMark();
+    case Nullability::kNonNullable:
+      return Symbols::Empty();
+    case Nullability::kLegacy:
+      return Symbols::Star();
+    default:
+      UNREACHABLE();
+  }
+}
 
 RawString* AbstractType::BuildName(NameVisibility name_visibility) const {
   ASSERT(name_visibility != kScrubbedName);
@@ -17203,7 +17304,7 @@
     if (FLAG_show_nullability) {
       return Symbols::FromConcat(
           thread, String::Handle(zone, TypeParameter::Cast(*this).name()),
-          String::Handle(zone, String::New(nullability_suffix[nullability()])));
+          NullabilitySuffix(nullability()));
     }
     return TypeParameter::Cast(*this).name();
   }
@@ -17221,8 +17322,7 @@
         return Symbols::FromConcat(
             thread,
             String::Handle(zone, signature_function.UserVisibleSignature()),
-            String::Handle(zone,
-                           String::New(nullability_suffix[nullability()])));
+            NullabilitySuffix(nullability()));
       }
       return signature_function.UserVisibleSignature();
     }
@@ -17232,10 +17332,9 @@
     if (!IsFinalized() || IsBeingFinalized()) {
       // TODO(regis): Check if this is dead code.
       if (FLAG_show_nullability) {
-        return Symbols::FromConcat(
-            thread, String::Handle(zone, class_name.raw()),
-            String::Handle(zone,
-                           String::New(nullability_suffix[nullability()])));
+        return Symbols::FromConcat(thread,
+                                   String::Handle(zone, class_name.raw()),
+                                   NullabilitySuffix(nullability()));
       }
       return class_name.raw();
     }
@@ -17278,8 +17377,7 @@
     pieces.Add(args_name);
   }
   if (FLAG_show_nullability) {
-    pieces.Add(
-        String::Handle(zone, String::New(nullability_suffix[nullability()])));
+    pieces.Add(NullabilitySuffix(nullability()));
   }
   // The name is only used for type checking and debugging purposes.
   // Unless profiling data shows otherwise, it is not worth caching the name in
@@ -17296,29 +17394,13 @@
   return IsTypeRef() && (TypeRef::Cast(*this).type() == AbstractType::null());
 }
 
-bool AbstractType::IsDynamicType() const {
-  return type_class_id() == kDynamicCid;
-}
-
-bool AbstractType::IsVoidType() const {
-  return type_class_id() == kVoidCid;
-}
-
-bool AbstractType::IsNeverType() const {
-  return type_class_id() == kNeverCid;
-}
-
-bool AbstractType::IsObjectType() const {
-  return type_class_id() == kInstanceCid;
-}
-
-bool AbstractType::IsTopType(NNBDMode mode) const {
+// TODO(regis): IsTopType is not yet nullability aware.
+bool AbstractType::IsTopType() const {
   const classid_t cid = type_class_id();
   if (cid == kIllegalCid) {
     return false;
   }
-  if (cid == kDynamicCid || cid == kVoidCid ||
-      (cid == kInstanceCid && (mode != kStrong || IsNullable()))) {
+  if (cid == kDynamicCid || cid == kVoidCid || cid == kInstanceCid) {
     return true;
   }
   // FutureOr<T> where T is a top type behaves as a top type.
@@ -17332,21 +17414,13 @@
         TypeArguments::Handle(zone, arguments());
     const AbstractType& type_arg =
         AbstractType::Handle(zone, type_arguments.TypeAt(0));
-    if (type_arg.IsTopType(mode)) {
+    if (type_arg.IsTopType()) {
       return true;
     }
   }
   return false;
 }
 
-bool AbstractType::IsNullType() const {
-  return type_class_id() == kNullCid;
-}
-
-bool AbstractType::IsBoolType() const {
-  return type_class_id() == kBoolCid;
-}
-
 bool AbstractType::IsIntType() const {
   return HasTypeClass() &&
          (type_class() == Type::Handle(Type::IntType()).type_class());
@@ -17375,14 +17449,6 @@
          (type_class() == Type::Handle(Type::Int32x4()).type_class());
 }
 
-bool AbstractType::IsNumberType() const {
-  return type_class_id() == kNumberCid;
-}
-
-bool AbstractType::IsSmiType() const {
-  return type_class_id() == kSmiCid;
-}
-
 bool AbstractType::IsStringType() const {
   return HasTypeClass() &&
          (type_class() == Type::Handle(Type::StringType()).type_class());
@@ -17403,22 +17469,23 @@
   return HasTypeClass() && type_class_id() == kFfiPointerCid;
 }
 
-bool AbstractType::IsSubtypeOf(const AbstractType& other,
+bool AbstractType::IsSubtypeOf(NNBDMode mode,
+                               const AbstractType& other,
                                Heap::Space space) const {
   ASSERT(IsFinalized());
   ASSERT(other.IsFinalized());
-  // Any type is a subtype of (and is more specific than) Object and dynamic.
-  // As of Dart 2.0, the Null type is a subtype of (and is more specific than)
-  // any type.
-  if (other.IsTopType() || IsNullType()) {
+  if (FLAG_strong_non_nullable_type_checks) {
+    UNIMPLEMENTED();
+  }
+  if (other.IsTopType() || IsNullType() || IsNeverType()) {
     return true;
   }
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
   // Type parameters cannot be handled by Class::IsSubtypeOf().
   // When comparing two uninstantiated function types, one returning type
-  // parameter K, the other returning type parameter V, we cannot assume that K
-  // is a subtype of V, or vice versa. We only return true if K equals V, as
+  // parameter K, the other returning type parameter V, we cannot assume that
+  // K is a subtype of V, or vice versa. We only return true if K equals V, as
   // defined by TypeParameter::Equals.
   // The same rule applies when checking the upper bound of a still
   // uninstantiated type at compile time. Returning false will defer the test
@@ -17437,11 +17504,11 @@
       if (type_param.IsFunctionTypeParameter() &&
           other_type_param.IsFunctionTypeParameter() &&
           type_param.IsFinalized() && other_type_param.IsFinalized()) {
-        // To be compatible, the function type parameters should be declared at
-        // the same position in the generic function. Their index therefore
+        // To be compatible, the function type parameters should be declared
+        // at the same position in the generic function. Their index therefore
         // needs adjustement before comparison.
-        // Example: 'foo<F>(bar<B>(B b)) { }' and 'baz<Z>(Z z) { }', baz can be
-        // assigned to bar, although B has index 1 and Z index 0.
+        // Example: 'foo<F>(bar<B>(B b)) { }' and 'baz<Z>(Z z) { }', baz can
+        // be assigned to bar, although B has index 1 and Z index 0.
         const Function& sig_fun =
             Function::Handle(zone, type_param.parameterized_function());
         const Function& other_sig_fun =
@@ -17455,22 +17522,22 @@
       }
     }
     const AbstractType& bound = AbstractType::Handle(zone, type_param.bound());
-    // We may be checking bounds at finalization time and can encounter
-    // a still unfinalized bound. Finalizing the bound here may lead to cycles.
+    // We may be checking bounds at finalization time and can encounter a
+    // still unfinalized bound. Finalizing the bound here may lead to cycles.
     if (!bound.IsFinalized()) {
-      return false;  // TODO(regis): Return "maybe after instantiation".
+      return false;
     }
-    if (bound.IsSubtypeOf(other, space)) {
+    if (bound.IsSubtypeOf(mode, other, space)) {
       return true;
     }
     // Apply additional subtyping rules if 'other' is 'FutureOr'.
-    if (IsSubtypeOfFutureOr(zone, other, space)) {
+    if (IsSubtypeOfFutureOr(zone, mode, other, space)) {
       return true;
     }
-    return false;  // TODO(regis): We should return "maybe after instantiation".
+    return false;
   }
   if (other.IsTypeParameter()) {
-    return false;  // TODO(regis): We should return "maybe after instantiation".
+    return false;
   }
   const Class& type_cls = Class::Handle(zone, type_class());
   const Class& other_type_cls = Class::Handle(zone, other.type_class());
@@ -17486,14 +17553,14 @@
       // Check for two function types.
       const Function& fun =
           Function::Handle(zone, Type::Cast(*this).signature());
-      return fun.IsSubtypeOf(other_fun, space);
+      return fun.IsSubtypeOf(mode, other_fun, space);
     }
     if (other.IsFunctionType() && !other_type_cls.IsTypedefClass()) {
       // [this] is not a function type. Therefore, non-function type [this]
       // cannot be a subtype of function type [other], unless [other] is not
       // only a function type, but also a named typedef.
-      // Indeed a typedef also behaves as a regular class-based type (with type
-      // arguments when generic).
+      // Indeed a typedef also behaves as a regular class-based type (with
+      // type arguments when generic).
       // This check is needed to avoid falling through to class-based type
       // tests, which yield incorrect result if [this] = _Closure class,
       // and [other] is a function type, because class of a function type is
@@ -17503,17 +17570,18 @@
   }
   if (IsFunctionType()) {
     // Apply additional subtyping rules if 'other' is 'FutureOr'.
-    if (IsSubtypeOfFutureOr(zone, other, space)) {
+    if (IsSubtypeOfFutureOr(zone, mode, other, space)) {
       return true;
     }
     return false;
   }
   return Class::IsSubtypeOf(
-      type_cls, TypeArguments::Handle(zone, arguments()), other_type_cls,
+      mode, type_cls, TypeArguments::Handle(zone, arguments()), other_type_cls,
       TypeArguments::Handle(zone, other.arguments()), space);
 }
 
 bool AbstractType::IsSubtypeOfFutureOr(Zone* zone,
+                                       NNBDMode mode,
                                        const AbstractType& other,
                                        Heap::Space space) const {
   if (other.IsType() &&
@@ -17533,7 +17601,7 @@
       return true;
     }
     // Retry the IsSubtypeOf check after unwrapping type arg of FutureOr.
-    if (IsSubtypeOf(other_type_arg, space)) {
+    if (IsSubtypeOf(mode, other_type_arg, space)) {
       return true;
     }
   }
@@ -17640,20 +17708,35 @@
   return Isolate::Current()->object_store()->type_type();
 }
 
-RawType* Type::NewNonParameterizedType(const Class& type_class) {
+RawType* Type::NewNonParameterizedType(const Class& type_class,
+                                       Nullability nullability) {
   ASSERT(type_class.NumTypeArguments() == 0);
+  if (type_class.IsNullClass()) {
+    // Ignore requested nullability (e.g. by mirrors).
+    return Type::NullType();
+  }
+  if (type_class.IsDynamicClass()) {
+    return Type::DynamicType();
+  }
+  if (type_class.IsVoidClass()) {
+    return Type::VoidType();
+  }
+  if (type_class.IsNeverClass()) {
+    return Type::NeverType();
+  }
   // It is too early to use the class finalizer, as type_class may not be named
   // yet, so do not call DeclarationType().
   Type& type = Type::Handle(type_class.declaration_type());
   if (type.IsNull()) {
     type = Type::New(Class::Handle(type_class.raw()),
-                     Object::null_type_arguments(), TokenPosition::kNoSource);
+                     Object::null_type_arguments(), TokenPosition::kNoSource,
+                     Nullability::kLegacy);
     type.SetIsFinalized();
     type ^= type.Canonicalize();
     type_class.set_declaration_type(type);
   }
   ASSERT(type.IsFinalized());
-  return type.raw();
+  return type.ToNullability(nullability, Heap::kOld);
 }
 
 void Type::SetIsFinalized() const {
@@ -17757,6 +17840,7 @@
 }
 
 RawAbstractType* Type::InstantiateFrom(
+    NNBDMode mode,
     const TypeArguments& instantiator_type_arguments,
     const TypeArguments& function_type_arguments,
     intptr_t num_free_fun_type_params,
@@ -17779,7 +17863,7 @@
     // parameterization of a generic typedef. They are otherwise ignored.
     ASSERT(type_arguments.Length() == cls.NumTypeArguments());
     type_arguments = type_arguments.InstantiateFrom(
-        instantiator_type_arguments, function_type_arguments,
+        mode, instantiator_type_arguments, function_type_arguments,
         num_free_fun_type_params, instantiation_trail, space);
     // A returned empty_type_arguments indicates a failed instantiation in dead
     // code that must be propagated up to the caller, the optimizing compiler.
@@ -17789,8 +17873,8 @@
   }
   // This uninstantiated type is not modified, as it can be instantiated
   // with different instantiators. Allocate a new instantiated version of it.
-  const Type& instantiated_type =
-      Type::Handle(zone, Type::New(cls, type_arguments, token_pos(), space));
+  const Type& instantiated_type = Type::Handle(
+      zone, Type::New(cls, type_arguments, token_pos(), nullability(), space));
   // For a function type, possibly instantiate and set its signature.
   if (!sig_fun.IsNull()) {
     // If we are finalizing a typedef, do not yet instantiate its signature,
@@ -17801,7 +17885,7 @@
       // A generic typedef may actually declare an instantiated signature.
       if (!sig_fun.HasInstantiatedSignature(kAny, num_free_fun_type_params)) {
         sig_fun = sig_fun.InstantiateSignatureFrom(
-            instantiator_type_arguments, function_type_arguments,
+            mode, instantiator_type_arguments, function_type_arguments,
             num_free_fun_type_params, space);
         // A returned null signature indicates a failed instantiation in dead
         // code that must be propagated up to the caller, the optimizing
@@ -17991,17 +18075,18 @@
   Zone* zone = thread->zone();
   Isolate* isolate = thread->isolate();
 
-  if ((type_class_id() == kVoidCid) && (isolate != Dart::vm_isolate())) {
-    ASSERT(Object::void_type().IsCanonical());
-    return Object::void_type().raw();
-  }
-
-  if ((type_class_id() == kDynamicCid) && (isolate != Dart::vm_isolate())) {
+  const classid_t cid = type_class_id();
+  if (cid == kDynamicCid) {
     ASSERT(Object::dynamic_type().IsCanonical());
     return Object::dynamic_type().raw();
   }
 
-  if ((type_class_id() == kNeverCid) && (isolate != Dart::vm_isolate())) {
+  if (cid == kVoidCid) {
+    ASSERT(Object::void_type().IsCanonical());
+    return Object::void_type().raw();
+  }
+
+  if (cid == kNeverCid) {
     ASSERT(Object::never_type().IsCanonical());
     return Object::never_type().raw();
   }
@@ -18009,8 +18094,8 @@
   const Class& cls = Class::Handle(zone, type_class());
 
   // Fast canonical lookup/registry for simple types.
-  if (IsNullType() || (IsLegacy() && !cls.IsGeneric() &&
-                       !cls.IsClosureClass() && !cls.IsTypedefClass())) {
+  if ((IsNullType() || IsLegacy()) && !cls.IsGeneric() &&
+      !cls.IsClosureClass() && !cls.IsTypedefClass()) {
     ASSERT(!IsFunctionType());
     ASSERT(!IsNullType() || IsNullable());
     Type& type = Type::Handle(zone, cls.declaration_type());
@@ -18127,20 +18212,27 @@
   if (IsRecursive()) {
     return true;
   }
-  if (type_class_id() == kDynamicCid) {
+  const classid_t cid = type_class_id();
+  if (cid == kDynamicCid) {
     return (raw() == Object::dynamic_type().raw());
   }
+  if (cid == kVoidCid) {
+    return (raw() == Object::void_type().raw());
+  }
+  if (cid == kNeverCid) {
+    return (raw() == Object::never_type().raw());
+  }
   Zone* zone = thread->zone();
   Isolate* isolate = thread->isolate();
   AbstractType& type = Type::Handle(zone);
   const Class& cls = Class::Handle(zone, type_class());
 
   // Fast canonical lookup/registry for simple types.
-  if (IsNullType() || (IsLegacy() && !cls.IsGeneric() &&
-                       !cls.IsClosureClass() && !cls.IsTypedefClass())) {
+  if ((IsNullType() || IsLegacy()) && !cls.IsGeneric() &&
+      !cls.IsClosureClass() && !cls.IsTypedefClass()) {
     ASSERT(!IsFunctionType());
-    ASSERT(!IsNullType() || IsNullable());
     type = cls.declaration_type();
+    ASSERT(type.IsCanonical());
     return (raw() == type.raw());
   }
 
@@ -18234,6 +18326,7 @@
 RawType* Type::New(const Class& clazz,
                    const TypeArguments& arguments,
                    TokenPosition token_pos,
+                   Nullability nullability,
                    Heap::Space space) {
   Zone* Z = Thread::Current()->zone();
   const Type& result = Type::Handle(Z, Type::New(space));
@@ -18242,11 +18335,7 @@
   result.SetHash(0);
   result.set_token_pos(token_pos);
   result.StoreNonPointer(&result.raw_ptr()->type_state_, RawType::kAllocated);
-  if (clazz.id() == kNullCid) {
-    result.set_nullability(kNullable);
-  } else {
-    result.set_nullability(kLegacy);
-  }
+  result.set_nullability(nullability);
 
   result.SetTypeTestingStub(
       Code::Handle(Z, TypeTestingStubGenerator::DefaultCodeForType(result)));
@@ -18323,6 +18412,7 @@
 }
 
 RawTypeRef* TypeRef::InstantiateFrom(
+    NNBDMode mode,
     const TypeArguments& instantiator_type_arguments,
     const TypeArguments& function_type_arguments,
     intptr_t num_free_fun_type_params,
@@ -18340,7 +18430,7 @@
   ASSERT(!ref_type.IsNull() && !ref_type.IsTypeRef());
   AbstractType& instantiated_ref_type = AbstractType::Handle();
   instantiated_ref_type = ref_type.InstantiateFrom(
-      instantiator_type_arguments, function_type_arguments,
+      mode, instantiator_type_arguments, function_type_arguments,
       num_free_fun_type_params, instantiation_trail, space);
   // A returned null type indicates a failed instantiation in dead code that
   // must be propagated up to the caller, the optimizing compiler.
@@ -18454,7 +18544,7 @@
 }
 
 void TypeParameter::set_nullability(Nullability value) const {
-  StoreNonPointer(&raw_ptr()->nullability_, value);
+  StoreNonPointer(&raw_ptr()->nullability_, static_cast<int8_t>(value));
 }
 
 RawTypeParameter* TypeParameter::ToNullability(Nullability value,
@@ -18554,6 +18644,7 @@
 }
 
 RawAbstractType* TypeParameter::InstantiateFrom(
+    NNBDMode mode,
     const TypeArguments& instantiator_type_arguments,
     const TypeArguments& function_type_arguments,
     intptr_t num_free_fun_type_params,
@@ -18568,7 +18659,9 @@
     if (function_type_arguments.IsNull()) {
       return Type::DynamicType();
     }
-    return function_type_arguments.TypeAt(index());
+    const AbstractType& result =
+        AbstractType::Handle(function_type_arguments.TypeAt(index()));
+    return result.CheckInstantiatedNullability(mode, *this, space);
   }
   ASSERT(IsClassTypeParameter());
   if (instantiator_type_arguments.IsNull()) {
@@ -18583,7 +18676,9 @@
     // (see AssertAssignableInstr::Canonicalize).
     return AbstractType::null();
   }
-  return instantiator_type_arguments.TypeAt(index());
+  const AbstractType& result =
+      AbstractType::Handle(instantiator_type_arguments.TypeAt(index()));
+  return result.CheckInstantiatedNullability(mode, *this, space);
   // There is no need to canonicalize the instantiated type parameter, since all
   // type arguments are canonicalized at type finalization time. It would be too
   // early to canonicalize the returned type argument here, since instantiation
@@ -18653,7 +18748,7 @@
   result.set_name(name);
   result.set_bound(bound);
   result.set_flags(0);
-  result.set_nullability(kLegacy);
+  result.set_nullability(Nullability::kLegacy);
   result.SetGenericCovariantImpl(is_generic_covariant_impl);
   result.SetHash(0);
   result.set_token_pos(token_pos);
@@ -21861,12 +21956,23 @@
   }
   if (num_free_params == kCurrentAndEnclosingFree ||
       !sig_fun.HasInstantiatedSignature(kAny)) {
-    return sig_fun.InstantiateSignatureFrom(inst_type_args, fn_type_args,
-                                            num_free_params, Heap::kOld);
+    // TODO(regis): Instead of NNBDMode::kLegacy, use the NNBDMode of the
+    // closure's function's owner's library.
+    return sig_fun.InstantiateSignatureFrom(NNBDMode::kLegacy, inst_type_args,
+                                            fn_type_args, num_free_params,
+                                            Heap::kOld);
   }
   return sig_fun.raw();
 }
 
+bool StackTrace::skip_sync_start_in_parent_stack() const {
+  return raw_ptr()->skip_sync_start_in_parent_stack;
+}
+
+void StackTrace::set_skip_sync_start_in_parent_stack(bool value) const {
+  StoreNonPointer(&raw_ptr()->skip_sync_start_in_parent_stack, value);
+}
+
 intptr_t StackTrace::Length() const {
   const Array& code_array = Array::Handle(raw_ptr()->code_array_);
   return code_array.Length();
@@ -21927,12 +22033,14 @@
   result.set_code_array(code_array);
   result.set_pc_offset_array(pc_offset_array);
   result.set_expand_inlined(true);  // default.
+  result.set_skip_sync_start_in_parent_stack(false);
   return result.raw();
 }
 
 RawStackTrace* StackTrace::New(const Array& code_array,
                                const Array& pc_offset_array,
                                const StackTrace& async_link,
+                               bool skip_sync_start_in_parent_stack,
                                Heap::Space space) {
   StackTrace& result = StackTrace::Handle();
   {
@@ -21945,6 +22053,7 @@
   result.set_code_array(code_array);
   result.set_pc_offset_array(pc_offset_array);
   result.set_expand_inlined(true);  // default.
+  result.set_skip_sync_start_in_parent_stack(skip_sync_start_in_parent_stack);
   return result.raw();
 }
 
@@ -22003,8 +22112,9 @@
   // Iterate through the stack frames and create C string description
   // for each frame.
   intptr_t frame_index = 0;
+  uint32_t frame_skip = 0;
   do {
-    for (intptr_t i = 0; i < stack_trace.Length(); i++) {
+    for (intptr_t i = frame_skip; i < stack_trace.Length(); i++) {
       code_object = stack_trace.CodeAtFrame(i);
       if (code_object.IsNull()) {
         // Check for a null function, which indicates a gap in a StackOverflow
@@ -22064,6 +22174,9 @@
       }
     }
     // Follow the link.
+    frame_skip = stack_trace.skip_sync_start_in_parent_stack()
+                     ? StackTrace::kSyncAsyncCroppedFrames
+                     : 0;
     stack_trace = stack_trace.async_link();
   } while (!stack_trace.IsNull());
 
@@ -22091,8 +22204,9 @@
   buffer.Printf("pid: %" Pd ", tid: %" Pd ", name %s\n", OS::ProcessId(),
                 OSThread::ThreadIdToIntPtr(thread->id()), thread->name());
   intptr_t frame_index = 0;
+  uint32_t frame_skip = 0;
   do {
-    for (intptr_t i = 0; i < stack_trace.Length(); i++) {
+    for (intptr_t i = frame_skip; i < stack_trace.Length(); i++) {
       code = stack_trace.CodeAtFrame(i);
       if (code.IsNull()) {
         // Check for a null function, which indicates a gap in a StackOverflow
@@ -22134,6 +22248,9 @@
       }
     }
     // Follow the link.
+    frame_skip = stack_trace.skip_sync_start_in_parent_stack()
+                     ? StackTrace::kSyncAsyncCroppedFrames
+                     : 0;
     stack_trace = stack_trace.async_link();
   } while (!stack_trace.IsNull());
 
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 4f9f92b..ba6dfb7 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -63,6 +63,7 @@
 class HierarchyInfo;
 class LocalScope;
 class CodeStatistics;
+class IsolateGroupReloadContext;
 
 #define REUSABLE_FORWARD_DECLARATION(name) class Reusable##name##HandleScope;
 REUSABLE_HANDLE_LIST(REUSABLE_FORWARD_DECLARATION)
@@ -837,6 +838,21 @@
 // The third string in the triplet is "print" if the triplet should be printed.
 typedef ZoneGrowableHandlePtrArray<const String> URIs;
 
+// Keep in sync with package:kernel/lib/ast.dart
+enum class Nullability {
+  kUndetermined = 0,
+  kNullable = 1,
+  kNonNullable = 2,
+  kLegacy = 3,
+};
+
+// NNBD modes reflecting the status of the library performing type reification
+// or subtype tests. Weak or strong mode is independent of this mode.
+enum class NNBDMode {
+  kLegacy,
+  kOptedIn,
+};
+
 class Class : public Object {
  public:
   enum InvocationDispatcherEntry {
@@ -935,7 +951,12 @@
   // class B<T, S>
   // class C<R> extends B<R, int>
   // C.DeclarationType() --> C [R, int, R]
-  RawType* DeclarationType() const;
+  // The declaration type is legacy by default, but another nullability
+  // variant may be requested. The first requested type gets cached in the class
+  // and subsequent nullability variants get cached in the object store.
+  // TODO(regis): Is this caching still useful or should we eliminate it?
+  RawType* DeclarationType(
+      Nullability nullability = Nullability::kLegacy) const;
 
   static intptr_t declaration_type_offset() {
     return OFFSET_OF(RawClass, declaration_type_);
@@ -1075,7 +1096,8 @@
 
   // Returns true if the type specified by cls and type_arguments is a
   // subtype of the type specified by other class and other_type_arguments.
-  static bool IsSubtypeOf(const Class& cls,
+  static bool IsSubtypeOf(NNBDMode mode,
+                          const Class& cls,
                           const TypeArguments& type_arguments,
                           const Class& other,
                           const TypeArguments& other_type_arguments,
@@ -1085,6 +1107,7 @@
   // subtype of FutureOr<T> specified by other class and other_type_arguments.
   // Returns false if other class is not a FutureOr.
   static bool IsSubtypeOfFutureOr(Zone* zone,
+                                  NNBDMode mode,
                                   const Class& cls,
                                   const TypeArguments& type_arguments,
                                   const Class& other,
@@ -2130,21 +2153,6 @@
   friend class SnapshotWriter;
 };
 
-// Keep in sync with package:kernel/lib/ast.dart
-enum Nullability {
-  kUndetermined = 0,
-  kNullable = 1,
-  kNonNullable = 2,
-  kLegacy = 3,
-};
-
-// Nullability aware subtype checking modes.
-enum NNBDMode {
-  kUnaware,
-  kWeak,
-  kStrong,
-};
-
 // Often used constants for number of free function type parameters.
 enum {
   kNoneFree = 0,
@@ -2185,7 +2193,8 @@
   // function type with uninstantiated type arguments 'T' and 'R' as elements of
   // its type argument vector.
   // A function type is non-nullable by default.
-  RawType* SignatureType(Nullability nullability = kNonNullable) const;
+  RawType* SignatureType(
+      Nullability nullability = Nullability::kNonNullable) const;
   RawType* ExistingSignatureType() const;
 
   // Update the signature type (with a canonical version).
@@ -2222,6 +2231,7 @@
 
   // Return a new function with instantiated result and parameter types.
   RawFunction* InstantiateSignatureFrom(
+      NNBDMode mode,
       const TypeArguments& instantiator_type_arguments,
       const TypeArguments& function_type_arguments,
       intptr_t num_free_fun_type_params,
@@ -2784,6 +2794,7 @@
   // Returns a TypeError if the provided arguments don't match the function
   // parameter types, NULL otherwise. Assumes AreValidArguments is called first.
   RawObject* DoArgumentTypesMatch(
+      NNBDMode mode,
       const Array& args,
       const ArgumentsDescriptor& arg_names,
       const TypeArguments& instantiator_type_args) const;
@@ -2791,11 +2802,13 @@
   // Returns true if the type argument count, total argument count and the names
   // of optional arguments are valid for calling this function.
   // Otherwise, it returns false and the reason (if error_message is not NULL).
-  bool AreValidArguments(intptr_t num_type_arguments,
+  bool AreValidArguments(NNBDMode mode,
+                         intptr_t num_type_arguments,
                          intptr_t num_arguments,
                          const Array& argument_names,
                          String* error_message) const;
-  bool AreValidArguments(const ArgumentsDescriptor& args_desc,
+  bool AreValidArguments(NNBDMode mode,
+                         const ArgumentsDescriptor& args_desc,
                          String* error_message) const;
 
   // Fully qualified name uniquely identifying the function under gdb and during
@@ -2808,7 +2821,9 @@
 
   // Returns true if the type of this function is a subtype of the type of
   // the other function.
-  bool IsSubtypeOf(const Function& other, Heap::Space space) const;
+  bool IsSubtypeOf(NNBDMode mode,
+                   const Function& other,
+                   Heap::Space space) const;
 
   bool IsDispatcherOrImplicitAccessor() const {
     switch (kind()) {
@@ -2909,24 +2924,24 @@
   }
 
   bool IsFfiLoad() const {
-    const auto kind = MethodRecognizer::RecognizeKind(*this);
+    const auto kind = recognized_kind();
     return MethodRecognizer::kFfiLoadInt8 <= kind &&
            kind <= MethodRecognizer::kFfiLoadPointer;
   }
 
   bool IsFfiStore() const {
-    const auto kind = MethodRecognizer::RecognizeKind(*this);
+    const auto kind = recognized_kind();
     return MethodRecognizer::kFfiStoreInt8 <= kind &&
            kind <= MethodRecognizer::kFfiStorePointer;
   }
 
   bool IsFfiFromAddress() const {
-    const auto kind = MethodRecognizer::RecognizeKind(*this);
+    const auto kind = recognized_kind();
     return kind == MethodRecognizer::kFfiFromAddress;
   }
 
   bool IsFfiGetAddress() const {
-    const auto kind = MethodRecognizer::RecognizeKind(*this);
+    const auto kind = recognized_kind();
     return kind == MethodRecognizer::kFfiGetAddress;
   }
 
@@ -3253,7 +3268,8 @@
   // Returns true if the type of the formal parameter at the given position in
   // this function is contravariant with the type of the other formal parameter
   // at the given position in the other function.
-  bool IsContravariantParameter(intptr_t parameter_position,
+  bool IsContravariantParameter(NNBDMode mode,
+                                intptr_t parameter_position,
                                 const Function& other,
                                 intptr_t other_parameter_position,
                                 Heap::Space space) const;
@@ -3818,6 +3834,13 @@
   static bool IsSetterName(const String& function_name);
   static bool IsInitName(const String& function_name);
 
+#if !defined(DART_PRECOMPILED_RUNTIME)
+  RawSubtypeTestCache* type_test_cache() const {
+    return raw_ptr()->type_test_cache_;
+  }
+  void set_type_test_cache(const SubtypeTestCache& cache) const;
+#endif
+
  private:
   static void InitializeNew(const Field& result,
                             const String& name,
@@ -3962,12 +3985,6 @@
 
   void set_debug_positions(const Array& value) const;
 
-  void set_yield_positions(const Array& value) const;
-
-  RawArray* yield_positions() const;
-
-  RawGrowableObjectArray* GetYieldPositions(const Function& function) const;
-
   RawLibrary* FindLibrary() const;
   RawString* GetLine(intptr_t line_number,
                      Heap::Space space = Heap::kNew) const;
@@ -4268,6 +4285,10 @@
     set_flags(RawLibrary::NnbdBit::update(value, raw_ptr()->flags_));
   }
 
+  NNBDMode nnbd_mode() const {
+    return is_nnbd() ? NNBDMode::kOptedIn : NNBDMode::kLegacy;
+  }
+
   RawString* PrivateName(const String& name) const;
 
   intptr_t index() const { return raw_ptr()->index_; }
@@ -5033,16 +5054,20 @@
           cur_kind_(0),
           cur_deopt_id_(0),
           cur_token_pos_(0),
-          cur_try_index_(0) {}
+          cur_try_index_(0),
+          cur_yield_index_(RawPcDescriptors::kInvalidYieldIndex) {}
 
     bool MoveNext() {
       // Moves to record that matches kind_mask_.
       while (byte_index_ < descriptors_.Length()) {
-        int32_t merged_kind_try = descriptors_.DecodeInteger(&byte_index_);
+        const int32_t kind_and_metadata =
+            descriptors_.DecodeInteger(&byte_index_);
         cur_kind_ =
-            RawPcDescriptors::MergedKindTry::DecodeKind(merged_kind_try);
-        cur_try_index_ =
-            RawPcDescriptors::MergedKindTry::DecodeTryIndex(merged_kind_try);
+            RawPcDescriptors::KindAndMetadata::DecodeKind(kind_and_metadata);
+        cur_try_index_ = RawPcDescriptors::KindAndMetadata::DecodeTryIndex(
+            kind_and_metadata);
+        cur_yield_index_ = RawPcDescriptors::KindAndMetadata::DecodeYieldIndex(
+            kind_and_metadata);
 
         cur_pc_offset_ += descriptors_.DecodeInteger(&byte_index_);
 
@@ -5062,6 +5087,7 @@
     intptr_t DeoptId() const { return cur_deopt_id_; }
     TokenPosition TokenPos() const { return TokenPosition(cur_token_pos_); }
     intptr_t TryIndex() const { return cur_try_index_; }
+    intptr_t YieldIndex() const { return cur_yield_index_; }
     RawPcDescriptors::Kind Kind() const {
       return static_cast<RawPcDescriptors::Kind>(cur_kind_);
     }
@@ -5079,7 +5105,8 @@
           cur_kind_(iter.cur_kind_),
           cur_deopt_id_(iter.cur_deopt_id_),
           cur_token_pos_(iter.cur_token_pos_),
-          cur_try_index_(iter.cur_try_index_) {}
+          cur_try_index_(iter.cur_try_index_),
+          cur_yield_index_(iter.cur_yield_index_) {}
 
     const PcDescriptors& descriptors_;
     const intptr_t kind_mask_;
@@ -5090,6 +5117,7 @@
     intptr_t cur_deopt_id_;
     intptr_t cur_token_pos_;
     intptr_t cur_try_index_;
+    intptr_t cur_yield_index_;
   };
 
   intptr_t Length() const;
@@ -5164,18 +5192,24 @@
  public:
   static const intptr_t kHashBits = 30;
 
-  intptr_t payload_size() const { return raw_ptr()->payload_size_; }
+  uintptr_t payload_size() const { return raw_ptr()->payload_size(); }
 
   bool Equals(const CompressedStackMaps& other) const {
-    if (payload_size() != other.payload_size()) return false;
+    // Both the payload size and the kind of table must match.
+    if (raw_ptr()->flags_and_size_ != other.raw_ptr()->flags_and_size_) {
+      return false;
+    }
     NoSafepointScope no_safepoint;
     return memcmp(raw_ptr(), other.raw_ptr(), InstanceSize(payload_size())) ==
            0;
   }
-  intptr_t Hash() const;
+
+  // Methods to allow use with PointerKeyValueTrait to create sets of CSMs.
+  bool Equals(const CompressedStackMaps* other) const { return Equals(*other); }
+  intptr_t Hashcode() const;
 
   static intptr_t UnroundedSize(RawCompressedStackMaps* maps) {
-    return UnroundedSize(maps->ptr()->payload_size_);
+    return UnroundedSize(maps->ptr()->payload_size());
   }
   static intptr_t UnroundedSize(intptr_t length) {
     return sizeof(RawCompressedStackMaps) + length;
@@ -5190,22 +5224,49 @@
   }
 
  private:
-  // The encoding logic for CompressedStackMaps entries is in
-  // CompressedStackMapsBuilder, and the decoding logic is in
-  // CompressedStackMapsIterator.
-  static RawCompressedStackMaps* New(const GrowableArray<uint8_t>& bytes);
+  static RawCompressedStackMaps* New(const GrowableArray<uint8_t>& bytes,
+                                     RawCompressedStackMaps::Kind kind);
 
-  void set_payload_size(intptr_t payload_size) const {
-    StoreNonPointer(&raw_ptr()->payload_size_, payload_size);
+  static RawCompressedStackMaps* NewInlined(
+      const GrowableArray<uint8_t>& bytes) {
+    return New(bytes, RawCompressedStackMaps::kInlined);
   }
+  static RawCompressedStackMaps* NewUsingTable(
+      const GrowableArray<uint8_t>& bytes) {
+    return New(bytes, RawCompressedStackMaps::kUsesTable);
+  }
+  static RawCompressedStackMaps* NewGlobalTable(
+      const GrowableArray<uint8_t>& bytes) {
+    return New(bytes, RawCompressedStackMaps::kGlobalTable);
+  }
+
+  void set_payload_size(intptr_t payload_size,
+                        RawCompressedStackMaps::Kind kind) const {
+    ASSERT(RawCompressedStackMaps::SizeField::is_valid(payload_size));
+    const uint32_t encoded_fields =
+        RawCompressedStackMaps::KindField::encode(kind) |
+        RawCompressedStackMaps::SizeField::encode(payload_size);
+    StoreNonPointer(&raw_ptr()->flags_and_size_, encoded_fields);
+  }
+
+  bool UsesGlobalTable() const {
+    return !IsNull() && raw_ptr()->UsesGlobalTable();
+  }
+  bool IsGlobalTable() const { return !IsNull() && raw_ptr()->IsGlobalTable(); }
 
   const uint8_t* Payload() const { return raw_ptr()->data(); }
   void SetPayload(const GrowableArray<uint8_t>& payload) const;
+  uint8_t PayloadByte(uintptr_t offset) const {
+    ASSERT(offset >= 0 && offset < payload_size());
+    return raw_ptr()->data()[offset];
+  }
 
   FINAL_HEAP_OBJECT_IMPLEMENTATION(CompressedStackMaps, Object);
   friend class Class;
   friend class CompressedStackMapsBuilder;
   friend class CompressedStackMapsIterator;
+  friend class ProgramVisitor;
+  friend class StackMapEntry;
 };
 
 class ExceptionHandlers : public Object {
@@ -5398,13 +5459,13 @@
   }
   void set_deopt_info_array(const Array& array) const;
 
-#if !defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_PRECOMPILER)
-  RawSmi* variables() const { return raw_ptr()->catch_entry_.variables_; }
-  void set_variables(const Smi& smi) const;
-#else
-  RawTypedData* catch_entry_moves_maps() const {
-    return raw_ptr()->catch_entry_.catch_entry_moves_maps_;
-  }
+#if !defined(DART_PRECOMPILED_RUNTIME)
+  intptr_t num_variables() const;
+  void set_num_variables(intptr_t num_variables) const;
+#endif
+
+#if defined(DART_PRECOMPILED_RUNTIME) || defined(DART_PRECOMPILER)
+  RawTypedData* catch_entry_moves_maps() const;
   void set_catch_entry_moves_maps(const TypedData& maps) const;
 #endif
 
@@ -5540,7 +5601,7 @@
 
   NOT_IN_PRODUCT(void PrintJSONInlineIntervals(JSONObject* object) const);
   void DumpInlineIntervals() const;
-  void DumpSourcePositions() const;
+  void DumpSourcePositions(bool relative_addresses = false) const;
 
   RawLocalVarDescriptors* var_descriptors() const {
 #if defined(PRODUCT)
@@ -5737,6 +5798,10 @@
 #endif
   }
 
+  // Initializes 4 cached entrypoint addresses in 'code' from 'instructions'.
+  static void InitializeCachedEntryPointsFrom(RawCode* code,
+                                              RawInstructions* instructions);
+
   void SetActiveInstructions(const Instructions& instructions) const;
 
   void set_instructions(const Instructions& instructions) const {
@@ -5777,6 +5842,7 @@
   friend class Precompiler;  // for set_object_pool
   friend class FunctionSerializationCluster;
   friend class CodeSerializationCluster;
+  friend class CodeDeserializationCluster;
   friend class StubCode;               // for set_object_pool
   friend class MegamorphicCacheTable;  // for set_object_pool
   friend class CodePatcher;     // for set_instructions
@@ -6196,12 +6262,12 @@
   static void Init();
   static void Cleanup();
 
+  RawArray* cache() const { return raw_ptr()->cache_; }
+
  private:
   // A VM heap allocated preinitialized empty subtype entry array.
   static RawArray* cached_array_;
 
-  RawArray* cache() const { return raw_ptr()->cache_; }
-
   void set_cache(const Array& value) const;
 
   intptr_t TestEntryLength() const;
@@ -6424,14 +6490,17 @@
 
   // Check if the type of this instance is a subtype of the given other type.
   // The type argument vectors are used to instantiate the other type if needed.
-  bool IsInstanceOf(const AbstractType& other,
+  bool IsInstanceOf(NNBDMode mode,
+                    const AbstractType& other,
                     const TypeArguments& other_instantiator_type_arguments,
                     const TypeArguments& other_function_type_arguments) const;
 
   // Returns true if the type of this instance is a subtype of FutureOr<T>
   // specified by instantiated type 'other'.
   // Returns false if other type is not a FutureOr.
-  bool IsFutureOrInstanceOf(Zone* zone, const AbstractType& other) const;
+  bool IsFutureOrInstanceOf(Zone* zone,
+                            NNBDMode mode,
+                            const AbstractType& other) const;
 
   bool IsValidNativeIndex(int index) const {
     return ((index >= 0) && (index < clazz()->ptr()->num_native_fields_));
@@ -6537,6 +6606,9 @@
     StorePointer(RawFieldAddrAtOffset(offset), value.raw());
   }
 
+  static RawInstance* NewFromCidAndSize(SharedClassTable* shared_class_table,
+                                        classid_t cid);
+
   // TODO(iposva): Determine if this gets in the way of Smi.
   HEAP_OBJECT_IMPLEMENTATION(Instance, Object);
   friend class ByteBuffer;
@@ -6566,8 +6638,6 @@
 
   RawLibrary* GetLibrary(int index) const;
   void AddImport(const Namespace& import) const;
-  RawObject* LookupObject(const String& name) const;
-  RawClass* LookupClass(const String& class_name) const;
 
   bool is_deferred_load() const { return raw_ptr()->is_deferred_load_; }
 
@@ -6661,7 +6731,8 @@
 
   // Check the subtype relationship, considering only a subvector of length
   // 'len' starting at 'from_index'.
-  bool IsSubtypeOf(const TypeArguments& other,
+  bool IsSubtypeOf(NNBDMode mode,
+                   const TypeArguments& other,
                    intptr_t from_index,
                    intptr_t len,
                    Heap::Space space) const;
@@ -6719,6 +6790,7 @@
   // type from the various type argument vectors (class instantiator, function,
   // or parent functions via the current context).
   RawTypeArguments* InstantiateFrom(
+      NNBDMode mode,
       const TypeArguments& instantiator_type_arguments,
       const TypeArguments& function_type_arguments,
       intptr_t num_free_fun_type_params,
@@ -6728,6 +6800,7 @@
   // Runtime instantiation with canonicalization. Not to be used during type
   // finalization at compile time.
   RawTypeArguments* InstantiateAndCanonicalizeFrom(
+      NNBDMode mode,
       const TypeArguments& instantiator_type_arguments,
       const TypeArguments& function_type_arguments) const;
 
@@ -6815,10 +6888,22 @@
   virtual void SetIsBeingFinalized() const;
 
   virtual Nullability nullability() const;
-  virtual bool IsUndetermined() const { return nullability() == kUndetermined; }
-  virtual bool IsNullable() const { return nullability() == kNullable; }
-  virtual bool IsNonNullable() const { return nullability() == kNonNullable; }
-  virtual bool IsLegacy() const { return nullability() == kLegacy; }
+  virtual bool IsUndetermined() const {
+    return nullability() == Nullability::kUndetermined;
+  }
+  virtual bool IsNullable() const {
+    return nullability() == Nullability::kNullable;
+  }
+  virtual bool IsNonNullable() const {
+    return nullability() == Nullability::kNonNullable;
+  }
+  virtual bool IsLegacy() const {
+    return nullability() == Nullability::kLegacy;
+  }
+  virtual RawAbstractType* CheckInstantiatedNullability(
+      NNBDMode mode,
+      const TypeParameter& type_param,
+      Heap::Space space) const;
 
   virtual bool HasTypeClass() const { return type_class_id() != kIllegalCid; }
   virtual classid_t type_class_id() const;
@@ -6854,6 +6939,7 @@
   //
   // Return a new type, or return 'this' if it is already instantiated.
   virtual RawAbstractType* InstantiateFrom(
+      NNBDMode mode,
       const TypeArguments& instantiator_type_arguments,
       const TypeArguments& function_type_arguments,
       intptr_t num_free_fun_type_params,
@@ -6924,26 +7010,25 @@
   bool IsNullTypeRef() const;
 
   // Check if this type represents the 'dynamic' type.
-  bool IsDynamicType() const;
+  bool IsDynamicType() const { return type_class_id() == kDynamicCid; }
 
   // Check if this type represents the 'void' type.
-  bool IsVoidType() const;
+  bool IsVoidType() const { return type_class_id() == kVoidCid; }
 
   // Check if this type represents the 'Null' type.
-  bool IsNullType() const;
+  bool IsNullType() const { return type_class_id() == kNullCid; }
 
   // Check if this type represents the 'Never' type.
-  bool IsNeverType() const;
+  bool IsNeverType() const { return type_class_id() == kNeverCid; }
 
   // Check if this type represents the 'Object' type.
-  bool IsObjectType() const;
+  bool IsObjectType() const { return type_class_id() == kInstanceCid; }
 
   // Check if this type represents a top type.
-  // TODO(regis): Remove default kUnaware mode as implementation progresses.
-  bool IsTopType(NNBDMode mode = kUnaware) const;
+  bool IsTopType() const;
 
   // Check if this type represents the 'bool' type.
-  bool IsBoolType() const;
+  bool IsBoolType() const { return type_class_id() == kBoolCid; }
 
   // Check if this type represents the 'int' type.
   bool IsIntType() const;
@@ -6961,10 +7046,10 @@
   bool IsInt32x4Type() const;
 
   // Check if this type represents the 'num' type.
-  bool IsNumberType() const;
+  bool IsNumberType() const { return type_class_id() == kNumberCid; }
 
   // Check if this type represents the '_Smi' type.
-  bool IsSmiType() const;
+  bool IsSmiType() const { return type_class_id() == kSmiCid; }
 
   // Check if this type represents the 'String' type.
   bool IsStringType() const;
@@ -6979,11 +7064,14 @@
   bool IsFfiPointerType() const;
 
   // Check the subtype relationship.
-  bool IsSubtypeOf(const AbstractType& other, Heap::Space space) const;
+  bool IsSubtypeOf(NNBDMode mode,
+                   const AbstractType& other,
+                   Heap::Space space) const;
 
   // Returns true iff subtype is a subtype of supertype, false otherwise or if
   // an error occurred.
   static bool InstantiateAndTestSubtype(
+      NNBDMode mode,
       AbstractType* subtype,
       AbstractType* supertype,
       const TypeArguments& instantiator_type_args,
@@ -7004,6 +7092,7 @@
   // Returns true if this type is a subtype of FutureOr<T> specified by 'other'.
   // Returns false if other type is not a FutureOr.
   bool IsSubtypeOfFutureOr(Zone* zone,
+                           NNBDMode mode,
                            const AbstractType& other,
                            Heap::Space space) const;
 
@@ -7053,8 +7142,8 @@
   }
   void set_nullability(Nullability value) const {
     ASSERT(!IsCanonical());
-    ASSERT(value != kUndetermined);
-    StoreNonPointer(&raw_ptr()->nullability_, value);
+    ASSERT(value != Nullability::kUndetermined);
+    StoreNonPointer(&raw_ptr()->nullability_, static_cast<int8_t>(value));
   }
   RawType* ToNullability(Nullability value, Heap::Space space) const;
   virtual classid_t type_class_id() const;
@@ -7080,6 +7169,7 @@
     return signature() != Function::null();
   }
   virtual RawAbstractType* InstantiateFrom(
+      NNBDMode mode,
       const TypeArguments& instantiator_type_arguments,
       const TypeArguments& function_type_arguments,
       intptr_t num_free_fun_type_params,
@@ -7093,6 +7183,7 @@
   virtual void EnumerateURIs(URIs* uris) const;
 
   virtual intptr_t Hash() const;
+  intptr_t ComputeHash() const;
 
   static intptr_t InstanceSize() {
     return RoundedAllocationSize(sizeof(RawType));
@@ -7153,15 +7244,17 @@
   static RawType* DartTypeType();
 
   // The finalized type of the given non-parameterized class.
-  static RawType* NewNonParameterizedType(const Class& type_class);
+  static RawType* NewNonParameterizedType(
+      const Class& type_class,
+      Nullability nullability = Nullability::kLegacy);
 
   static RawType* New(const Class& clazz,
                       const TypeArguments& arguments,
                       TokenPosition token_pos,
+                      Nullability nullability = Nullability::kLegacy,
                       Heap::Space space = Heap::kOld);
 
  private:
-  intptr_t ComputeHash() const;
   void SetHash(intptr_t value) const;
 
   void set_token_pos(TokenPosition token_pos) const;
@@ -7224,6 +7317,7 @@
     return !ref_type.IsNull() && ref_type.IsFunctionType();
   }
   virtual RawTypeRef* InstantiateFrom(
+      NNBDMode mode,
       const TypeArguments& instantiator_type_arguments,
       const TypeArguments& function_type_arguments,
       intptr_t num_free_fun_type_params,
@@ -7302,6 +7396,7 @@
   virtual bool IsEquivalent(const Instance& other, TrailPtr trail = NULL) const;
   virtual bool IsRecursive() const { return false; }
   virtual RawAbstractType* InstantiateFrom(
+      NNBDMode mode,
       const TypeArguments& instantiator_type_arguments,
       const TypeArguments& function_type_arguments,
       intptr_t num_free_fun_type_params,
@@ -9070,6 +9165,7 @@
 
   FINAL_HEAP_OBJECT_IMPLEMENTATION(TypedData, TypedDataBase);
   friend class Class;
+  friend class CompressedStackMapsIterator;
   friend class ExternalTypedData;
   friend class TypedDataView;
 };
@@ -9642,6 +9738,23 @@
   RawSmi* PcOffsetAtFrame(intptr_t frame_index) const;
   void SetPcOffsetAtFrame(intptr_t frame_index, const Smi& pc_offset) const;
 
+  bool skip_sync_start_in_parent_stack() const;
+  void set_skip_sync_start_in_parent_stack(bool value) const;
+
+  // The number of frames that should be cut off the top of an async stack trace
+  // if it's appended to a synchronous stack trace along a sync-async call.
+  //
+  // Without cropping, the border would look like:
+  //
+  // <async function>
+  // ---------------------------
+  // <asynchronous gap marker>
+  // <async function>
+  //
+  // Since it's not actually an async call, we crop off the last two
+  // frames when concatenating the sync and async stacktraces.
+  static constexpr intptr_t kSyncAsyncCroppedFrames = 2;
+
   static intptr_t InstanceSize() {
     return RoundedAllocationSize(sizeof(RawStackTrace));
   }
@@ -9652,6 +9765,7 @@
   static RawStackTrace* New(const Array& code_array,
                             const Array& pc_offset_array,
                             const StackTrace& async_link,
+                            bool skip_sync_start_in_parent_stack,
                             Heap::Space space = Heap::kNew);
 
  private:
diff --git a/runtime/vm/object_graph.cc b/runtime/vm/object_graph.cc
index 432a6a0..280ca5d 100644
--- a/runtime/vm/object_graph.cc
+++ b/runtime/vm/object_graph.cc
@@ -1011,6 +1011,51 @@
   Flush(true);
 }
 
+CountObjectsVisitor::CountObjectsVisitor(Thread* thread, intptr_t class_count)
+    : ObjectVisitor(),
+      HandleVisitor(thread),
+      new_count_(new intptr_t[class_count]),
+      new_size_(new intptr_t[class_count]),
+      new_external_size_(new intptr_t[class_count]),
+      old_count_(new intptr_t[class_count]),
+      old_size_(new intptr_t[class_count]),
+      old_external_size_(new intptr_t[class_count]) {
+  memset(new_count_.get(), 0, class_count * sizeof(intptr_t));
+  memset(new_size_.get(), 0, class_count * sizeof(intptr_t));
+  memset(new_external_size_.get(), 0, class_count * sizeof(intptr_t));
+  memset(old_count_.get(), 0, class_count * sizeof(intptr_t));
+  memset(old_size_.get(), 0, class_count * sizeof(intptr_t));
+  memset(old_external_size_.get(), 0, class_count * sizeof(intptr_t));
+}
+
+void CountObjectsVisitor::VisitObject(RawObject* obj) {
+  intptr_t cid = obj->GetClassId();
+  intptr_t size = obj->HeapSize();
+  if (obj->IsNewObject()) {
+    new_count_[cid] += 1;
+    new_size_[cid] += size;
+  } else {
+    old_count_[cid] += 1;
+    old_size_[cid] += size;
+  }
+}
+
+void CountObjectsVisitor::VisitHandle(uword addr) {
+  FinalizablePersistentHandle* handle =
+      reinterpret_cast<FinalizablePersistentHandle*>(addr);
+  RawObject* obj = handle->raw();
+  if (!obj->IsHeapObject()) {
+    return;
+  }
+  intptr_t cid = obj->GetClassId();
+  intptr_t size = handle->external_size();
+  if (obj->IsNewObject()) {
+    new_external_size_[cid] += size;
+  } else {
+    old_external_size_[cid] += size;
+  }
+}
+
 #endif  // !defined(PRODUCT)
 
 }  // namespace dart
diff --git a/runtime/vm/object_graph.h b/runtime/vm/object_graph.h
index 8be3382..681c31f 100644
--- a/runtime/vm/object_graph.h
+++ b/runtime/vm/object_graph.h
@@ -5,7 +5,10 @@
 #ifndef RUNTIME_VM_OBJECT_GRAPH_H_
 #define RUNTIME_VM_OBJECT_GRAPH_H_
 
+#include <memory>
+
 #include "vm/allocation.h"
+#include "vm/dart_api_state.h"
 #include "vm/thread_stack_resource.h"
 
 namespace dart {
@@ -200,6 +203,24 @@
   DISALLOW_COPY_AND_ASSIGN(HeapSnapshotWriter);
 };
 
+class CountObjectsVisitor : public ObjectVisitor, public HandleVisitor {
+ public:
+  CountObjectsVisitor(Thread* thread, intptr_t class_count);
+  ~CountObjectsVisitor() {}
+
+  void VisitObject(RawObject* obj);
+  void VisitHandle(uword addr);
+
+  std::unique_ptr<intptr_t[]> new_count_;
+  std::unique_ptr<intptr_t[]> new_size_;
+  std::unique_ptr<intptr_t[]> new_external_size_;
+  std::unique_ptr<intptr_t[]> old_count_;
+  std::unique_ptr<intptr_t[]> old_size_;
+  std::unique_ptr<intptr_t[]> old_external_size_;
+
+  DISALLOW_COPY_AND_ASSIGN(CountObjectsVisitor);
+};
+
 #endif  // !defined(PRODUCT)
 
 }  // namespace dart
diff --git a/runtime/vm/object_id_ring_test.cc b/runtime/vm/object_id_ring_test.cc
index 23d47a6..1b70a92 100644
--- a/runtime/vm/object_id_ring_test.cc
+++ b/runtime/vm/object_id_ring_test.cc
@@ -137,7 +137,6 @@
   EXPECT_EQ(3, list_length);
 
   Isolate* isolate = thread->isolate();
-  Heap* heap = isolate->heap();
   ObjectIdRing* ring = isolate->object_id_ring();
   ObjectIdRing::LookupResult kind = ObjectIdRing::kInvalid;
 
@@ -167,7 +166,7 @@
     EXPECT_EQ(RawObject::ToAddr(raw_obj), RawObject::ToAddr(raw_obj1));
     EXPECT_EQ(RawObject::ToAddr(raw_obj), RawObject::ToAddr(raw_obj2));
     // Force a scavenge.
-    heap->CollectGarbage(Heap::kNew);
+    GCTestHelper::CollectNewSpace();
     RawObject* raw_object_moved1 = ring->GetObjectForId(raw_obj_id1, &kind);
     EXPECT_EQ(ObjectIdRing::kValid, kind);
     RawObject* raw_object_moved2 = ring->GetObjectForId(raw_obj_id2, &kind);
@@ -197,7 +196,6 @@
 // Test that the ring table is updated with nulls when the old GC collects.
 ISOLATE_UNIT_TEST_CASE(ObjectIdRingOldGCTest) {
   Isolate* isolate = thread->isolate();
-  Heap* heap = isolate->heap();
   ObjectIdRing* ring = isolate->object_id_ring();
 
   ObjectIdRing::LookupResult kind = ObjectIdRing::kInvalid;
@@ -230,7 +228,7 @@
   // Force a GC. No reference exist to the old string anymore. It should be
   // collected and the object id ring will now return the null object for
   // those ids.
-  heap->CollectGarbage(Heap::kOld);
+  GCTestHelper::CollectOldSpace();
   RawObject* raw_object_moved1 = ring->GetObjectForId(raw_obj_id1, &kind);
   EXPECT_EQ(ObjectIdRing::kCollected, kind);
   EXPECT_EQ(Object::null(), raw_object_moved1);
diff --git a/runtime/vm/object_reload.cc b/runtime/vm/object_reload.cc
index 22591a2..c2c29dc 100644
--- a/runtime/vm/object_reload.cc
+++ b/runtime/vm/object_reload.cc
@@ -683,15 +683,17 @@
 
   // Class cannot change enum property.
   if (is_enum_class() != replacement.is_enum_class()) {
-    context->AddReasonForCancelling(new (context->zone()) EnumClassConflict(
-        context->zone(), *this, replacement));
+    context->group_reload_context()->AddReasonForCancelling(
+        new (context->zone())
+            EnumClassConflict(context->zone(), *this, replacement));
     return;
   }
 
   // Class cannot change typedef property.
   if (IsTypedefClass() != replacement.IsTypedefClass()) {
-    context->AddReasonForCancelling(new (context->zone()) TypedefClassConflict(
-        context->zone(), *this, replacement));
+    context->group_reload_context()->AddReasonForCancelling(
+        new (context->zone())
+            TypedefClassConflict(context->zone(), *this, replacement));
     return;
   }
 
@@ -700,7 +702,7 @@
     const Error& error =
         Error::Handle(replacement.EnsureIsFinalized(Thread::Current()));
     if (!error.IsNull()) {
-      context->AddReasonForCancelling(
+      context->group_reload_context()->AddReasonForCancelling(
           new (context->zone())
               EnsureFinalizedError(context->zone(), *this, replacement, error));
       return;  // No reason to check other properties.
@@ -711,8 +713,9 @@
 
   // Native field count cannot change.
   if (num_native_fields() != replacement.num_native_fields()) {
-    context->AddReasonForCancelling(new (context->zone()) NativeFieldsConflict(
-        context->zone(), *this, replacement));
+    context->group_reload_context()->AddReasonForCancelling(
+        new (context->zone())
+            NativeFieldsConflict(context->zone(), *this, replacement));
     return;
   }
 
@@ -770,14 +773,23 @@
                                IsolateReloadContext* context) const {
   // Make sure the declaration types argument count matches for the two classes.
   // ex. class A<int,B> {} cannot be replace with class A<B> {}.
+  auto group_context = context->group_reload_context();
   if (NumTypeArguments() != replacement.NumTypeArguments()) {
-    context->AddReasonForCancelling(new (context->zone()) TypeParametersChanged(
-        context->zone(), *this, replacement));
+    group_context->AddReasonForCancelling(
+        new (context->zone())
+            TypeParametersChanged(context->zone(), *this, replacement));
     return false;
   }
   if (RequiresInstanceMorphing(replacement)) {
-    context->AddInstanceMorpher(new (context->zone()) InstanceMorpher(
-        context->zone(), *this, replacement));
+    ASSERT(id() == replacement.id());
+    const classid_t cid = id();
+
+    // We unconditionally create an instance morpher. As a side effect of
+    // building the morpher, we will mark all new fields as late.
+    auto instance_morpher = InstanceMorpher::CreateFromClassDescriptors(
+        context->zone(), context->isolate()->shared_class_table(), *this,
+        replacement);
+    group_context->EnsureHasInstanceMorpherFor(cid, instance_morpher);
   }
   return true;
 }
@@ -786,14 +798,16 @@
                                   IsolateReloadContext* context) const {
   // The replacement class must also prefinalized.
   if (!replacement.is_prefinalized()) {
-    context->AddReasonForCancelling(new (context->zone()) PreFinalizedConflict(
-        context->zone(), *this, replacement));
+    context->group_reload_context()->AddReasonForCancelling(
+        new (context->zone())
+            PreFinalizedConflict(context->zone(), *this, replacement));
     return false;
   }
   // Check the instance sizes are equal.
   if (instance_size() != replacement.instance_size()) {
-    context->AddReasonForCancelling(new (context->zone()) InstanceSizeConflict(
-        context->zone(), *this, replacement));
+    context->group_reload_context()->AddReasonForCancelling(
+        new (context->zone())
+            InstanceSizeConflict(context->zone(), *this, replacement));
     return false;
   }
   return true;
@@ -880,7 +894,7 @@
     args_desc_array_ = ic.arguments_descriptor();
     ArgumentsDescriptor args_desc(args_desc_array_);
     if (new_target_.IsNull() ||
-        !new_target_.AreValidArguments(args_desc, NULL)) {
+        !new_target_.AreValidArguments(NNBDMode::kLegacy, args_desc, NULL)) {
       // TODO(rmacnak): Patch to a NSME stub.
       VTIR_Print("Cannot rebind static call to %s from %s\n",
                  old_target_.ToCString(),
diff --git a/runtime/vm/object_service.cc b/runtime/vm/object_service.cc
index 7685888..0e52082 100644
--- a/runtime/vm/object_service.cc
+++ b/runtime/vm/object_service.cc
@@ -164,14 +164,6 @@
       }
     }
   }
-  {
-    ClassTable* class_table = Isolate::Current()->class_table();
-    const ClassHeapStats* stats = class_table->StatsWithUpdatedSize(id());
-    if (stats != NULL) {
-      JSONObject allocation_stats(&jsobj, "_allocationStats");
-      stats->PrintToJSONObject(*this, &allocation_stats, /*internal*/ true);
-    }
-  }
 }
 
 void TypeArguments::PrintJSONImpl(JSONStream* stream, bool ref) const {
diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h
index 684e06b..373f1fc 100644
--- a/runtime/vm/object_store.h
+++ b/runtime/vm/object_store.h
@@ -129,6 +129,7 @@
   RW(GrowableObjectArray, llvm_constant_pool)                                  \
   RW(GrowableObjectArray, llvm_function_pool)                                  \
   RW(Array, llvm_constant_hash_table)                                          \
+  RW(CompressedStackMaps, canonicalized_stack_map_entries)                     \
   RW(ObjectPool, global_object_pool)                                           \
   RW(Array, unique_dynamic_targets)                                            \
   RW(GrowableObjectArray, megamorphic_cache_table)                             \
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index 41a77bc..1b66b14 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -2129,11 +2129,11 @@
     array.Add(value);
   }
   Heap* heap = Isolate::Current()->heap();
-  heap->CollectAllGarbage();
+  GCTestHelper::CollectAllGarbage();
   intptr_t capacity_before = heap->CapacityInWords(Heap::kOld);
   new_array = Array::MakeFixedLength(array);
   EXPECT_EQ(1, new_array.Length());
-  heap->CollectAllGarbage();
+  GCTestHelper::CollectAllGarbage();
   intptr_t capacity_after = heap->CapacityInWords(Heap::kOld);
   // Page should shrink.
   EXPECT_LT(capacity_after, capacity_before);
@@ -2702,14 +2702,19 @@
 ISOLATE_UNIT_TEST_CASE(PcDescriptors) {
   DescriptorList* builder = new DescriptorList(0);
 
-  // kind, pc_offset, deopt_id, token_pos, try_index
-  builder->AddDescriptor(RawPcDescriptors::kOther, 10, 1, TokenPosition(20), 1);
-  builder->AddDescriptor(RawPcDescriptors::kDeopt, 20, 2, TokenPosition(30), 0);
-  builder->AddDescriptor(RawPcDescriptors::kOther, 30, 3, TokenPosition(40), 1);
-  builder->AddDescriptor(RawPcDescriptors::kOther, 10, 4, TokenPosition(40), 2);
-  builder->AddDescriptor(RawPcDescriptors::kOther, 10, 5, TokenPosition(80), 3);
-  builder->AddDescriptor(RawPcDescriptors::kOther, 80, 6, TokenPosition(150),
-                         3);
+  // kind, pc_offset, deopt_id, token_pos, try_index, yield_index
+  builder->AddDescriptor(RawPcDescriptors::kOther, 10, 1, TokenPosition(20), 1,
+                         1);
+  builder->AddDescriptor(RawPcDescriptors::kDeopt, 20, 2, TokenPosition(30), 0,
+                         -1);
+  builder->AddDescriptor(RawPcDescriptors::kOther, 30, 3, TokenPosition(40), 1,
+                         10);
+  builder->AddDescriptor(RawPcDescriptors::kOther, 10, 4, TokenPosition(40), 2,
+                         20);
+  builder->AddDescriptor(RawPcDescriptors::kOther, 10, 5, TokenPosition(80), 3,
+                         30);
+  builder->AddDescriptor(RawPcDescriptors::kOther, 80, 6, TokenPosition(150), 3,
+                         30);
 
   PcDescriptors& descriptors = PcDescriptors::Handle();
   descriptors ^= builder->FinalizePcDescriptors(0);
@@ -2728,6 +2733,7 @@
   PcDescriptors::Iterator iter(pc_descs, RawPcDescriptors::kAnyKind);
 
   EXPECT_EQ(true, iter.MoveNext());
+  EXPECT_EQ(1, iter.YieldIndex());
   EXPECT_EQ(20, iter.TokenPos().value());
   EXPECT_EQ(1, iter.TryIndex());
   EXPECT_EQ(static_cast<uword>(10), iter.PcOffset());
@@ -2735,19 +2741,24 @@
   EXPECT_EQ(RawPcDescriptors::kOther, iter.Kind());
 
   EXPECT_EQ(true, iter.MoveNext());
+  EXPECT_EQ(-1, iter.YieldIndex());
   EXPECT_EQ(30, iter.TokenPos().value());
   EXPECT_EQ(RawPcDescriptors::kDeopt, iter.Kind());
 
   EXPECT_EQ(true, iter.MoveNext());
+  EXPECT_EQ(10, iter.YieldIndex());
   EXPECT_EQ(40, iter.TokenPos().value());
 
   EXPECT_EQ(true, iter.MoveNext());
+  EXPECT_EQ(20, iter.YieldIndex());
   EXPECT_EQ(40, iter.TokenPos().value());
 
   EXPECT_EQ(true, iter.MoveNext());
+  EXPECT_EQ(30, iter.YieldIndex());
   EXPECT_EQ(80, iter.TokenPos().value());
 
   EXPECT_EQ(true, iter.MoveNext());
+  EXPECT_EQ(30, iter.YieldIndex());
   EXPECT_EQ(150, iter.TokenPos().value());
 
   EXPECT_EQ(3, iter.TryIndex());
@@ -2763,16 +2774,17 @@
 
   // kind, pc_offset, deopt_id, token_pos, try_index
   builder->AddDescriptor(RawPcDescriptors::kOther, 100, 1, TokenPosition(200),
-                         1);
+                         1, 10);
   builder->AddDescriptor(RawPcDescriptors::kDeopt, 200, 2, TokenPosition(300),
-                         0);
+                         0, -1);
   builder->AddDescriptor(RawPcDescriptors::kOther, 300, 3, TokenPosition(400),
-                         1);
-  builder->AddDescriptor(RawPcDescriptors::kOther, 100, 4, TokenPosition(0), 2);
+                         1, 10);
+  builder->AddDescriptor(RawPcDescriptors::kOther, 100, 4, TokenPosition(0), 2,
+                         20);
   builder->AddDescriptor(RawPcDescriptors::kOther, 100, 5, TokenPosition(800),
-                         3);
+                         3, 30);
   builder->AddDescriptor(RawPcDescriptors::kOther, 800, 6, TokenPosition(150),
-                         3);
+                         3, 30);
 
   PcDescriptors& descriptors = PcDescriptors::Handle();
   descriptors ^= builder->FinalizePcDescriptors(0);
@@ -2791,6 +2803,7 @@
   PcDescriptors::Iterator iter(pc_descs, RawPcDescriptors::kAnyKind);
 
   EXPECT_EQ(true, iter.MoveNext());
+  EXPECT_EQ(10, iter.YieldIndex());
   EXPECT_EQ(200, iter.TokenPos().value());
   EXPECT_EQ(1, iter.TryIndex());
   EXPECT_EQ(static_cast<uword>(100), iter.PcOffset());
@@ -2798,19 +2811,24 @@
   EXPECT_EQ(RawPcDescriptors::kOther, iter.Kind());
 
   EXPECT_EQ(true, iter.MoveNext());
+  EXPECT_EQ(-1, iter.YieldIndex());
   EXPECT_EQ(300, iter.TokenPos().value());
   EXPECT_EQ(RawPcDescriptors::kDeopt, iter.Kind());
 
   EXPECT_EQ(true, iter.MoveNext());
+  EXPECT_EQ(10, iter.YieldIndex());
   EXPECT_EQ(400, iter.TokenPos().value());
 
   EXPECT_EQ(true, iter.MoveNext());
+  EXPECT_EQ(20, iter.YieldIndex());
   EXPECT_EQ(0, iter.TokenPos().value());
 
   EXPECT_EQ(true, iter.MoveNext());
+  EXPECT_EQ(30, iter.YieldIndex());
   EXPECT_EQ(800, iter.TokenPos().value());
 
   EXPECT_EQ(true, iter.MoveNext());
+  EXPECT_EQ(30, iter.YieldIndex());
   EXPECT_EQ(150, iter.TokenPos().value());
 
   EXPECT_EQ(3, iter.TryIndex());
@@ -3217,7 +3235,6 @@
 }
 
 ISOLATE_UNIT_TEST_CASE(WeakProperty_PreserveCrossGen) {
-  Isolate* isolate = Isolate::Current();
   WeakProperty& weak = WeakProperty::Handle();
   {
     // Weak property and value in new. Key in old.
@@ -3232,8 +3249,8 @@
     key ^= OneByteString::null();
     value ^= OneByteString::null();
   }
-  isolate->heap()->CollectGarbage(Heap::kNew);
-  isolate->heap()->CollectGarbage(Heap::kOld);
+  GCTestHelper::CollectNewSpace();
+  GCTestHelper::CollectOldSpace();
   // Weak property key and value should survive due to cross-generation
   // pointers.
   EXPECT(weak.key() != Object::null());
@@ -3251,8 +3268,8 @@
     key ^= OneByteString::null();
     value ^= OneByteString::null();
   }
-  isolate->heap()->CollectGarbage(Heap::kNew);
-  isolate->heap()->CollectGarbage(Heap::kOld);
+  GCTestHelper::CollectNewSpace();
+  GCTestHelper::CollectOldSpace();
   // Weak property key and value should survive due to cross-generation
   // pointers.
   EXPECT(weak.key() != Object::null());
@@ -3270,7 +3287,7 @@
     key ^= Integer::null();
     value ^= OneByteString::null();
   }
-  isolate->heap()->CollectAllGarbage();
+  GCTestHelper::CollectAllGarbage();
   // Weak property key and value should survive due implicit liveness of
   // non-heap objects.
   EXPECT(weak.key() != Object::null());
@@ -3288,7 +3305,7 @@
     key ^= OneByteString::null();
     value ^= OneByteString::null();
   }
-  isolate->heap()->CollectAllGarbage();
+  GCTestHelper::CollectAllGarbage();
   // Weak property key and value should survive due implicit liveness of
   // non-heap objects.
   EXPECT(weak.key() != Object::null());
@@ -3305,8 +3322,8 @@
     key ^= OneByteString::null();
     value ^= OneByteString::null();
   }
-  isolate->heap()->CollectGarbage(Heap::kNew);
-  isolate->heap()->CollectGarbage(Heap::kOld);
+  GCTestHelper::CollectNewSpace();
+  GCTestHelper::CollectOldSpace();
   // Weak property key and value should survive due to cross-generation
   // pointers.
   EXPECT(weak.key() != Object::null());
@@ -3323,8 +3340,8 @@
     key ^= OneByteString::null();
     value ^= OneByteString::null();
   }
-  isolate->heap()->CollectGarbage(Heap::kNew);
-  isolate->heap()->CollectGarbage(Heap::kOld);
+  GCTestHelper::CollectNewSpace();
+  GCTestHelper::CollectOldSpace();
   // Weak property key and value should survive due to cross-generation
   // pointers.
   EXPECT(weak.key() != Object::null());
@@ -3334,7 +3351,6 @@
 ISOLATE_UNIT_TEST_CASE(WeakProperty_PreserveRecurse) {
   // This used to end in an infinite recursion. Caused by scavenging the weak
   // property before scavenging the key.
-  Isolate* isolate = Isolate::Current();
   WeakProperty& weak = WeakProperty::Handle();
   Array& arr = Array::Handle(Array::New(1));
   {
@@ -3348,13 +3364,12 @@
     weak.set_key(key);
     weak.set_value(value);
   }
-  isolate->heap()->CollectAllGarbage();
+  GCTestHelper::CollectAllGarbage();
   EXPECT(weak.key() != Object::null());
   EXPECT(weak.value() != Object::null());
 }
 
 ISOLATE_UNIT_TEST_CASE(WeakProperty_PreserveOne_NewSpace) {
-  Isolate* isolate = Isolate::Current();
   WeakProperty& weak = WeakProperty::Handle();
   String& key = String::Handle();
   key ^= OneByteString::New("key");
@@ -3366,13 +3381,12 @@
     weak.set_key(key);
     weak.set_value(value);
   }
-  isolate->heap()->CollectAllGarbage();
+  GCTestHelper::CollectAllGarbage();
   EXPECT(weak.key() != Object::null());
   EXPECT(weak.value() != Object::null());
 }
 
 ISOLATE_UNIT_TEST_CASE(WeakProperty_PreserveTwo_NewSpace) {
-  Isolate* isolate = Isolate::Current();
   WeakProperty& weak1 = WeakProperty::Handle();
   String& key1 = String::Handle();
   key1 ^= OneByteString::New("key1");
@@ -3392,7 +3406,7 @@
     weak2.set_key(key2);
     weak2.set_value(value2);
   }
-  isolate->heap()->CollectAllGarbage();
+  GCTestHelper::CollectAllGarbage();
   EXPECT(weak1.key() != Object::null());
   EXPECT(weak1.value() != Object::null());
   EXPECT(weak2.key() != Object::null());
@@ -3400,7 +3414,6 @@
 }
 
 ISOLATE_UNIT_TEST_CASE(WeakProperty_PreserveTwoShared_NewSpace) {
-  Isolate* isolate = Isolate::Current();
   WeakProperty& weak1 = WeakProperty::Handle();
   WeakProperty& weak2 = WeakProperty::Handle();
   String& key = String::Handle();
@@ -3418,7 +3431,7 @@
     weak2.set_key(key);
     weak2.set_value(value2);
   }
-  isolate->heap()->CollectAllGarbage();
+  GCTestHelper::CollectAllGarbage();
   EXPECT(weak1.key() != Object::null());
   EXPECT(weak1.value() != Object::null());
   EXPECT(weak2.key() != Object::null());
@@ -3426,7 +3439,6 @@
 }
 
 ISOLATE_UNIT_TEST_CASE(WeakProperty_PreserveOne_OldSpace) {
-  Isolate* isolate = Isolate::Current();
   WeakProperty& weak = WeakProperty::Handle();
   String& key = String::Handle();
   key ^= OneByteString::New("key", Heap::kOld);
@@ -3438,13 +3450,12 @@
     weak.set_key(key);
     weak.set_value(value);
   }
-  isolate->heap()->CollectAllGarbage();
+  GCTestHelper::CollectAllGarbage();
   EXPECT(weak.key() != Object::null());
   EXPECT(weak.value() != Object::null());
 }
 
 ISOLATE_UNIT_TEST_CASE(WeakProperty_PreserveTwo_OldSpace) {
-  Isolate* isolate = Isolate::Current();
   WeakProperty& weak1 = WeakProperty::Handle();
   String& key1 = String::Handle();
   key1 ^= OneByteString::New("key1", Heap::kOld);
@@ -3464,7 +3475,7 @@
     weak2.set_key(key2);
     weak2.set_value(value2);
   }
-  isolate->heap()->CollectAllGarbage();
+  GCTestHelper::CollectAllGarbage();
   EXPECT(weak1.key() != Object::null());
   EXPECT(weak1.value() != Object::null());
   EXPECT(weak2.key() != Object::null());
@@ -3472,7 +3483,6 @@
 }
 
 ISOLATE_UNIT_TEST_CASE(WeakProperty_PreserveTwoShared_OldSpace) {
-  Isolate* isolate = Isolate::Current();
   WeakProperty& weak1 = WeakProperty::Handle();
   WeakProperty& weak2 = WeakProperty::Handle();
   String& key = String::Handle();
@@ -3490,7 +3500,7 @@
     weak2.set_key(key);
     weak2.set_value(value2);
   }
-  isolate->heap()->CollectAllGarbage();
+  GCTestHelper::CollectAllGarbage();
   EXPECT(weak1.key() != Object::null());
   EXPECT(weak1.value() != Object::null());
   EXPECT(weak2.key() != Object::null());
@@ -3498,7 +3508,6 @@
 }
 
 ISOLATE_UNIT_TEST_CASE(WeakProperty_ClearOne_NewSpace) {
-  Isolate* isolate = Isolate::Current();
   WeakProperty& weak = WeakProperty::Handle();
   {
     HANDLESCOPE(thread);
@@ -3512,13 +3521,12 @@
     key ^= OneByteString::null();
     value ^= OneByteString::null();
   }
-  isolate->heap()->CollectAllGarbage();
+  GCTestHelper::CollectAllGarbage();
   EXPECT(weak.key() == Object::null());
   EXPECT(weak.value() == Object::null());
 }
 
 ISOLATE_UNIT_TEST_CASE(WeakProperty_ClearTwoShared_NewSpace) {
-  Isolate* isolate = Isolate::Current();
   WeakProperty& weak1 = WeakProperty::Handle();
   WeakProperty& weak2 = WeakProperty::Handle();
   {
@@ -3536,7 +3544,7 @@
     weak2.set_key(key);
     weak2.set_value(value2);
   }
-  isolate->heap()->CollectAllGarbage();
+  GCTestHelper::CollectAllGarbage();
   EXPECT(weak1.key() == Object::null());
   EXPECT(weak1.value() == Object::null());
   EXPECT(weak2.key() == Object::null());
@@ -3544,7 +3552,6 @@
 }
 
 ISOLATE_UNIT_TEST_CASE(WeakProperty_ClearOne_OldSpace) {
-  Isolate* isolate = Isolate::Current();
   WeakProperty& weak = WeakProperty::Handle();
   {
     HANDLESCOPE(thread);
@@ -3558,13 +3565,12 @@
     key ^= OneByteString::null();
     value ^= OneByteString::null();
   }
-  isolate->heap()->CollectAllGarbage();
+  GCTestHelper::CollectAllGarbage();
   EXPECT(weak.key() == Object::null());
   EXPECT(weak.value() == Object::null());
 }
 
 ISOLATE_UNIT_TEST_CASE(WeakProperty_ClearTwoShared_OldSpace) {
-  Isolate* isolate = Isolate::Current();
   WeakProperty& weak1 = WeakProperty::Handle();
   WeakProperty& weak2 = WeakProperty::Handle();
   {
@@ -3582,7 +3588,7 @@
     weak2.set_key(key);
     weak2.set_value(value2);
   }
-  isolate->heap()->CollectAllGarbage();
+  GCTestHelper::CollectAllGarbage();
   EXPECT(weak1.key() == Object::null());
   EXPECT(weak1.value() == Object::null());
   EXPECT(weak2.key() == Object::null());
@@ -4005,8 +4011,7 @@
     bin::VmService::SetNativeResolver();
   }
 
-  Heap* heap = Isolate::Current()->heap();
-  heap->CollectAllGarbage();
+  GCTestHelper::CollectAllGarbage();
   GrowableArray<Object*> objects;
   {
     HeapIterationScope iteration(Thread::Current());
diff --git a/runtime/vm/program_visitor.cc b/runtime/vm/program_visitor.cc
index 5edf8e3..41d2e31 100644
--- a/runtime/vm/program_visitor.cc
+++ b/runtime/vm/program_visitor.cc
@@ -199,84 +199,303 @@
   }
 }
 
-class CompressedStackMapsKeyValueTrait {
+class StackMapEntry : public ZoneAllocated {
  public:
-  // Typedefs needed for the DirectChainedHashMap template.
-  typedef const CompressedStackMaps* Key;
-  typedef const CompressedStackMaps* Value;
-  typedef const CompressedStackMaps* Pair;
-
-  static Key KeyOf(Pair kv) { return kv; }
-
-  static Value ValueOf(Pair kv) { return kv; }
-
-  static inline intptr_t Hashcode(Key key) { return key->Hash(); }
-
-  static inline bool IsKeyEqual(Pair pair, Key key) {
-    return pair->Equals(*key);
+  StackMapEntry(Zone* zone, const CompressedStackMapsIterator& it)
+      : maps_(CompressedStackMaps::Handle(zone, it.maps_.raw())),
+        bits_container_(
+            CompressedStackMaps::Handle(zone, it.bits_container_.raw())),
+        spill_slot_bit_count_(it.current_spill_slot_bit_count_),
+        non_spill_slot_bit_count_(it.current_non_spill_slot_bit_count_),
+        bits_offset_(it.current_bits_offset_) {
+    ASSERT(!maps_.IsNull() && !maps_.IsGlobalTable());
+    ASSERT(!bits_container_.IsNull());
+    ASSERT(!maps_.UsesGlobalTable() || bits_container_.IsGlobalTable());
+    // Check that the iterator was fully loaded when we ran the initializing
+    // expressions above. By this point we enter the body of the constructor,
+    // it's too late to run EnsureFullyLoadedEntry().
+    ASSERT(it.HasLoadedEntry());
+    ASSERT(it.current_spill_slot_bit_count_ >= 0);
   }
+
+  static const intptr_t kHashBits = 30;
+
+  intptr_t Hashcode() {
+    if (hash_ != 0) return hash_;
+    uint32_t hash = 0;
+    hash = CombineHashes(hash, spill_slot_bit_count_);
+    hash = CombineHashes(hash, non_spill_slot_bit_count_);
+    for (intptr_t i = 0; i < PayloadLength(); i++) {
+      hash = CombineHashes(hash, PayloadByte(i));
+    }
+    hash_ = FinalizeHash(hash, kHashBits);
+    return hash_;
+  }
+
+  bool Equals(const StackMapEntry* other) const {
+    if (spill_slot_bit_count_ != other->spill_slot_bit_count_ ||
+        non_spill_slot_bit_count_ != other->non_spill_slot_bit_count_) {
+      return false;
+    }
+    // Since we ensure that bits in the payload that are not part of the
+    // actual stackmap data are cleared, we can just compare payloads by byte
+    // instead of calling IsObject for each bit.
+    for (intptr_t i = 0; i < PayloadLength(); i++) {
+      if (PayloadByte(i) != other->PayloadByte(i)) return false;
+    }
+    return true;
+  }
+
+  // Encodes this StackMapEntry to the given array of bytes and returns the
+  // initial offset of the entry in the array.
+  intptr_t EncodeTo(GrowableArray<uint8_t>* array) {
+    auto const current_offset = array->length();
+    CompressedStackMapsBuilder::EncodeLEB128(array, spill_slot_bit_count_);
+    CompressedStackMapsBuilder::EncodeLEB128(array, non_spill_slot_bit_count_);
+    for (intptr_t i = 0; i < PayloadLength(); i++) {
+      array->Add(PayloadByte(i));
+    }
+    return current_offset;
+  }
+
+  intptr_t UsageCount() const { return uses_; }
+  void IncrementUsageCount() { uses_ += 1; }
+
+ private:
+  intptr_t Length() const {
+    return spill_slot_bit_count_ + non_spill_slot_bit_count_;
+  }
+  intptr_t PayloadLength() const {
+    return Utils::RoundUp(Length(), kBitsPerByte) >> kBitsPerByteLog2;
+  }
+  intptr_t PayloadByte(intptr_t offset) const {
+    return bits_container_.PayloadByte(bits_offset_ + offset);
+  }
+
+  const CompressedStackMaps& maps_;
+  const CompressedStackMaps& bits_container_;
+  const intptr_t spill_slot_bit_count_;
+  const intptr_t non_spill_slot_bit_count_;
+  const intptr_t bits_offset_;
+
+  intptr_t uses_ = 1;
+  intptr_t hash_ = 0;
 };
 
-typedef DirectChainedHashMap<CompressedStackMapsKeyValueTrait>
+// Used for maps of indices and offsets. These are non-negative, and so the
+// value for entries may be 0. Since 0 is kNoValue for
+// RawPointerKeyValueTrait<const StackMapEntry, intptr_t>, we can't just use it.
+class StackMapEntryKeyIntValueTrait {
+ public:
+  typedef StackMapEntry* Key;
+  typedef intptr_t Value;
+
+  struct Pair {
+    Key key;
+    Value value;
+    Pair() : key(nullptr), value(-1) {}
+    Pair(const Key key, const Value& value)
+        : key(ASSERT_NOTNULL(key)), value(value) {}
+    Pair(const Pair& other) : key(other.key), value(other.value) {}
+  };
+
+  static Key KeyOf(Pair kv) { return kv.key; }
+  static Value ValueOf(Pair kv) { return kv.value; }
+  static intptr_t Hashcode(Key key) { return key->Hashcode(); }
+  static bool IsKeyEqual(Pair kv, Key key) { return key->Equals(kv.key); }
+};
+
+typedef DirectChainedHashMap<StackMapEntryKeyIntValueTrait> StackMapEntryIntMap;
+
+typedef DirectChainedHashMap<PointerKeyValueTrait<const CompressedStackMaps>>
     CompressedStackMapsSet;
 
-void ProgramVisitor::DedupCompressedStackMaps() {
-  class DedupCompressedStackMapsVisitor : public FunctionVisitor {
+void ProgramVisitor::NormalizeAndDedupCompressedStackMaps() {
+  // Walks all the CSMs in Code objects and collects their entry information
+  // for consolidation.
+  class CollectStackMapEntriesVisitor : public FunctionVisitor {
    public:
-    explicit DedupCompressedStackMapsVisitor(Zone* zone)
+    CollectStackMapEntriesVisitor(Zone* zone,
+                                  const CompressedStackMaps& global_table)
         : zone_(zone),
-          canonical_compressed_stackmaps_set_(),
+          old_global_table_(global_table),
           code_(Code::Handle(zone)),
-          compressed_stackmaps_(CompressedStackMaps::Handle(zone)) {}
-
-    void AddCompressedStackMaps(const CompressedStackMaps& maps) {
-      canonical_compressed_stackmaps_set_.Insert(
-          &CompressedStackMaps::ZoneHandle(zone_, maps.raw()));
+          compressed_stackmaps_(CompressedStackMaps::Handle(zone)),
+          collected_entries_(zone, 2),
+          entry_indices_(zone),
+          entry_offset_(zone) {
+      ASSERT(old_global_table_.IsNull() || old_global_table_.IsGlobalTable());
     }
 
     void Visit(const Function& function) {
-      if (!function.HasCode()) {
-        return;
-      }
+      if (!function.HasCode()) return;
       code_ = function.CurrentCode();
       compressed_stackmaps_ = code_.compressed_stackmaps();
-      if (compressed_stackmaps_.IsNull()) return;
-      compressed_stackmaps_ = DedupCompressedStackMaps(compressed_stackmaps_);
-      code_.set_compressed_stackmaps(compressed_stackmaps_);
+      CompressedStackMapsIterator it(compressed_stackmaps_, old_global_table_);
+      while (it.MoveNext()) {
+        it.EnsureFullyLoadedEntry();
+        auto const entry = new (zone_) StackMapEntry(zone_, it);
+        auto const index = entry_indices_.LookupValue(entry);
+        if (index < 0) {
+          auto new_index = collected_entries_.length();
+          collected_entries_.Add(entry);
+          entry_indices_.Insert({entry, new_index});
+        } else {
+          collected_entries_.At(index)->IncrementUsageCount();
+        }
+      }
     }
 
-    RawCompressedStackMaps* DedupCompressedStackMaps(
-        const CompressedStackMaps& maps) {
-      auto const canonical_maps =
-          canonical_compressed_stackmaps_set_.LookupValue(&maps);
-      if (canonical_maps == nullptr) {
-        AddCompressedStackMaps(maps);
-        return maps.raw();
-      } else {
-        return canonical_maps->raw();
+    // Creates a new global table of stack map information. Also adds the
+    // offsets of encoded StackMapEntry objects to entry_offsets for use
+    // when normalizing CompressedStackMaps.
+    RawCompressedStackMaps* CreateGlobalTable(
+        StackMapEntryIntMap* entry_offsets) {
+      ASSERT(entry_offsets->IsEmpty());
+      if (collected_entries_.length() == 0) return CompressedStackMaps::null();
+      // First, sort the entries from most used to least used. This way,
+      // the most often used CSMs will have the lowest offsets, which means
+      // they will be smaller when LEB128 encoded.
+      collected_entries_.Sort(
+          [](StackMapEntry* const* e1, StackMapEntry* const* e2) {
+            return static_cast<int>((*e2)->UsageCount() - (*e1)->UsageCount());
+          });
+      GrowableArray<uint8_t> bytes;
+      // Encode the entries and record their offset in the payload. Sorting the
+      // entries may have changed their indices, so update those as well.
+      for (intptr_t i = 0, n = collected_entries_.length(); i < n; i++) {
+        auto const entry = collected_entries_.At(i);
+        entry_indices_.Update({entry, i});
+        entry_offsets->Insert({entry, entry->EncodeTo(&bytes)});
       }
+      const auto& data = CompressedStackMaps::Handle(
+          zone_, CompressedStackMaps::NewGlobalTable(bytes));
+      return data.raw();
     }
 
    private:
-    Zone* zone_;
+    Zone* const zone_;
+    const CompressedStackMaps& old_global_table_;
+
+    Code& code_;
+    CompressedStackMaps& compressed_stackmaps_;
+    GrowableArray<StackMapEntry*> collected_entries_;
+    StackMapEntryIntMap entry_indices_;
+    StackMapEntryIntMap entry_offset_;
+  };
+
+  // Walks all the CSMs in Code objects, normalizes them, and then dedups them.
+  //
+  // We use normalized to refer to CSMs whose entries are references to the
+  // new global table created during stack map collection, and non-normalized
+  // for CSMs that either have inlined entry information or whose entries are
+  // references to the _old_ global table in the object store, if any.
+  class NormalizeAndDedupCompressedStackMapsVisitor : public FunctionVisitor {
+   public:
+    NormalizeAndDedupCompressedStackMapsVisitor(
+        Zone* zone,
+        const CompressedStackMaps& global_table,
+        const StackMapEntryIntMap& entry_offsets)
+        : zone_(zone),
+          old_global_table_(global_table),
+          entry_offsets_(entry_offsets),
+          canonical_compressed_stackmaps_set_(),
+          code_(Code::Handle(zone)),
+          compressed_stackmaps_(CompressedStackMaps::Handle(zone)),
+          current_normalized_maps_(CompressedStackMaps::Handle(zone)) {
+      ASSERT(old_global_table_.IsNull() || old_global_table_.IsGlobalTable());
+    }
+
+    // Creates a normalized CSM from the given non-normalized CSM.
+    RawCompressedStackMaps* NormalizeEntries(const CompressedStackMaps& maps) {
+      GrowableArray<uint8_t> new_payload;
+      CompressedStackMapsIterator it(maps, old_global_table_);
+      intptr_t last_offset = 0;
+      while (it.MoveNext()) {
+        it.EnsureFullyLoadedEntry();
+        StackMapEntry entry(zone_, it);
+        auto const entry_offset = entry_offsets_.LookupValue(&entry);
+        auto const pc_delta = it.pc_offset() - last_offset;
+        CompressedStackMapsBuilder::EncodeLEB128(&new_payload, pc_delta);
+        CompressedStackMapsBuilder::EncodeLEB128(&new_payload, entry_offset);
+        last_offset = it.pc_offset();
+      }
+      return CompressedStackMaps::NewUsingTable(new_payload);
+    }
+
+    RawCompressedStackMaps* NormalizeAndDedupCompressedStackMaps(
+        const CompressedStackMaps& maps) {
+      ASSERT(!maps.IsNull());
+      // First check is to make sure [maps] hasn't already been normalized,
+      // since any normalized map already has a canonical entry in the set.
+      auto canonical_maps =
+          canonical_compressed_stackmaps_set_.LookupValue(&maps);
+      if (canonical_maps != nullptr) return canonical_maps->raw();
+      current_normalized_maps_ = NormalizeEntries(compressed_stackmaps_);
+      // Use the canonical entry for the newly normalized CSM, if one exists.
+      canonical_maps = canonical_compressed_stackmaps_set_.LookupValue(
+          &current_normalized_maps_);
+      if (canonical_maps != nullptr) return canonical_maps->raw();
+      canonical_compressed_stackmaps_set_.Insert(
+          &CompressedStackMaps::ZoneHandle(zone_,
+                                           current_normalized_maps_.raw()));
+      return current_normalized_maps_.raw();
+    }
+
+    void Visit(const Function& function) {
+      if (!function.HasCode()) return;
+      code_ = function.CurrentCode();
+      compressed_stackmaps_ = code_.compressed_stackmaps();
+      // We represent empty CSMs as the null value, and thus those don't need to
+      // be normalized or deduped.
+      if (compressed_stackmaps_.IsNull()) return;
+      compressed_stackmaps_ =
+          NormalizeAndDedupCompressedStackMaps(compressed_stackmaps_);
+      code_.set_compressed_stackmaps(compressed_stackmaps_);
+    }
+
+   private:
+    Zone* const zone_;
+    const CompressedStackMaps& old_global_table_;
+    const StackMapEntryIntMap& entry_offsets_;
     CompressedStackMapsSet canonical_compressed_stackmaps_set_;
     Code& code_;
     CompressedStackMaps& compressed_stackmaps_;
+    CompressedStackMaps& current_normalized_maps_;
   };
 
-  DedupCompressedStackMapsVisitor visitor(Thread::Current()->zone());
-  if (Snapshot::IncludesCode(Dart::vm_snapshot_kind())) {
-    // Prefer existing objects in the VM isolate.
-    const Array& object_table = Object::vm_isolate_snapshot_object_table();
-    Object& object = Object::Handle();
-    for (intptr_t i = 0; i < object_table.Length(); i++) {
-      object = object_table.At(i);
-      if (object.IsCompressedStackMaps()) {
-        visitor.AddCompressedStackMaps(CompressedStackMaps::Cast(object));
-      }
-    }
-  }
-  ProgramVisitor::VisitFunctions(&visitor);
+  // The stack map deduplication happens in two phases:
+  // 1) Visit all CompressedStackMaps (CSM) objects and collect individual entry
+  //    info as canonicalized StackMapEntries (SMEs). Also record the number of
+  //    times the same entry info was seen across all CSMs in each SME.
+  //
+  // The results of phase 1 are used to create a new global table with entries
+  // sorted by decreasing frequency, so that entries that appear more often in
+  // CSMs have smaller payload offsets (less bytes used in the LEB128 encoding).
+  //
+  // 2) Visit all CSMs and replace each with a canonicalized normalized version
+  //    that uses the new global table for non-PC offset entry information.
+  Thread* const t = Thread::Current();
+  StackZone temp_zone(t);
+  HandleScope temp_handles(t);
+  Zone* zone = temp_zone.GetZone();
+  auto object_store = t->isolate()->object_store();
+  const auto& old_global_table = CompressedStackMaps::Handle(
+      zone, object_store->canonicalized_stack_map_entries());
+  CollectStackMapEntriesVisitor collect_visitor(zone, old_global_table);
+  ProgramVisitor::VisitFunctions(&collect_visitor);
+
+  // We retrieve the new offsets for CSM entries by creating the new global
+  // table now. We go ahead and put it in place, as we already have a handle
+  // on the old table that we can pass to the normalizing visitor.
+  StackMapEntryIntMap entry_offsets(zone);
+  const auto& new_global_table = CompressedStackMaps::Handle(
+      zone, collect_visitor.CreateGlobalTable(&entry_offsets));
+  object_store->set_canonicalized_stack_map_entries(new_global_table);
+
+  NormalizeAndDedupCompressedStackMapsVisitor dedup_visitor(
+      zone, old_global_table, entry_offsets);
+  ProgramVisitor::VisitFunctions(&dedup_visitor);
 }
 
 class PcDescriptorsKeyValueTrait {
@@ -887,7 +1106,7 @@
 
   BindStaticCalls();
   ShareMegamorphicBuckets();
-  DedupCompressedStackMaps();
+  NormalizeAndDedupCompressedStackMaps();
   DedupPcDescriptors();
   NOT_IN_PRECOMPILED(DedupDeoptEntries());
 #if defined(DART_PRECOMPILER)
diff --git a/runtime/vm/program_visitor.h b/runtime/vm/program_visitor.h
index d18b60d..e66f6a6 100644
--- a/runtime/vm/program_visitor.h
+++ b/runtime/vm/program_visitor.h
@@ -33,7 +33,7 @@
 #if !defined(DART_PRECOMPILED_RUNTIME)
   static void BindStaticCalls();
   static void ShareMegamorphicBuckets();
-  static void DedupCompressedStackMaps();
+  static void NormalizeAndDedupCompressedStackMaps();
   static void DedupPcDescriptors();
   static void DedupDeoptEntries();
 #if defined(DART_PRECOMPILER)
diff --git a/runtime/vm/raw_object.cc b/runtime/vm/raw_object.cc
index 624b55b..15b17fd 100644
--- a/runtime/vm/raw_object.cc
+++ b/runtime/vm/raw_object.cc
@@ -179,7 +179,7 @@
     case kCompressedStackMapsCid: {
       const RawCompressedStackMaps* maps =
           reinterpret_cast<const RawCompressedStackMaps*>(this);
-      intptr_t length = maps->ptr()->payload_size_;
+      intptr_t length = maps->ptr()->payload_size();
       instance_size = CompressedStackMaps::InstanceSize(length);
       break;
     }
@@ -216,9 +216,9 @@
 #if defined(DEBUG)
       auto class_table = isolate->shared_class_table();
 #if !defined(DART_PRECOMPILED_RUNTIME)
-      auto reload_context = isolate->reload_context();
+      auto reload_context = isolate->group()->reload_context();
       const bool use_saved_class_table =
-          reload_context != nullptr ? reload_context->UseSavedClassTableForGC()
+          reload_context != nullptr ? reload_context->UseSavedSizeTableForGC()
                                     : false;
 #else
       const bool use_saved_class_table = false;
@@ -532,7 +532,7 @@
 VARIABLE_NULL_VISITOR(Instructions, Instructions::Size(raw_obj))
 VARIABLE_NULL_VISITOR(PcDescriptors, raw_obj->ptr()->length_)
 VARIABLE_NULL_VISITOR(CodeSourceMap, raw_obj->ptr()->length_)
-VARIABLE_NULL_VISITOR(CompressedStackMaps, raw_obj->ptr()->payload_size_)
+VARIABLE_NULL_VISITOR(CompressedStackMaps, raw_obj->ptr()->payload_size())
 VARIABLE_NULL_VISITOR(OneByteString, Smi::Value(raw_obj->ptr()->length_))
 VARIABLE_NULL_VISITOR(TwoByteString, Smi::Value(raw_obj->ptr()->length_))
 // Abstract types don't have their visitor called.
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index d3dd8b9..23d384a 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -16,7 +16,6 @@
 #include "vm/compiler/runtime_api.h"
 #include "vm/exceptions.h"
 #include "vm/globals.h"
-#include "vm/object_graph.h"
 #include "vm/pointer_tagging.h"
 #include "vm/snapshot.h"
 #include "vm/token.h"
@@ -1153,7 +1152,6 @@
   RawArray* compile_time_constants_;
   RawTypedData* line_starts_;
   RawArray* debug_positions_;
-  RawArray* yield_positions_;
   RawKernelProgramInfo* kernel_program_info_;
   RawString* source_;
   VISIT_TO(RawObject*, source_);
@@ -1349,10 +1347,11 @@
   RawObject* owner_;  // Function, Null, or a Class.
   RawExceptionHandlers* exception_handlers_;
   RawPcDescriptors* pc_descriptors_;
-  union {
-    RawTypedData* catch_entry_moves_maps_;
-    RawSmi* variables_;
-  } catch_entry_;
+  // If FLAG_precompiled_mode, then this field contains
+  //   RawTypedData* catch_entry_moves_maps
+  // Otherwise, it is
+  //   RawSmi* num_variables
+  RawObject* catch_entry_;
   RawCompressedStackMaps* compressed_stackmaps_;
   RawArray* inlined_id_to_function_;
   RawCodeSourceMap* code_source_map_;
@@ -1520,25 +1519,42 @@
   static const char* KindToCString(Kind k);
   static bool ParseKind(const char* cstr, Kind* out);
 
-  class MergedKindTry {
+  // Used to represent the absense of a yield index in PcDescriptors.
+  static constexpr intptr_t kInvalidYieldIndex = -1;
+
+  class KindAndMetadata {
    public:
     // Most of the time try_index will be small and merged field will fit into
     // one byte.
-    static int32_t Encode(intptr_t kind, intptr_t try_index) {
-      intptr_t kind_shift = Utils::ShiftForPowerOfTwo(kind);
+    static int32_t Encode(intptr_t kind,
+                          intptr_t try_index,
+                          intptr_t yield_index) {
+      const intptr_t kind_shift = Utils::ShiftForPowerOfTwo(kind);
       ASSERT(Utils::IsUint(kKindShiftSize, kind_shift));
       ASSERT(Utils::IsInt(kTryIndexSize, try_index));
-      return (try_index << kTryIndexPos) | (kind_shift << kKindShiftPos);
+      ASSERT(Utils::IsInt(kYieldIndexSize, yield_index));
+      return (yield_index << kYieldIndexPos) | (try_index << kTryIndexPos) |
+             (kind_shift << kKindShiftPos);
     }
 
-    static intptr_t DecodeKind(int32_t merged_kind_try) {
+    static intptr_t DecodeKind(int32_t kind_and_metadata) {
       const intptr_t kKindShiftMask = (1 << kKindShiftSize) - 1;
-      return 1 << (merged_kind_try & kKindShiftMask);
+      return 1 << (kind_and_metadata & kKindShiftMask);
     }
 
-    static intptr_t DecodeTryIndex(int32_t merged_kind_try) {
+    static intptr_t DecodeTryIndex(int32_t kind_and_metadata) {
       // Arithmetic shift.
-      return merged_kind_try >> kTryIndexPos;
+      return static_cast<int32_t>(static_cast<uint32_t>(kind_and_metadata)
+                                  << (32 - (kTryIndexPos + kTryIndexSize))) >>
+             (32 - kTryIndexSize);
+    }
+
+    static intptr_t DecodeYieldIndex(int32_t kind_and_metadata) {
+      // Arithmetic shift.
+      return static_cast<int32_t>(
+                 static_cast<uint32_t>(kind_and_metadata)
+                 << (32 - (kYieldIndexPos + kYieldIndexSize))) >>
+             (32 - kYieldIndexSize);
     }
 
    private:
@@ -1547,8 +1563,13 @@
     // Is kKindShiftSize enough bits?
     COMPILE_ASSERT(kLastKind <= 1 << ((1 << kKindShiftSize) - 1));
 
-    static const intptr_t kTryIndexPos = kKindShiftSize;
-    static const intptr_t kTryIndexSize = 32 - kKindShiftSize;
+    static const intptr_t kTryIndexPos = kKindShiftPos + kKindShiftSize;
+    static const intptr_t kTryIndexSize = 10;
+
+    static const intptr_t kYieldIndexPos = kTryIndexPos + kTryIndexSize;
+    static const intptr_t kYieldIndexSize = 32 - kYieldIndexPos;
+
+    COMPILE_ASSERT((kYieldIndexPos + kYieldIndexSize) == 32);
   };
 
  private:
@@ -1594,31 +1615,75 @@
   RAW_HEAP_OBJECT_IMPLEMENTATION(CompressedStackMaps);
   VISIT_NOTHING();
 
-  uint32_t payload_size_;  // Length of the encoded payload, in bytes.
+  // The most significant bits are the length of the encoded payload, in bytes.
+  // The low bits determine the expected payload contents, as described below.
+  uint32_t flags_and_size_;
 
-  // Variable length data follows here. The payload consists of entries with
-  // the following information:
+  // Variable length data follows here. There are three types of
+  // CompressedStackMaps (CSM):
   //
-  // * A header containing the following three pieces of information:
-  //   * An unsigned integer representing the PC offset as a delta from the
-  //     PC offset of the previous entry (from 0 for the first entry).
-  //   * An unsigned integer representing the number of bits used for
-  //     register entries.
-  //   * An unsigned integer representing the number of bits used for spill
-  //     slot entries.
-  // * The body containing the bits for the stack map. The length of the body
-  //   in bits is the sum of the register and spill slot bit counts.
+  // 1) kind == kInlined: CSMs that include all information about the stack
+  //    maps. The payload for these contain tightly packed entries with the
+  //    following information:
   //
-  // Each unsigned integer is LEB128 encoded, as generally they tend to fit in
-  // a single byte or two. Thus, entry headers are not a fixed length, and
-  // currently there is no random access of entries.  In addition, PC offsets
-  // are currently encoded as deltas, which also inhibits random access without
-  // accessing previous entries. That means to find an entry for a given PC
-  // offset, a linear search must be done where the payload is decoded
-  // up to the entry whose PC offset is >= the given PC.
+  //   * A header containing the following three pieces of information:
+  //     * An unsigned integer representing the PC offset as a delta from the
+  //       PC offset of the previous entry (from 0 for the first entry).
+  //     * An unsigned integer representing the number of bits used for
+  //       spill slot entries.
+  //     * An unsigned integer representing the number of bits used for other
+  //       entries.
+  //   * The body containing the bits for the stack map. The length of the body
+  //     in bits is the sum of the spill slot and non-spill slot bit counts.
+  //
+  // 2) kind == kUsesTable: CSMs where the majority of the stack map information
+  //    has been offloaded and canonicalized into a global table. The payload
+  //    contains tightly packed entries with the following information:
+  //
+  //   * A header containing just an unsigned integer representing the PC offset
+  //     delta as described above.
+  //   * The body is just an unsigned integer containing the offset into the
+  //     payload for the global table.
+  //
+  // 3) kind == kGlobalTable: A CSM implementing the global table. Here, the
+  //    payload contains tightly packed entries with the following information:
+  //   * A header containing the following two pieces of information:
+  //     * An unsigned integer representing the number of bits used for
+  //       spill slot entries.
+  //     * An unsigned integer representing the number of bits used for other
+  //       entries.
+  //   * The body containing the bits for the stack map. The length of the body
+  //     in bits is the sum of the spill slot and non-spill slot bit counts.
+  //
+  // In all types of CSM, each unsigned integer is LEB128 encoded, as generally
+  // they tend to fit in a single byte or two. Thus, entry headers are not a
+  // fixed length, and currently there is no random access of entries.  In
+  // addition, PC offsets are currently encoded as deltas, which also inhibits
+  // random access without accessing previous entries. That means to find an
+  // entry for a given PC offset, a linear search must be done where the payload
+  // is decoded up to the entry whose PC offset is >= the given PC.
+
   uint8_t* data() { OPEN_ARRAY_START(uint8_t, uint8_t); }
   const uint8_t* data() const { OPEN_ARRAY_START(uint8_t, uint8_t); }
 
+  enum Kind {
+    kInlined = 0b00,
+    kUsesTable = 0b01,
+    kGlobalTable = 0b10,
+  };
+
+  static const uintptr_t kKindBits = 2;
+  using KindField = BitField<uint32_t, Kind, 0, kKindBits>;
+  using SizeField = BitField<uint32_t, uint32_t, kKindBits, 32 - kKindBits>;
+
+  uint32_t payload_size() const { return SizeField::decode(flags_and_size_); }
+  bool UsesGlobalTable() const {
+    return KindField::decode(flags_and_size_) == kUsesTable;
+  }
+  bool IsGlobalTable() const {
+    return KindField::decode(flags_and_size_) == kGlobalTable;
+  }
+
   friend class ImageWriter;
 };
 
@@ -2519,6 +2584,10 @@
 
   // False for pre-allocated stack trace (used in OOM and Stack overflow).
   bool expand_inlined_;
+  // Whether the link between the stack and the async-link represents a
+  // synchronous start to an asynchronous function. In this case, we omit the
+  // <asynchronous suspension> marker when concatenating the stacks.
+  bool skip_sync_start_in_parent_stack;
 };
 
 // VM type for capturing JS regular expressions.
diff --git a/runtime/vm/raw_object_fields.cc b/runtime/vm/raw_object_fields.cc
index c818091..079cbe7 100644
--- a/runtime/vm/raw_object_fields.cc
+++ b/runtime/vm/raw_object_fields.cc
@@ -61,7 +61,6 @@
   F(Script, compile_time_constants_)                                           \
   F(Script, line_starts_)                                                      \
   F(Script, debug_positions_)                                                  \
-  F(Script, yield_positions_)                                                  \
   F(Script, kernel_program_info_)                                              \
   F(Script, source_)                                                           \
   F(Library, name_)                                                            \
@@ -99,6 +98,7 @@
   F(Code, owner_)                                                              \
   F(Code, exception_handlers_)                                                 \
   F(Code, pc_descriptors_)                                                     \
+  F(Code, catch_entry_)                                                        \
   F(Code, compressed_stackmaps_)                                               \
   F(Code, inlined_id_to_function_)                                             \
   F(Code, code_source_map_)                                                    \
diff --git a/runtime/vm/resolver.cc b/runtime/vm/resolver.cc
index 9dec549..82dadf3 100644
--- a/runtime/vm/resolver.cc
+++ b/runtime/vm/resolver.cc
@@ -42,7 +42,8 @@
       zone,
       ResolveDynamicAnyArgs(zone, receiver_class, function_name, allow_add));
 
-  if (function.IsNull() || !function.AreValidArguments(args_desc, NULL)) {
+  if (function.IsNull() ||
+      !function.AreValidArguments(NNBDMode::kLegacy, args_desc, NULL)) {
     // Return a null function to signal to the upper levels to dispatch to
     // "noSuchMethod" function.
     if (FLAG_trace_resolving) {
@@ -50,7 +51,8 @@
           String::Handle(zone, Symbols::New(thread, "function not found"));
       if (!function.IsNull()) {
         // Obtain more detailed error message.
-        function.AreValidArguments(args_desc, &error_message);
+        function.AreValidArguments(NNBDMode::kLegacy, args_desc,
+                                   &error_message);
       }
       THR_Print("ResolveDynamic error '%s': %s.\n", function_name.ToCString(),
                 error_message.ToCString());
@@ -149,13 +151,14 @@
     const Object& object = Object::Handle(library.ResolveName(function_name));
     if (!object.IsNull() && object.IsFunction()) {
       function ^= object.raw();
-      if (!function.AreValidArguments(type_args_len, num_arguments,
-                                      argument_names, NULL)) {
+      if (!function.AreValidArguments(NNBDMode::kLegacy, type_args_len,
+                                      num_arguments, argument_names, NULL)) {
         if (FLAG_trace_resolving) {
           String& error_message = String::Handle();
           // Obtain more detailed error message.
-          function.AreValidArguments(type_args_len, num_arguments,
-                                     argument_names, &error_message);
+          function.AreValidArguments(NNBDMode::kLegacy, type_args_len,
+                                     num_arguments, argument_names,
+                                     &error_message);
           THR_Print("ResolveStatic error '%s': %s.\n",
                     function_name.ToCString(), error_message.ToCString());
         }
@@ -196,15 +199,16 @@
   const Function& function =
       Function::Handle(cls.LookupStaticFunction(function_name));
   if (function.IsNull() ||
-      !function.AreValidArguments(type_args_len, num_arguments, argument_names,
-                                  NULL)) {
+      !function.AreValidArguments(NNBDMode::kLegacy, type_args_len,
+                                  num_arguments, argument_names, NULL)) {
     // Return a null function to signal to the upper levels to throw a
     // resolution error or maybe throw the error right here.
     if (FLAG_trace_resolving) {
       String& error_message = String::Handle(String::New("function not found"));
       if (!function.IsNull()) {
         // Obtain more detailed error message.
-        function.AreValidArguments(type_args_len, num_arguments, argument_names,
+        function.AreValidArguments(NNBDMode::kLegacy, type_args_len,
+                                   num_arguments, argument_names,
                                    &error_message);
       }
       THR_Print("ResolveStatic error '%s': %s.\n", function_name.ToCString(),
@@ -227,15 +231,16 @@
   const Function& function =
       Function::Handle(cls.LookupStaticFunctionAllowPrivate(function_name));
   if (function.IsNull() ||
-      !function.AreValidArguments(type_args_len, num_arguments, argument_names,
-                                  NULL)) {
+      !function.AreValidArguments(NNBDMode::kLegacy, type_args_len,
+                                  num_arguments, argument_names, NULL)) {
     // Return a null function to signal to the upper levels to throw a
     // resolution error or maybe throw the error right here.
     if (FLAG_trace_resolving) {
       String& error_message = String::Handle(String::New("function not found"));
       if (!function.IsNull()) {
         // Obtain more detailed error message.
-        function.AreValidArguments(type_args_len, num_arguments, argument_names,
+        function.AreValidArguments(NNBDMode::kLegacy, type_args_len,
+                                   num_arguments, argument_names,
                                    &error_message);
       }
       THR_Print("ResolveStaticAllowPrivate error '%s': %s.\n",
diff --git a/runtime/vm/runtime_entry.cc b/runtime/vm/runtime_entry.cc
index 1bca9a1..076e818 100644
--- a/runtime/vm/runtime_entry.cc
+++ b/runtime/vm/runtime_entry.cc
@@ -385,8 +385,8 @@
   ASSERT(function_type_arguments.IsNull() ||
          function_type_arguments.IsInstantiated());
   type =
-      type.InstantiateFrom(instantiator_type_arguments, function_type_arguments,
-                           kAllFree, NULL, Heap::kOld);
+      type.InstantiateFrom(NNBDMode::kLegacy, instantiator_type_arguments,
+                           function_type_arguments, kAllFree, NULL, Heap::kOld);
   if (type.IsTypeRef()) {
     type = TypeRef::Cast(type).type();
     ASSERT(!type.IsTypeRef());
@@ -417,7 +417,7 @@
   // instantiator can be reused as type argument vector.
   ASSERT(!type_arguments.IsUninstantiatedIdentity());
   type_arguments = type_arguments.InstantiateAndCanonicalizeFrom(
-      instantiator_type_arguments, function_type_arguments);
+      NNBDMode::kLegacy, instantiator_type_arguments, function_type_arguments);
   ASSERT(type_arguments.IsNull() || type_arguments.IsInstantiated());
   arguments.SetReturn(type_arguments);
 }
@@ -444,7 +444,8 @@
 
   // The supertype or subtype may not be instantiated.
   if (AbstractType::InstantiateAndTestSubtype(
-          &subtype, &supertype, instantiator_type_args, function_type_args)) {
+          NNBDMode::kLegacy, &subtype, &supertype, instantiator_type_args,
+          function_type_args)) {
     return;
   }
 
@@ -537,7 +538,8 @@
   do {
     call_function = cls.LookupDynamicFunction(Symbols::Call());
     if (!call_function.IsNull()) {
-      if (!call_function.AreValidArguments(args_desc, NULL)) {
+      if (!call_function.AreValidArguments(NNBDMode::kLegacy, args_desc,
+                                           NULL)) {
         call_function = Function::null();
       }
       break;
@@ -573,9 +575,9 @@
   } else {
     // Instantiate type before printing.
     const AbstractType& instantiated_type =
-        AbstractType::Handle(type.InstantiateFrom(instantiator_type_arguments,
-                                                  function_type_arguments,
-                                                  kAllFree, NULL, Heap::kOld));
+        AbstractType::Handle(type.InstantiateFrom(
+            NNBDMode::kLegacy, instantiator_type_arguments,
+            function_type_arguments, kAllFree, NULL, Heap::kOld));
     OS::PrintErr("%s: '%s' %s '%s' instantiated from '%s' (pc: %#" Px ").\n",
                  message, String::Handle(instance_type.Name()).ToCString(),
                  (result.raw() == Bool::True().raw()) ? "is" : "is !",
@@ -698,9 +700,9 @@
   if (FLAG_trace_type_checks) {
     AbstractType& test_type = AbstractType::Handle(zone, type.raw());
     if (!test_type.IsInstantiated()) {
-      test_type = type.InstantiateFrom(instantiator_type_arguments,
-                                       function_type_arguments, kAllFree, NULL,
-                                       Heap::kNew);
+      test_type = type.InstantiateFrom(
+          NNBDMode::kLegacy, instantiator_type_arguments,
+          function_type_arguments, kAllFree, NULL, Heap::kNew);
     }
     const auto& type_class = Class::Handle(zone, test_type.type_class());
     const auto& instance_class_name =
@@ -751,7 +753,8 @@
   ASSERT(type.IsFinalized());
   ASSERT(!type.IsDynamicType());  // No need to check assignment.
   const Bool& result = Bool::Get(instance.IsInstanceOf(
-      type, instantiator_type_arguments, function_type_arguments));
+      NNBDMode::kLegacy, type, instantiator_type_arguments,
+      function_type_arguments));
   if (FLAG_trace_type_checks) {
     PrintTypeCheck("InstanceOf", instance, type, instantiator_type_arguments,
                    function_type_arguments, result);
@@ -800,7 +803,8 @@
   ASSERT(!src_instance.IsNull());     // Already checked in inlined code.
 
   const bool is_instance_of = src_instance.IsInstanceOf(
-      dst_type, instantiator_type_arguments, function_type_arguments);
+      NNBDMode::kLegacy, dst_type, instantiator_type_arguments,
+      function_type_arguments);
 
   if (FLAG_trace_type_checks) {
     PrintTypeCheck("TypeCheck", src_instance, dst_type,
@@ -814,9 +818,9 @@
         AbstractType::Handle(zone, src_instance.GetType(Heap::kNew));
     if (!dst_type.IsInstantiated()) {
       // Instantiate dst_type before reporting the error.
-      dst_type = dst_type.InstantiateFrom(instantiator_type_arguments,
-                                          function_type_arguments, kAllFree,
-                                          NULL, Heap::kNew);
+      dst_type = dst_type.InstantiateFrom(
+          NNBDMode::kLegacy, instantiator_type_arguments,
+          function_type_arguments, kAllFree, NULL, Heap::kNew);
       // Note that instantiated dst_type may be malbounded.
     }
     if (dst_name.IsNull()) {
@@ -1221,7 +1225,8 @@
 static RawFunction* ComputeTypeCheckTarget(const Instance& receiver,
                                            const AbstractType& type,
                                            const ArgumentsDescriptor& desc) {
-  bool result = receiver.IsInstanceOf(type, Object::null_type_arguments(),
+  bool result = receiver.IsInstanceOf(NNBDMode::kLegacy, type,
+                                      Object::null_type_arguments(),
                                       Object::null_type_arguments());
   ObjectStore* store = Isolate::Current()->object_store();
   const Function& target =
@@ -2086,7 +2091,7 @@
     while (!cls.IsNull()) {
       function = cls.LookupDynamicFunction(target_name);
       if (!function.IsNull()) {
-        ASSERT(!function.AreValidArguments(args_desc, NULL));
+        ASSERT(!function.AreValidArguments(NNBDMode::kLegacy, args_desc, NULL));
         break;  // mismatch, invoke noSuchMethod
       }
       function = cls.LookupDynamicFunction(getter_name);
@@ -2281,8 +2286,8 @@
     }
 
     // Issue a reload.
-    bool success =
-        isolate->ReloadSources(&js, true /* force_reload */, script_uri);
+    bool success = isolate->group()->ReloadSources(&js, true /* force_reload */,
+                                                   script_uri);
     if (!success) {
       FATAL1("*** Isolate reload failed:\n%s\n", js.ToCString());
     }
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index 69eec8e..a90b073 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -3201,12 +3201,15 @@
     return true;
   }
 
-  Isolate* isolate = thread->isolate();
-  if (!isolate->HasTagHandler()) {
+  IsolateGroup* isolate_group = thread->isolate_group();
+  if (isolate_group->library_tag_handler() == nullptr) {
     js->PrintError(kFeatureDisabled,
                    "A library tag handler must be installed.");
     return true;
   }
+  // TODO(dartbug.com/36097): We need to change the "reloadSources" service-api
+  // call to accept an isolate group instead of an isolate.
+  Isolate* isolate = thread->isolate();
   if ((isolate->sticky_error() != Error::null()) ||
       (Thread::Current()->sticky_error() != Error::null())) {
     js->PrintError(kIsolateReloadBarred,
@@ -3214,7 +3217,7 @@
                    "was an unhandled exception error. Restart the isolate.");
     return true;
   }
-  if (isolate->IsReloading()) {
+  if (isolate_group->IsReloading()) {
     js->PrintError(kIsolateIsReloading, "This isolate is being reloaded.");
     return true;
   }
@@ -3226,8 +3229,8 @@
   const bool force_reload =
       BoolParameter::Parse(js->LookupParam("force"), false);
 
-  isolate->ReloadSources(js, force_reload, js->LookupParam("rootLibUri"),
-                         js->LookupParam("packagesUri"));
+  isolate_group->ReloadSources(js, force_reload, js->LookupParam("rootLibUri"),
+                               js->LookupParam("packagesUri"));
 
   Service::CheckForPause(isolate, js);
 
@@ -3961,7 +3964,6 @@
   Isolate* isolate = thread->isolate();
   if (should_reset_accumulator) {
     isolate->UpdateLastAllocationProfileAccumulatorResetTimestamp();
-    isolate->shared_class_table()->ResetAllocationAccumulators();
   }
   if (should_collect) {
     isolate->UpdateLastAllocationProfileGCTimestamp();
diff --git a/runtime/vm/service.h b/runtime/vm/service.h
index f283627..f2ca26a 100644
--- a/runtime/vm/service.h
+++ b/runtime/vm/service.h
@@ -8,7 +8,6 @@
 #include "include/dart_tools_api.h"
 
 #include "vm/allocation.h"
-#include "vm/object_graph.h"
 #include "vm/object_id_ring.h"
 #include "vm/os_thread.h"
 
diff --git a/runtime/vm/stack_frame.cc b/runtime/vm/stack_frame.cc
index b2ad52a..ec71428 100644
--- a/runtime/vm/stack_frame.cc
+++ b/runtime/vm/stack_frame.cc
@@ -276,7 +276,10 @@
     // on the stack map.
     CompressedStackMaps maps;
     maps = code.compressed_stackmaps();
-    CompressedStackMapsIterator it(maps);
+    CompressedStackMaps global_table;
+    global_table =
+        this->isolate()->object_store()->canonicalized_stack_map_entries();
+    CompressedStackMapsIterator it(maps, global_table);
     const uword start = Instructions::PayloadStart(code.instructions());
     const uint32_t pc_offset = pc() - start;
     if (it.Find(pc_offset)) {
@@ -299,7 +302,7 @@
       // of outgoing arguments is not explicitly tracked.
 
       // Spill slots are at the 'bottom' of the frame.
-      intptr_t spill_slot_count = it.spill_slot_bit_count();
+      intptr_t spill_slot_count = it.SpillSlotBitCount();
       for (intptr_t bit = 0; bit < spill_slot_count; ++bit) {
         if (it.IsObject(bit)) {
           visitor->VisitPointer(last);
@@ -309,7 +312,7 @@
 
       // The live registers at the 'top' of the frame comprise the rest of the
       // stack map.
-      for (intptr_t bit = it.length() - 1; bit >= spill_slot_count; --bit) {
+      for (intptr_t bit = it.Length() - 1; bit >= spill_slot_count; --bit) {
         if (it.IsObject(bit)) {
           visitor->VisitPointer(first);
         }
diff --git a/runtime/vm/stack_trace.cc b/runtime/vm/stack_trace.cc
index 17724a3..449c323 100644
--- a/runtime/vm/stack_trace.cc
+++ b/runtime/vm/stack_trace.cc
@@ -4,13 +4,15 @@
 
 #include "vm/stack_trace.h"
 #include "vm/stack_frame.h"
+#include "vm/symbols.h"
 
 namespace dart {
 
 // Count the number of frames that are on the stack.
 intptr_t StackTraceUtils::CountFrames(Thread* thread,
                                       int skip_frames,
-                                      const Function& async_function) {
+                                      const Function& async_function,
+                                      bool* sync_async_end) {
   Zone* zone = thread->zone();
   intptr_t frame_count = 0;
   StackFrameIterator frames(ValidationPolicy::kDontValidateFrames, thread,
@@ -20,8 +22,12 @@
   Function& function = Function::Handle(zone);
   Code& code = Code::Handle(zone);
   Bytecode& bytecode = Bytecode::Handle(zone);
+  String& function_name = String::Handle(zone);
   const bool async_function_is_null = async_function.IsNull();
-  for (; frame != NULL; frame = frames.NextFrame()) {
+  int sync_async_gap_frames = -1;
+  ASSERT(async_function_is_null || sync_async_end != NULL);
+  for (; frame != NULL && sync_async_gap_frames != 0;
+       frame = frames.NextFrame()) {
     if (!frame->IsDartFrame()) {
       continue;
     }
@@ -39,14 +45,23 @@
       code = frame->LookupDartCode();
       function = code.function();
     }
-    frame_count++;
+    if (sync_async_gap_frames > 0) {
+      function_name = function.QualifiedScrubbedName();
+      if (!CheckAndSkipAsync(&sync_async_gap_frames, function_name)) {
+        *sync_async_end = false;
+        return frame_count;
+      }
+    } else {
+      frame_count++;
+    }
     if (!async_function_is_null &&
         (async_function.raw() == function.parent_function())) {
-      return frame_count;
+      sync_async_gap_frames = kSyncAsyncFrameGap;
     }
   }
-  // We hit the sentinel.
-  ASSERT(async_function_is_null);
+  if (!async_function_is_null) {
+    *sync_async_end = sync_async_gap_frames == 0;
+  }
   return frame_count;
 }
 
diff --git a/runtime/vm/stack_trace.h b/runtime/vm/stack_trace.h
index 394f45b..ea4ed29 100644
--- a/runtime/vm/stack_trace.h
+++ b/runtime/vm/stack_trace.h
@@ -8,6 +8,7 @@
 #include "vm/allocation.h"
 #include "vm/flag_list.h"
 #include "vm/object.h"
+#include "vm/symbols.h"
 
 namespace dart {
 
@@ -16,10 +17,12 @@
   /// Counts the number of stack frames.
   /// Skips over the first |skip_frames|.
   /// If |async_function| is not null, stops at the function that has
-  /// |async_function| as its parent.
+  /// |async_function| as its parent, and records in 'sync_async_end' whether
+  /// |async_function| was called synchronously.
   static intptr_t CountFrames(Thread* thread,
                               int skip_frames,
-                              const Function& async_function);
+                              const Function& async_function,
+                              bool* sync_async_end);
 
   /// Collects |count| frames into |code_array| and |pc_offset_array|.
   /// Writing begins at |array_offset|.
@@ -42,6 +45,36 @@
                                              StackTrace* async_stack_trace,
                                              Array* async_code_array,
                                              Array* async_pc_offset_array);
+
+  // The number of frames involved in a "sync-async" gap: a synchronous initial
+  // invocation of an asynchronous function. See CheckAndSkipAsync.
+  static constexpr intptr_t kSyncAsyncFrameGap = 2;
+
+  // A synchronous invocation of an async function involves the following
+  // frames:
+  //   <async function>__<anonymous_closure>    (0)
+  //   _Closure.call                            (1)
+  //   _AsyncAwaitCompleter.start               (2)
+  //   <async_function>                         (3)
+  //
+  // Alternatively, for bytecode or optimized frames, we may see:
+  //   <async function>__<anonymous_closure>    (0)
+  //   _AsyncAwaitCompleter.start               (1)
+  //   <async_function>                         (2)
+  static bool CheckAndSkipAsync(int* skip_sync_async_frames_count,
+                                const String& function_name) {
+    ASSERT(*skip_sync_async_frames_count > 0);
+    if (function_name.Equals(Symbols::_AsyncAwaitCompleterStart())) {
+      *skip_sync_async_frames_count = 0;
+      return true;
+    }
+    if (function_name.Equals(Symbols::_ClosureCall()) &&
+        *skip_sync_async_frames_count == 2) {
+      (*skip_sync_async_frames_count)--;
+      return true;
+    }
+    return false;
+  }
 };
 
 }  // namespace dart
diff --git a/runtime/vm/stub_code.cc b/runtime/vm/stub_code.cc
index 739e4fd..98f20cf 100644
--- a/runtime/vm/stub_code.cc
+++ b/runtime/vm/stub_code.cc
@@ -25,8 +25,13 @@
 
 DECLARE_FLAG(bool, enable_interpreter);
 
-Code* StubCode::entries_[kNumStubEntries] = {
-#define STUB_CODE_DECLARE(name) nullptr,
+StubCode::StubCodeEntry StubCode::entries_[kNumStubEntries] = {
+#if defined(DART_PRECOMPILED_RUNTIME)
+#define STUB_CODE_DECLARE(name) {nullptr, #name},
+#else
+#define STUB_CODE_DECLARE(name)                                                \
+  {nullptr, #name, compiler::StubCodeCompiler::Generate##name##Stub},
+#endif
     VM_STUB_CODE_LIST(STUB_CODE_DECLARE)
 #undef STUB_CODE_DECLARE
 };
@@ -39,25 +44,22 @@
 
 #else
 
-#define STUB_CODE_GENERATE(name)                                               \
-  entries_[k##name##Index] = Code::ReadOnlyHandle();                           \
-  *entries_[k##name##Index] =                                                  \
-      Generate("_stub_" #name, &object_pool_builder,                           \
-               compiler::StubCodeCompiler::Generate##name##Stub);
-
-#define STUB_CODE_SET_OBJECT_POOL(name)                                        \
-  entries_[k##name##Index]->set_object_pool(object_pool.raw());
-
 void StubCode::Init() {
   compiler::ObjectPoolBuilder object_pool_builder;
 
   // Generate all the stubs.
-  VM_STUB_CODE_LIST(STUB_CODE_GENERATE);
+  for (size_t i = 0; i < ARRAY_SIZE(entries_); i++) {
+    entries_[i].code = Code::ReadOnlyHandle();
+    *(entries_[i].code) =
+        Generate(entries_[i].name, &object_pool_builder, entries_[i].generator);
+  }
 
   const ObjectPool& object_pool =
       ObjectPool::Handle(ObjectPool::NewFromBuilder(object_pool_builder));
 
-  VM_STUB_CODE_LIST(STUB_CODE_SET_OBJECT_POOL)
+  for (size_t i = 0; i < ARRAY_SIZE(entries_); i++) {
+    entries_[i].code->set_object_pool(object_pool.raw());
+  }
 }
 
 #undef STUB_CODE_GENERATE
@@ -74,32 +76,22 @@
       /*optimized=*/false));
 #ifndef PRODUCT
   if (FLAG_support_disassembler && FLAG_disassemble_stubs) {
-    LogBlock lb;
-    THR_Print("Code for stub '%s': {\n", name);
-    DisassembleToStdout formatter;
-    code.Disassemble(&formatter);
-    THR_Print("}\n");
-    const ObjectPool& object_pool = ObjectPool::Handle(code.object_pool());
-    if (!object_pool.IsNull()) {
-      object_pool.DebugPrint();
-    }
+    Disassembler::DisassembleStub(name, code);
   }
 #endif  // !PRODUCT
   return code.raw();
 }
 #endif  // defined(DART_PRECOMPILED_RUNTIME)
 
-#define STUB_CODE_CLEANUP(name) entries_[k##name##Index] = nullptr;
-
 void StubCode::Cleanup() {
-  VM_STUB_CODE_LIST(STUB_CODE_CLEANUP);
+  for (size_t i = 0; i < ARRAY_SIZE(entries_); i++) {
+    entries_[i].code = nullptr;
+  }
 }
 
-#undef STUB_CODE_CLEANUP
-
 bool StubCode::HasBeenInitialized() {
   // Use AsynchronousGapMarker as canary.
-  return entries_[kAsynchronousGapMarkerIndex] != nullptr;
+  return entries_[kAsynchronousGapMarkerIndex].code != nullptr;
 }
 
 bool StubCode::InInvocationStub(uword pc, bool is_interpreted_frame) {
@@ -199,15 +191,7 @@
     Code::NotifyCodeObservers(name, stub, /*optimized=*/false);
 #ifndef PRODUCT
     if (FLAG_support_disassembler && FLAG_disassemble_stubs) {
-      LogBlock lb;
-      THR_Print("Code for allocation stub '%s': {\n", name);
-      DisassembleToStdout formatter;
-      stub.Disassemble(&formatter);
-      THR_Print("}\n");
-      const ObjectPool& object_pool = ObjectPool::Handle(stub.object_pool());
-      if (!object_pool.IsNull()) {
-        object_pool.DebugPrint();
-      }
+      Disassembler::DisassembleStub(name, stub);
     }
 #endif  // !PRODUCT
   }
@@ -245,15 +229,7 @@
 
 #ifndef PRODUCT
   if (FLAG_support_disassembler && FLAG_disassemble_stubs) {
-    LogBlock lb;
-    THR_Print("Code for isolate stub '%s': {\n", name);
-    DisassembleToStdout formatter;
-    stub.Disassemble(&formatter);
-    THR_Print("}\n");
-    const ObjectPool& object_pool = ObjectPool::Handle(stub.object_pool());
-    if (!object_pool.IsNull()) {
-      object_pool.DebugPrint();
-    }
+    Disassembler::DisassembleStub(name, stub);
   }
 #endif  // !PRODUCT
   return stub.raw();
@@ -279,14 +255,12 @@
 }
 
 const char* StubCode::NameOfStub(uword entry_point) {
-#define VM_STUB_CODE_TESTER(name)                                              \
-  if (entries_[k##name##Index] != nullptr &&                                   \
-      !entries_[k##name##Index]->IsNull() &&                                   \
-      entries_[k##name##Index]->EntryPoint() == entry_point) {                 \
-    return "" #name;                                                           \
+  for (size_t i = 0; i < ARRAY_SIZE(entries_); i++) {
+    if ((entries_[i].code != nullptr) && !entries_[i].code->IsNull() &&
+        (entries_[i].code->EntryPoint() == entry_point)) {
+      return entries_[i].name;
+    }
   }
-  VM_STUB_CODE_LIST(VM_STUB_CODE_TESTER);
-#undef VM_STUB_CODE_TESTER
   return nullptr;
 }
 
diff --git a/runtime/vm/stub_code.h b/runtime/vm/stub_code.h
index cf832cb..db86482 100644
--- a/runtime/vm/stub_code.h
+++ b/runtime/vm/stub_code.h
@@ -22,6 +22,8 @@
 class SnapshotReader;
 class SnapshotWriter;
 
+DECLARE_FLAG(bool, disassemble_stubs);
+
 // Is it permitted for the stubs above to refer to Object::null(), which is
 // allocated in the VM isolate and shared across all isolates.
 // However, in cases where a simple GC-safe placeholder is needed on the stack,
@@ -52,7 +54,7 @@
 
 // Define the shared stub code accessors.
 #define STUB_CODE_ACCESSOR(name)                                               \
-  static const Code& name() { return *entries_[k##name##Index]; }              \
+  static const Code& name() { return *entries_[k##name##Index].code; }         \
   static intptr_t name##Size() { return name().Size(); }
   VM_STUB_CODE_LIST(STUB_CODE_ACCESSOR);
 #undef STUB_CODE_ACCESSOR
@@ -76,11 +78,11 @@
   static const intptr_t kNoInstantiator = 0;
   static const intptr_t kInstantiationSizeInWords = 3;
 
-  static const Code& EntryAt(intptr_t index) { return *entries_[index]; }
+  static const Code& EntryAt(intptr_t index) { return *(entries_[index].code); }
   static void EntryAtPut(intptr_t index, Code* entry) {
     ASSERT(entry->IsReadOnlyHandle());
-    ASSERT(entries_[index] == nullptr);
-    entries_[index] = entry;
+    ASSERT(entries_[index].code == nullptr);
+    entries_[index].code = entry;
   }
   static intptr_t NumEntries() { return kNumStubEntries; }
 
@@ -106,7 +108,14 @@
         kNumStubEntries
   };
 
-  static Code* entries_[kNumStubEntries];
+  struct StubCodeEntry {
+    Code* code;
+    const char* name;
+#if !defined(DART_PRECOMPILED_RUNTIME)
+    void (*generator)(compiler::Assembler* assembler);
+#endif
+  };
+  static StubCodeEntry entries_[kNumStubEntries];
 };
 
 }  // namespace dart
diff --git a/runtime/vm/symbols.cc b/runtime/vm/symbols.cc
index 3333c03..312e23b 100644
--- a/runtime/vm/symbols.cc
+++ b/runtime/vm/symbols.cc
@@ -382,7 +382,8 @@
       ASSERT(type.IsType());
       ASSERT(type.IsCanonical());
       bool present = table.Insert(type);
-      ASSERT(!present);
+      // Two recursive types with different topology (and hashes) may be equal.
+      ASSERT(!present || type.IsRecursive());
     }
     object_store->set_canonical_types(table.Release());
   }
@@ -397,7 +398,8 @@
       ASSERT(type_arg.IsTypeArguments());
       ASSERT(type_arg.IsCanonical());
       bool present = table.Insert(type_arg);
-      ASSERT(!present);
+      // Two recursive types with different topology (and hashes) may be equal.
+      ASSERT(!present || type_arg.IsRecursive());
     }
     object_store->set_canonical_type_arguments(table.Release());
   }
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index e9aa508..cb64951 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -580,6 +580,9 @@
   static const String& Percent() {
     return *(symbol_handles_[kNullCharId + '%']);
   }
+  static const String& QuestionMark() {
+    return *(symbol_handles_[kNullCharId + '?']);
+  }
   static const String& Caret() { return *(symbol_handles_[kNullCharId + '^']); }
   static const String& Tilde() { return *(symbol_handles_[kNullCharId + '~']); }
 
diff --git a/runtime/vm/thread.cc b/runtime/vm/thread.cc
index 2afc376..cd0dee8 100644
--- a/runtime/vm/thread.cc
+++ b/runtime/vm/thread.cc
@@ -514,7 +514,6 @@
       }
       heap()->CollectGarbage(Heap::kNew);
     }
-    heap()->CheckFinishConcurrentMarking(this);
   }
   if ((interrupt_bits & kMessageInterrupt) != 0) {
     MessageHandler::MessageStatus status =
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index 2469d30..3353213 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -173,6 +173,8 @@
 
 #define CACHED_ADDRESSES_LIST(V)                                               \
   CACHED_VM_STUBS_ADDRESSES_LIST(V)                                            \
+  V(uword, bootstrap_native_wrapper_entry_point_,                              \
+    NativeEntry::BootstrapNativeCallWrapperEntry(), 0)                         \
   V(uword, no_scope_native_wrapper_entry_point_,                               \
     NativeEntry::NoScopeNativeCallWrapperEntry(), 0)                           \
   V(uword, auto_scope_native_wrapper_entry_point_,                             \
diff --git a/runtime/vm/type_testing_stubs.cc b/runtime/vm/type_testing_stubs.cc
index eff9fd1..244974e 100644
--- a/runtime/vm/type_testing_stubs.cc
+++ b/runtime/vm/type_testing_stubs.cc
@@ -104,7 +104,7 @@
     return Code::null();
   }
 
-  // TODO(regis): Revisit when type checking mode is not kUnaware anymore.
+  // TODO(regis): Revisit when type checking mode is not kLegacy anymore.
   if (type.raw() == Type::ObjectType() || type.raw() == Type::DynamicType() ||
       type.raw() == Type::VoidType()) {
     return StubCode::TopTypeTypeTest().raw();
@@ -274,7 +274,8 @@
                                   /*exclude_null=*/false);
 
     const Type& int_type = Type::Handle(Type::IntType());
-    const bool smi_is_ok = int_type.IsSubtypeOf(type, Heap::kNew);
+    const bool smi_is_ok =
+        int_type.IsSubtypeOf(NNBDMode::kLegacy, type, Heap::kNew);
 
     BuildOptimizedSubtypeRangeCheck(assembler, ranges, class_id_reg,
                                     instance_reg, smi_is_ok);
diff --git a/runtime/vm/unit_test.cc b/runtime/vm/unit_test.cc
index 66addfe..e6b60bb 100644
--- a/runtime/vm/unit_test.cc
+++ b/runtime/vm/unit_test.cc
@@ -33,6 +33,9 @@
 
 namespace dart {
 
+DECLARE_FLAG(bool, gc_during_reload);
+DECLARE_FLAG(bool, force_evacuation);
+
 const uint8_t* platform_strong_dill = kPlatformStrongDill;
 const intptr_t platform_strong_dill_size = kPlatformStrongDillSize;
 
@@ -126,6 +129,7 @@
     OS::PrintErr("Creation of isolate failed '%s'\n", err);
     free(err);
   }
+
   EXPECT(isolate != NULL);
   return isolate;
 }
@@ -139,6 +143,20 @@
                        group_data, isolate_data);
 }
 
+void SetupCoreLibrariesForUnitTest() {
+  TransitionVMToNative transition(Thread::Current());
+
+  Dart_EnterScope();
+  bool ok = bin::DartUtils::SetOriginalWorkingDirectory();
+  RELEASE_ASSERT(ok);
+  Dart_Handle result = bin::DartUtils::PrepareForScriptLoading(
+      /*is_service_isolate=*/false,
+      /*trace_loading=*/false);
+  Dart_ExitScope();
+
+  RELEASE_ASSERT(!Dart_IsError(result));
+}
+
 static const char* kPackageScheme = "package:";
 
 static bool IsPackageSchemeURL(const char* url_name) {
@@ -558,17 +576,22 @@
 #ifndef PRODUCT
 
 Dart_Handle TestCase::SetReloadTestScript(const char* script) {
-    Dart_SourceFile* sourcefiles = NULL;
-    intptr_t num_files = BuildSourceFilesArray(&sourcefiles, script);
-    Dart_KernelCompilationResult compilation_result =
-        KernelIsolate::UpdateInMemorySources(num_files, sourcefiles);
-    delete[] sourcefiles;
-    if (compilation_result.status != Dart_KernelCompilationStatus_Ok) {
-      Dart_Handle result = Dart_NewApiError(compilation_result.error);
-      free(compilation_result.error);
-      return result;
-    }
-    return Api::Success();
+  // For our vm/cc/IsolateReload_* tests we flip the GC flag on, which will
+  // cause the isolate reload to do GCs before/after morphing, etc.
+  FLAG_gc_during_reload = true;
+  FLAG_force_evacuation = true;
+
+  Dart_SourceFile* sourcefiles = NULL;
+  intptr_t num_files = BuildSourceFilesArray(&sourcefiles, script);
+  Dart_KernelCompilationResult compilation_result =
+      KernelIsolate::UpdateInMemorySources(num_files, sourcefiles);
+  delete[] sourcefiles;
+  if (compilation_result.status != Dart_KernelCompilationStatus_Ok) {
+    Dart_Handle result = Dart_NewApiError(compilation_result.error);
+    free(compilation_result.error);
+    return result;
+  }
+  return Api::Success();
 }
 
 Dart_Handle TestCase::TriggerReload(const uint8_t* kernel_buffer,
@@ -579,10 +602,11 @@
   bool success = false;
   {
     TransitionNativeToVM transition(thread);
-    success = isolate->ReloadKernel(&js,
-                                    false,  // force_reload
-                                    kernel_buffer, kernel_buffer_size,
-                                    true);  // dont_delete_reload_context
+    success =
+        isolate->group()->ReloadKernel(&js,
+                                       false,  // force_reload
+                                       kernel_buffer, kernel_buffer_size,
+                                       true);  // dont_delete_reload_context
     OS::PrintErr("RELOAD REPORT:\n%s\n", js.ToCString());
   }
 
@@ -593,9 +617,10 @@
 
   if (Dart_IsError(result)) {
     // Keep load error.
-  } else if (isolate->reload_context()->reload_aborted()) {
+  } else if (isolate->group()->reload_context()->reload_aborted()) {
     TransitionNativeToVM transition(thread);
-    result = Api::NewHandle(thread, isolate->reload_context()->error());
+    result = Api::NewHandle(
+        thread, isolate->reload_context()->group_reload_context()->error());
   } else {
     result = Dart_RootLibrary();
   }
@@ -603,6 +628,7 @@
   TransitionNativeToVM transition(thread);
   if (isolate->reload_context() != NULL) {
     isolate->DeleteReloadContext();
+    isolate->group()->DeleteReloadContext();
   }
 
   return result;
diff --git a/runtime/vm/unit_test.h b/runtime/vm/unit_test.h
index 947cd15..0d134cd 100644
--- a/runtime/vm/unit_test.h
+++ b/runtime/vm/unit_test.h
@@ -440,6 +440,10 @@
   DISALLOW_COPY_AND_ASSIGN(TestIsolateScope);
 };
 
+// Ensures core libraries are initialized, thereby allowing vm/cc tests to
+// e.g. run functions using microtasks.
+void SetupCoreLibrariesForUnitTest();
+
 template <typename T>
 struct is_void {
   static const bool value = false;
diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn
index e637088..33fa0b4 100644
--- a/sdk/BUILD.gn
+++ b/sdk/BUILD.gn
@@ -690,14 +690,14 @@
   visibility = [ ":copy_dev_compiler_sdk" ]
   deps = [
     ":copy_libraries",
-    "../utils/dartdevc:dartdevc_kernel_sdk_outline",
+    "../utils/dartdevc:dartdevc_platform",
     "../utils/dartdevc:dartdevc_sdk",
   ]
   gen_dir = get_label_info("../utils/dartdevc:dartdevc_sdk", "target_gen_dir")
   sources = [
     # TODO(vsm): Remove post CFE.
     "$gen_dir/ddc_sdk.sum",
-    "$gen_dir/kernel/ddc_sdk.dill",
+    "$root_out_dir/ddc_sdk.dill",
   ]
   outputs = [
     "$root_out_dir/dart-sdk/lib/_internal/{{source_file_part}}",
diff --git a/sdk/lib/_http/crypto.dart b/sdk/lib/_http/crypto.dart
index 28b65ee..73f3745 100644
--- a/sdk/lib/_http/crypto.dart
+++ b/sdk/lib/_http/crypto.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.
 
+// @dart = 2.6
+
 part of dart._http;
 
 class _CryptoUtils {
diff --git a/sdk/lib/_http/http.dart b/sdk/lib/_http/http.dart
index 2fc751f..855234b 100644
--- a/sdk/lib/_http/http.dart
+++ b/sdk/lib/_http/http.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.
 
+// @dart = 2.6
+
 library dart._http;
 
 import 'dart:async';
@@ -126,8 +128,8 @@
  * about the streaming qualities of an HttpServer.
  * Pausing the subscription of the stream, pauses at the OS level.
  *
- * * The [shelf](https://pub.dartlang.org/packages/shelf)
- * package on pub.dartlang.org contains a set of high-level classes that,
+ * * The [shelf](https://pub.dev/packages/shelf)
+ * package on pub.dev contains a set of high-level classes that,
  * together with this class, makes it easy to provide content through HTTP
  * servers.
  */
@@ -1006,7 +1008,7 @@
  * that contains the content of and information about an HTTP request.
  *
  * __Note__: Check out the
- * [http_server](https://pub.dartlang.org/packages/http_server)
+ * [http_server](https://pub.dev/packages/http_server)
  * package, which makes working with the low-level
  * dart:io HTTP server subsystem easier.
  *
@@ -1402,6 +1404,22 @@
   @Deprecated("Use defaultHttpsPort instead")
   static const int DEFAULT_HTTPS_PORT = defaultHttpsPort;
 
+  /// Enable logging of HTTP requests from all [HttpClient]s to the developer
+  /// timeline.
+  ///
+  /// Default is `false`.
+  static set enableTimelineLogging(bool value) {
+    _enableTimelineLogging = value ?? false;
+  }
+
+  /// Current state of HTTP request logging from all [HttpClient]s to the
+  /// developer timeline.
+  ///
+  /// Default is `false`.
+  static bool get enableTimelineLogging => _enableTimelineLogging;
+
+  static bool _enableTimelineLogging = false;
+
   /// Gets and sets the idle timeout of non-active persistent (keep-alive)
   /// connections.
   ///
diff --git a/sdk/lib/_http/http_date.dart b/sdk/lib/_http/http_date.dart
index d9301b4..edeb98f 100644
--- a/sdk/lib/_http/http_date.dart
+++ b/sdk/lib/_http/http_date.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.
 
+// @dart = 2.6
+
 part of dart._http;
 
 /**
diff --git a/sdk/lib/_http/http_headers.dart b/sdk/lib/_http/http_headers.dart
index d452315..028fd2d 100644
--- a/sdk/lib/_http/http_headers.dart
+++ b/sdk/lib/_http/http_headers.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.
 
+// @dart = 2.6
+
 part of dart._http;
 
 class _HttpHeaders implements HttpHeaders {
diff --git a/sdk/lib/_http/http_impl.dart b/sdk/lib/_http/http_impl.dart
index 46611c0..323ea9b 100644
--- a/sdk/lib/_http/http_impl.dart
+++ b/sdk/lib/_http/http_impl.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.
 
+// @dart = 2.6
+
 part of dart._http;
 
 int _nextServiceId = 1;
@@ -443,7 +445,9 @@
   }
 
   Future<HttpClientResponse> _authenticate(bool proxyAuth) {
+    _httpRequest._timeline?.instant('Authentication');
     Future<HttpClientResponse> retry() {
+      _httpRequest._timeline?.instant('Retrying');
       // Drain body and retry.
       return drain().then((_) {
         return _httpClient
@@ -1062,6 +1066,7 @@
   // The HttpClient this request belongs to.
   final _HttpClient _httpClient;
   final _HttpClientConnection _httpClientConnection;
+  final TimelineTask _timeline;
 
   final Completer<HttpClientResponse> _responseCompleter =
       new Completer<HttpClientResponse>();
@@ -1078,15 +1083,61 @@
   List<RedirectInfo> _responseRedirects = [];
 
   _HttpClientRequest(_HttpOutgoing outgoing, Uri uri, this.method, this._proxy,
-      this._httpClient, this._httpClientConnection)
+      this._httpClient, this._httpClientConnection, this._timeline)
       : uri = uri,
         super(uri, "1.1", outgoing) {
+    _timeline?.instant('Request initiated');
     // GET and HEAD have 'content-length: 0' by default.
     if (method == "GET" || method == "HEAD") {
       contentLength = 0;
     } else {
       headers.chunkedTransferEncoding = true;
     }
+
+    _responseCompleter.future.then((response) {
+      _timeline?.instant('Response receieved');
+      Map formatConnectionInfo() => {
+            'localPort': response.connectionInfo?.localPort,
+            'remoteAddress': response.connectionInfo?.remoteAddress?.address,
+            'remotePort': response.connectionInfo?.remotePort,
+          };
+
+      Map formatHeaders() {
+        final headers = <String, List<String>>{};
+        response.headers.forEach((name, values) {
+          headers[name] = values;
+        });
+        return headers;
+      }
+
+      List<Map<String, dynamic>> formatRedirectInfo() {
+        final redirects = <Map<String, dynamic>>[];
+        for (final redirect in response.redirects) {
+          redirects.add({
+            'location': redirect.location.toString(),
+            'method': redirect.method,
+            'statusCode': redirect.statusCode,
+          });
+        }
+        return redirects;
+      }
+
+      _timeline?.finish(arguments: {
+        // TODO(bkonyi): consider exposing certificate information?
+        // 'certificate': response.certificate,
+        'requestHeaders': outgoing.outbound.headers._headers,
+        'compressionState': response.compressionState.toString(),
+        'connectionInfo': formatConnectionInfo(),
+        'contentLength': response.contentLength,
+        'cookies': [for (final cookie in response.cookies) cookie.toString()],
+        'responseHeaders': formatHeaders(),
+        'isRedirect': response.isRedirect,
+        'persistentConnection': response.persistentConnection,
+        'reasonPhrase': response.reasonPhrase,
+        'redirects': formatRedirectInfo(),
+        'statusCode': response.statusCode,
+      });
+    }, onError: (e) {});
   }
 
   Future<HttpClientResponse> get done {
@@ -1684,7 +1735,8 @@
     });
   }
 
-  _HttpClientRequest send(Uri uri, int port, String method, _Proxy proxy) {
+  _HttpClientRequest send(
+      Uri uri, int port, String method, _Proxy proxy, TimelineTask timeline) {
     if (closed) {
       throw new HttpException("Socket closed before request was sent",
           uri: uri);
@@ -1696,8 +1748,8 @@
     _SiteCredentials creds; // Credentials used to authorize this request.
     var outgoing = new _HttpOutgoing(_socket);
     // Create new request object, wrapping the outgoing connection.
-    var request =
-        new _HttpClientRequest(outgoing, uri, method, proxy, _httpClient, this);
+    var request = new _HttpClientRequest(
+        outgoing, uri, method, proxy, _httpClient, this, timeline);
     // For the Host header an IPv6 address must be enclosed in []'s.
     var host = uri.host;
     if (host.contains(':')) host = "[$host]";
@@ -1732,6 +1784,7 @@
         creds.authorize(request);
       }
     }
+
     // Start sending the request (lazy, delayed until the user provides
     // data).
     _httpParser.isHead = method == "HEAD";
@@ -1825,10 +1878,31 @@
         .then((_) => _socket.destroy());
   }
 
-  Future<_HttpClientConnection> createProxyTunnel(String host, int port,
-      _Proxy proxy, bool callback(X509Certificate certificate)) {
+  Future<_HttpClientConnection> createProxyTunnel(
+      String host,
+      int port,
+      _Proxy proxy,
+      bool callback(X509Certificate certificate),
+      TimelineTask timeline) {
+    timeline?.instant('Establishing proxy tunnel', arguments: {
+      'proxyInfo': {
+        if (proxy.host != null) 'host': proxy.host,
+        if (proxy.port != null)
+          'port': proxy.port,
+        if (proxy.username != null)
+          'username': proxy.username,
+        // TODO(bkonyi): is this something we would want to surface? Initial
+        // thought is no.
+        // if (proxy.password != null)
+        //   'password': proxy.password,
+        'isDirect': proxy.isDirect,
+      }
+    });
+    final method = "CONNECT";
+    final uri = Uri(host: host, port: port);
+    _HttpClient._startRequestTimelineEvent(timeline, method, uri);
     _HttpClientRequest request =
-        send(new Uri(host: host, port: port), port, "CONNECT", proxy);
+        send(Uri(host: host, port: port), port, method, proxy, timeline);
     if (proxy.isAuthenticated) {
       // If the proxy configuration contains user information use that
       // for proxy basic authorization.
@@ -1838,10 +1912,10 @@
     }
     return request.close().then((response) {
       if (response.statusCode != HttpStatus.ok) {
-        throw new HttpException(
-            "Proxy failed to establish tunnel "
-            "(${response.statusCode} ${response.reasonPhrase})",
-            uri: request.uri);
+        final error = "Proxy failed to establish tunnel "
+            "(${response.statusCode} ${response.reasonPhrase})";
+        timeline?.instant(error);
+        throw new HttpException(error, uri: request.uri);
       }
       var socket = (response as _HttpClientResponse)
           ._httpRequest
@@ -1851,6 +1925,7 @@
           host: host, context: _context, onBadCertificate: callback);
     }).then((secureSocket) {
       String key = _HttpClientConnection.makeKey(true, host, port);
+      timeline?.instant('Proxy tunnel established');
       return new _HttpClientConnection(
           key, secureSocket, request._httpClient, true);
     });
@@ -1964,8 +2039,8 @@
     }
   }
 
-  Future<_ConnectionInfo> connect(
-      String uriHost, int uriPort, _Proxy proxy, _HttpClient client) {
+  Future<_ConnectionInfo> connect(String uriHost, int uriPort, _Proxy proxy,
+      _HttpClient client, TimelineTask timeline) {
     if (hasIdle) {
       var connection = takeIdle();
       client._connectionsChanged();
@@ -1975,7 +2050,7 @@
         _active.length + _connecting >= client.maxConnectionsPerHost) {
       var completer = new Completer<_ConnectionInfo>();
       _pending.add(() {
-        completer.complete(connect(uriHost, uriPort, proxy, client));
+        completer.complete(connect(uriHost, uriPort, proxy, client, timeline));
       });
       return completer.future;
     }
@@ -2021,7 +2096,7 @@
         if (isSecure && !proxy.isDirect) {
           connection._dispose = true;
           return connection
-              .createProxyTunnel(uriHost, uriPort, proxy, callback)
+              .createProxyTunnel(uriHost, uriPort, proxy, callback, timeline)
               .then((tunnel) {
             client
                 ._getConnectionTarget(uriHost, uriPort, true)
@@ -2175,6 +2250,16 @@
 
   set findProxy(String f(Uri uri)) => _findProxy = f;
 
+  static void _startRequestTimelineEvent(
+      TimelineTask timeline, String method, Uri uri) {
+    timeline?.start('HTTP CLIENT ${method.toUpperCase()}', arguments: {
+      'filterKey':
+          'HTTP/client', // key used to filter network requests from timeline
+      'method': method.toUpperCase(),
+      'uri': uri.toString(),
+    });
+  }
+
   Future<_HttpClientRequest> _openUrl(String method, Uri uri) {
     if (_closing) {
       throw new StateError("Client is closed");
@@ -2212,19 +2297,32 @@
         return new Future.error(error, stackTrace);
       }
     }
-    return _getConnection(uri.host, port, proxyConf, isSecure)
-        .then((_ConnectionInfo info) {
+    TimelineTask timeline;
+    // TODO(bkonyi): do we want this to be opt-in?
+    if (HttpClient.enableTimelineLogging) {
+      timeline = TimelineTask();
+      _startRequestTimelineEvent(timeline, method, uri);
+    }
+    return _getConnection(uri.host, port, proxyConf, isSecure, timeline).then(
+        (_ConnectionInfo info) {
       _HttpClientRequest send(_ConnectionInfo info) {
+        timeline?.instant('Connection established');
         return info.connection
-            .send(uri, port, method.toUpperCase(), info.proxy);
+            .send(uri, port, method.toUpperCase(), info.proxy, timeline);
       }
 
       // If the connection was closed before the request was sent, create
       // and use another connection.
       if (info.connection.closed) {
-        return _getConnection(uri.host, port, proxyConf, isSecure).then(send);
+        return _getConnection(uri.host, port, proxyConf, isSecure, timeline)
+            .then(send);
       }
       return send(info);
+    }, onError: (error) {
+      timeline?.finish(arguments: {
+        'error': error.toString(),
+      });
+      throw error;
     });
   }
 
@@ -2291,7 +2389,7 @@
 
   // Get a new _HttpClientConnection, from the matching _ConnectionTarget.
   Future<_ConnectionInfo> _getConnection(String uriHost, int uriPort,
-      _ProxyConfiguration proxyConf, bool isSecure) {
+      _ProxyConfiguration proxyConf, bool isSecure, TimelineTask timeline) {
     Iterator<_Proxy> proxies = proxyConf.proxies.iterator;
 
     Future<_ConnectionInfo> connect(error) {
@@ -2300,7 +2398,7 @@
       String host = proxy.isDirect ? uriHost : proxy.host;
       int port = proxy.isDirect ? uriPort : proxy.port;
       return _getConnectionTarget(host, port, isSecure)
-          .connect(uriHost, uriPort, proxy, this)
+          .connect(uriHost, uriPort, proxy, this, timeline)
           // On error, continue with next proxy.
           .catchError(connect);
     }
diff --git a/sdk/lib/_http/http_parser.dart b/sdk/lib/_http/http_parser.dart
index f0444c2..8ef7ab0 100644
--- a/sdk/lib/_http/http_parser.dart
+++ b/sdk/lib/_http/http_parser.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.
 
+// @dart = 2.6
+
 part of dart._http;
 
 // Global constants.
diff --git a/sdk/lib/_http/http_session.dart b/sdk/lib/_http/http_session.dart
index 3907609..30b65af 100644
--- a/sdk/lib/_http/http_session.dart
+++ b/sdk/lib/_http/http_session.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.
 
+// @dart = 2.6
+
 part of dart._http;
 
 const String _DART_SESSION_ID = "DARTSESSID";
diff --git a/sdk/lib/_http/overrides.dart b/sdk/lib/_http/overrides.dart
index 7f9e689..4112c3c 100644
--- a/sdk/lib/_http/overrides.dart
+++ b/sdk/lib/_http/overrides.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.
 
+// @dart = 2.6
+
 part of dart._http;
 
 final _httpOverridesToken = new Object();
diff --git a/sdk/lib/_http/websocket.dart b/sdk/lib/_http/websocket.dart
index 5a949af..1d27852 100644
--- a/sdk/lib/_http/websocket.dart
+++ b/sdk/lib/_http/websocket.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.
 
+// @dart = 2.6
+
 part of dart._http;
 
 /**
diff --git a/sdk/lib/_http/websocket_impl.dart b/sdk/lib/_http/websocket_impl.dart
index ebbce45..c3d08ab 100644
--- a/sdk/lib/_http/websocket_impl.dart
+++ b/sdk/lib/_http/websocket_impl.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.
 
+// @dart = 2.6
+
 part of dart._http;
 
 const String _webSocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
diff --git a/sdk/lib/_internal/js_dev_runtime/lib/js/dart2js/js_dart2js.dart b/sdk/lib/_internal/js_dev_runtime/lib/js/dart2js/js_dart2js.dart
index 49c7df3..1be2417 100644
--- a/sdk/lib/_internal/js_dev_runtime/lib/js/dart2js/js_dart2js.dart
+++ b/sdk/lib/_internal/js_dev_runtime/lib/js/dart2js/js_dart2js.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.
 
+// @dart = 2.6
+
 // DDC version of sdk/lib/js/dart2js/js_dart2js.dart
 
 /// Low-level support for interoperating with JavaScript.
diff --git a/sdk/lib/_internal/js_dev_runtime/lib/js_util/dart2js/js_util_dart2js.dart b/sdk/lib/_internal/js_dev_runtime/lib/js_util/dart2js/js_util_dart2js.dart
index d0377bb..feda1c1 100644
--- a/sdk/lib/_internal/js_dev_runtime/lib/js_util/dart2js/js_util_dart2js.dart
+++ b/sdk/lib/_internal/js_dev_runtime/lib/js_util/dart2js/js_util_dart2js.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.
 
+// @dart = 2.6
+
 /// Utility methods to efficiently manipulate typed JSInterop objects in cases
 /// where the name to call is not known at runtime. You should only use these
 /// methods when the same effect cannot be achieved with @JS annotations.
diff --git a/sdk/lib/_internal/js_dev_runtime/libraries.dart b/sdk/lib/_internal/js_dev_runtime/libraries.dart
index d5cffa2..b844996 100644
--- a/sdk/lib/_internal/js_dev_runtime/libraries.dart
+++ b/sdk/lib/_internal/js_dev_runtime/libraries.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.
 
+// @dart = 2.6
+
 library libraries;
 
 /**
diff --git a/sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart b/sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart
index 894aef4..ef0a652 100644
--- a/sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart
+++ b/sdk/lib/_internal/js_dev_runtime/patch/async_patch.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.
 
+// @dart = 2.6
+
 // Patch file for the dart:async library.
 
 import 'dart:_js_helper' show notNull, patch, ReifyFunctionTypes;
diff --git a/sdk/lib/_internal/js_dev_runtime/patch/cli_patch.dart b/sdk/lib/_internal/js_dev_runtime/patch/cli_patch.dart
index b1c3841..b3ba63c 100644
--- a/sdk/lib/_internal/js_dev_runtime/patch/cli_patch.dart
+++ b/sdk/lib/_internal/js_dev_runtime/patch/cli_patch.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.
 
+// @dart = 2.6
+
 import 'dart:_js_helper' show patch;
 
 @patch
diff --git a/sdk/lib/_internal/js_dev_runtime/patch/collection_patch.dart b/sdk/lib/_internal/js_dev_runtime/patch/collection_patch.dart
index daa3bf8..f0f7c9b 100644
--- a/sdk/lib/_internal/js_dev_runtime/patch/collection_patch.dart
+++ b/sdk/lib/_internal/js_dev_runtime/patch/collection_patch.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.
 
+// @dart = 2.6
+
 // Patch file for dart:collection classes.
 import 'dart:_foreign_helper' show JS, JSExportName;
 import 'dart:_runtime' as dart;
diff --git a/sdk/lib/_internal/js_dev_runtime/patch/convert_patch.dart b/sdk/lib/_internal/js_dev_runtime/patch/convert_patch.dart
index 486473b..6b85e67 100644
--- a/sdk/lib/_internal/js_dev_runtime/patch/convert_patch.dart
+++ b/sdk/lib/_internal/js_dev_runtime/patch/convert_patch.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.
 
+// @dart = 2.6
+
 // Patch file for dart:convert library.
 
 import 'dart:_js_helper' show argumentErrorValue, patch;
diff --git a/sdk/lib/_internal/js_dev_runtime/patch/core_patch.dart b/sdk/lib/_internal/js_dev_runtime/patch/core_patch.dart
index a52e489..af9ae7d 100644
--- a/sdk/lib/_internal/js_dev_runtime/patch/core_patch.dart
+++ b/sdk/lib/_internal/js_dev_runtime/patch/core_patch.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.
 
+// @dart = 2.6
+
 // Patch file for dart:core classes.
 import "dart:_internal" as _symbol_dev;
 import 'dart:_interceptors';
@@ -949,6 +951,9 @@
 int _max(int a, int b) => a > b ? a : b;
 int _min(int a, int b) => a < b ? a : b;
 
+/// Empty list used as an initializer for local variables in the `_BigIntImpl`.
+final _dummyList = new Uint16List(0);
+
 // Copyright 2009 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
@@ -1194,9 +1199,6 @@
       return null;
     }
 
-    if (radix is! int) {
-      throw ArgumentError.value(radix, 'radix', 'is not an integer');
-    }
     if (radix < 2 || radix > 36) {
       throw RangeError.range(radix, 2, 36, 'radix');
     }
@@ -1558,8 +1560,7 @@
   ///
   /// Returns 0 if abs(this) == abs(other); a positive number if
   /// abs(this) > abs(other); and a negative number if abs(this) < abs(other).
-  int _absCompare(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  int _absCompare(_BigIntImpl other) {
     return _compareDigits(_digits, _used, other._digits, other._used);
   }
 
@@ -1569,8 +1570,7 @@
    * Returns a negative number if `this` is less than `other`, zero if they are
    * equal, and a positive number if `this` is greater than `other`.
    */
-  int compareTo(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  int compareTo(covariant _BigIntImpl other) {
     if (_isNegative == other._isNegative) {
       var result = _absCompare(other);
       // Use 0 - result to avoid negative zero in JavaScript.
@@ -1712,7 +1712,8 @@
     var digits = _digits;
     var otherDigits = other._digits;
     var resultDigits = Uint16List(resultUsed);
-    var l, m;
+    _BigIntImpl l;
+    int m;
     if (used < otherUsed) {
       l = other;
       m = used;
@@ -1738,7 +1739,8 @@
     var digits = _digits;
     var otherDigits = other._digits;
     var resultDigits = Uint16List(resultUsed);
-    var l, m;
+    _BigIntImpl l;
+    int m;
     if (used < otherUsed) {
       l = other;
       m = used;
@@ -1766,8 +1768,7 @@
    * Of both operands are negative, the result is negative, otherwise
    * the result is non-negative.
    */
-  _BigIntImpl operator &(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl operator &(covariant _BigIntImpl other) {
     if (_isZero || other._isZero) return zero;
     if (_isNegative == other._isNegative) {
       if (_isNegative) {
@@ -1782,7 +1783,7 @@
       return _absAndSetSign(other, false);
     }
     // _isNegative != other._isNegative
-    var p, n;
+    _BigIntImpl p, n;
     if (_isNegative) {
       p = other;
       n = this;
@@ -1806,8 +1807,7 @@
    * If both operands are non-negative, the result is non-negative,
    * otherwise the result us negative.
    */
-  _BigIntImpl operator |(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl operator |(covariant _BigIntImpl other) {
     if (_isZero) return other;
     if (other._isZero) return this;
     if (_isNegative == other._isNegative) {
@@ -1823,7 +1823,7 @@
       return _absOrSetSign(other, false);
     }
     // _neg != a._neg
-    var p, n;
+    _BigIntImpl p, n;
     if (_isNegative) {
       p = other;
       n = this;
@@ -1848,8 +1848,7 @@
    * If the operands have the same sign, the result is non-negative,
    * otherwise the result is negative.
    */
-  _BigIntImpl operator ^(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl operator ^(covariant _BigIntImpl other) {
     if (_isZero) return other;
     if (other._isZero) return this;
     if (_isNegative == other._isNegative) {
@@ -1862,7 +1861,7 @@
       return _absXorSetSign(other, false);
     }
     // _isNegative != a._isNegative
-    var p, n;
+    _BigIntImpl p, n;
     if (_isNegative) {
       p = other;
       n = this;
@@ -1897,8 +1896,7 @@
   }
 
   /// Addition operator.
-  _BigIntImpl operator +(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl operator +(covariant _BigIntImpl other) {
     if (_isZero) return other;
     if (other._isZero) return this;
     var isNegative = _isNegative;
@@ -1916,8 +1914,7 @@
   }
 
   /// Subtraction operator.
-  _BigIntImpl operator -(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl operator -(covariant _BigIntImpl other) {
     if (_isZero) return -other;
     if (other._isZero) return this;
     var isNegative = _isNegative;
@@ -1969,8 +1966,7 @@
   }
 
   /// Multiplication operator.
-  _BigIntImpl operator *(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl operator *(covariant _BigIntImpl other) {
     var used = _used;
     var otherUsed = other._used;
     if (used == 0 || otherUsed == 0) {
@@ -2018,8 +2014,7 @@
   }
 
   /// Returns `trunc(this / other)`, with `other != 0`.
-  _BigIntImpl _div(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl _div(_BigIntImpl other) {
     assert(other._used > 0);
     if (_used < other._used) {
       return zero;
@@ -2038,8 +2033,7 @@
   }
 
   /// Returns `this - other * trunc(this / other)`, with `other != 0`.
-  _BigIntImpl _rem(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl _rem(_BigIntImpl other) {
     assert(other._used > 0);
     if (_used < other._used) {
       return this;
@@ -2239,8 +2233,7 @@
    * seven.remainder(-three);   // => 1
    * ```
    */
-  _BigIntImpl operator ~/(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl operator ~/(covariant _BigIntImpl other) {
     if (other._used == 0) {
       throw const IntegerDivisionByZeroException();
     }
@@ -2254,8 +2247,7 @@
    * `this == (this ~/ other) * other + r`.
    * As a consequence the remainder `r` has the same sign as the divider `this`.
    */
-  _BigIntImpl remainder(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl remainder(covariant _BigIntImpl other) {
     if (other._used == 0) {
       throw const IntegerDivisionByZeroException();
     }
@@ -2266,16 +2258,16 @@
   double operator /(BigInt other) => this.toDouble() / other.toDouble();
 
   /** Relational less than operator. */
-  bool operator <(BigInt other) => compareTo(other) < 0;
+  bool operator <(covariant _BigIntImpl other) => compareTo(other) < 0;
 
   /** Relational less than or equal operator. */
-  bool operator <=(BigInt other) => compareTo(other) <= 0;
+  bool operator <=(covariant _BigIntImpl other) => compareTo(other) <= 0;
 
   /** Relational greater than operator. */
-  bool operator >(BigInt other) => compareTo(other) > 0;
+  bool operator >(covariant _BigIntImpl other) => compareTo(other) > 0;
 
   /** Relational greater than or equal operator. */
-  bool operator >=(BigInt other) => compareTo(other) >= 0;
+  bool operator >=(covariant _BigIntImpl other) => compareTo(other) >= 0;
 
   /**
    * Euclidean modulo operator.
@@ -2288,8 +2280,7 @@
    *
    * See [remainder] for the remainder of the truncating division.
    */
-  _BigIntImpl operator %(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl operator %(covariant _BigIntImpl other) {
     if (other._used == 0) {
       throw const IntegerDivisionByZeroException();
     }
@@ -2352,9 +2343,8 @@
    * The [exponent] must be non-negative and [modulus] must be
    * positive.
    */
-  _BigIntImpl modPow(BigInt bigExponent, BigInt bigModulus) {
-    _BigIntImpl exponent = bigExponent;
-    _BigIntImpl modulus = bigModulus;
+  _BigIntImpl modPow(
+      covariant _BigIntImpl exponent, covariant _BigIntImpl modulus) {
     if (exponent._isNegative) {
       throw ArgumentError("exponent must be positive: $exponent");
     }
@@ -2378,7 +2368,7 @@
       resultDigits[j] = gDigits[j];
     }
     var resultUsed = gUsed;
-    var result2Used;
+    int result2Used;
     for (int i = exponentBitlen - 2; i >= 0; i--) {
       result2Used = z.sqr(resultDigits, resultUsed, result2Digits);
       if (!(exponent & (one << i))._isZero) {
@@ -2453,19 +2443,19 @@
     // Variables a, b, c, and d require one more digit.
     final abcdUsed = maxUsed + 1;
     final abcdLen = abcdUsed + 2; // +2 to satisfy _absAdd.
-    var aDigits, bDigits, cDigits, dDigits;
-    bool aIsNegative, bIsNegative, cIsNegative, dIsNegative;
+    var aDigits = _dummyList;
+    var aIsNegative = false;
+    var cDigits = _dummyList;
+    var cIsNegative = false;
     if (ac) {
       aDigits = Uint16List(abcdLen);
-      aIsNegative = false;
       aDigits[0] = 1;
       cDigits = Uint16List(abcdLen);
-      cIsNegative = false;
     }
-    bDigits = Uint16List(abcdLen);
-    bIsNegative = false;
-    dDigits = Uint16List(abcdLen);
-    dIsNegative = false;
+    var bDigits = Uint16List(abcdLen);
+    var bIsNegative = false;
+    var dDigits = Uint16List(abcdLen);
+    var dIsNegative = false;
     dDigits[0] = 1;
 
     while (true) {
@@ -2658,8 +2648,7 @@
    * It is an error if no modular inverse exists.
    */
   // Returns 1/this % modulus, with modulus > 0.
-  _BigIntImpl modInverse(BigInt bigInt) {
-    _BigIntImpl modulus = bigInt;
+  _BigIntImpl modInverse(covariant _BigIntImpl modulus) {
     if (modulus <= zero) {
       throw ArgumentError("Modulus must be strictly positive: $modulus");
     }
@@ -2684,8 +2673,7 @@
    *
    * If both `this` and `other` is zero, the result is also zero.
    */
-  _BigIntImpl gcd(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl gcd(covariant _BigIntImpl other) {
     if (_isZero) return other.abs();
     if (other._isZero) return this.abs();
     return _binaryGcd(this, other, false);
@@ -3004,8 +2992,8 @@
                 _modulus._digits[_modulus._used - 1].bitLength);
 
   int convert(_BigIntImpl x, Uint16List resultDigits) {
-    var digits;
-    var used;
+    Uint16List digits;
+    int used;
     if (x._isNegative || x._absCompare(_modulus) >= 0) {
       var remainder = x._rem(_modulus);
       if (x._isNegative && remainder._used > 0) {
diff --git a/sdk/lib/_internal/js_dev_runtime/patch/developer_patch.dart b/sdk/lib/_internal/js_dev_runtime/patch/developer_patch.dart
index 7f5e4fe..954f09e 100644
--- a/sdk/lib/_internal/js_dev_runtime/patch/developer_patch.dart
+++ b/sdk/lib/_internal/js_dev_runtime/patch/developer_patch.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.
 
+// @dart = 2.6
+
 // Patch file for dart:developer library.
 
 import 'dart:_js_helper' show patch, ForceInline, ReifyFunctionTypes;
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 5e850bb..6ab2349 100644
--- a/sdk/lib/_internal/js_dev_runtime/patch/internal_patch.dart
+++ b/sdk/lib/_internal/js_dev_runtime/patch/internal_patch.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.
 
+// @dart = 2.6
+
 import 'dart:core' hide Symbol;
 import 'dart:core' as core show Symbol;
 import 'dart:_js_primitives' show printString;
diff --git a/sdk/lib/_internal/js_dev_runtime/patch/io_patch.dart b/sdk/lib/_internal/js_dev_runtime/patch/io_patch.dart
index fcdaa65..514ffcb 100644
--- a/sdk/lib/_internal/js_dev_runtime/patch/io_patch.dart
+++ b/sdk/lib/_internal/js_dev_runtime/patch/io_patch.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.
 
+// @dart = 2.6
+
 import 'dart:_js_helper' show patch;
 import 'dart:async';
 import 'dart:convert';
diff --git a/sdk/lib/_internal/js_dev_runtime/patch/isolate_patch.dart b/sdk/lib/_internal/js_dev_runtime/patch/isolate_patch.dart
index f6aa73bb..93e4165 100644
--- a/sdk/lib/_internal/js_dev_runtime/patch/isolate_patch.dart
+++ b/sdk/lib/_internal/js_dev_runtime/patch/isolate_patch.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.
 
+// @dart = 2.6
+
 // Patch file for the dart:isolate library.
 
 import 'dart:_js_helper' show patch, NoReifyGeneric;
diff --git a/sdk/lib/_internal/js_dev_runtime/patch/math_patch.dart b/sdk/lib/_internal/js_dev_runtime/patch/math_patch.dart
index 2ba4220..c2363f7 100644
--- a/sdk/lib/_internal/js_dev_runtime/patch/math_patch.dart
+++ b/sdk/lib/_internal/js_dev_runtime/patch/math_patch.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.
 
+// @dart = 2.6
+
 // Patch file for dart:math library.
 import 'dart:_foreign_helper' show JS;
 import 'dart:_js_helper' show patch, nullCheck, notNull;
diff --git a/sdk/lib/_internal/js_dev_runtime/patch/mirrors_patch.dart b/sdk/lib/_internal/js_dev_runtime/patch/mirrors_patch.dart
index e3b015b..7795c8f 100644
--- a/sdk/lib/_internal/js_dev_runtime/patch/mirrors_patch.dart
+++ b/sdk/lib/_internal/js_dev_runtime/patch/mirrors_patch.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.
 
+// @dart = 2.6
+
 // Patch library for dart:mirrors.
 
 import 'dart:_js_helper' show patch;
diff --git a/sdk/lib/_internal/js_dev_runtime/patch/typed_data_patch.dart b/sdk/lib/_internal/js_dev_runtime/patch/typed_data_patch.dart
index f1e2dc1..ab74676 100644
--- a/sdk/lib/_internal/js_dev_runtime/patch/typed_data_patch.dart
+++ b/sdk/lib/_internal/js_dev_runtime/patch/typed_data_patch.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.
 
+// @dart = 2.6
+
 import 'dart:collection';
 import 'dart:_js_helper' show patch;
 import 'dart:_native_typed_data';
diff --git a/sdk/lib/_internal/js_dev_runtime/private/annotations.dart b/sdk/lib/_internal/js_dev_runtime/private/annotations.dart
index bc437da..feac26e 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/annotations.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/annotations.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.
 
+// @dart = 2.6
+
 part of dart._js_helper;
 
 /// Tells the optimizing compiler to always inline the annotated method.
diff --git a/sdk/lib/_internal/js_dev_runtime/private/custom_hash_map.dart b/sdk/lib/_internal/js_dev_runtime/private/custom_hash_map.dart
index c7c920d..c387062 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/custom_hash_map.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/custom_hash_map.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.
 
+// @dart = 2.6
+
 part of dart._js_helper;
 
 class CustomKeyHashMap<K, V> extends CustomHashMap<K, V> {
diff --git a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/classes.dart b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/classes.dart
index 1fe79ab..ac6ad55 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/classes.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/classes.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.
 
+// @dart = 2.6
+
 /// This library defines the operations that define and manipulate Dart
 /// classes.  Included in this are:
 ///   - Generics
diff --git a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart
index f875336..4a5813d 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.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.
 
+// @dart = 2.6
+
 part of dart._runtime;
 
 // We need to set these properties while the sdk is only partially initialized
diff --git a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart
index e388cd6..eac2648 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.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.
 
+// @dart = 2.6
+
 /// This library defines runtime operations on objects used by the code
 /// generator.
 part of dart._runtime;
diff --git a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/rtti.dart b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/rtti.dart
index 34c66e2..a869a3f 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/rtti.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/rtti.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.
 
+// @dart = 2.6
+
 /// This library defines the association between runtime objects and
 /// runtime types.
 part of dart._runtime;
diff --git a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/runtime.dart b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/runtime.dart
index 1c6ce56..68eef6d 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/runtime.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/runtime.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.
 
+// @dart = 2.6
+
 @ReifyFunctionTypes(false)
 library dart._runtime;
 
diff --git a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart
index 4456041..7931294 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/types.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.
 
+// @dart = 2.6
+
 /// This library defines the representation of runtime types.
 part of dart._runtime;
 
diff --git a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/utils.dart b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/utils.dart
index 2c06179..c691cfd 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/utils.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/utils.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.
 
+// @dart = 2.6
+
 part of dart._runtime;
 
 /// This library defines a set of general javascript utilities for us
diff --git a/sdk/lib/_internal/js_dev_runtime/private/debugger.dart b/sdk/lib/_internal/js_dev_runtime/private/debugger.dart
index 4618317..9bdca7a 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/debugger.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/debugger.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.
 
+// @dart = 2.6
+
 library dart._debugger;
 
 import 'dart:_foreign_helper' show JS;
diff --git a/sdk/lib/_internal/js_dev_runtime/private/foreign_helper.dart b/sdk/lib/_internal/js_dev_runtime/private/foreign_helper.dart
index 588d789..b46e817 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/foreign_helper.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/foreign_helper.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.
 
+// @dart = 2.6
+
 library dart._foreign_helper;
 
 /**
diff --git a/sdk/lib/_internal/js_dev_runtime/private/identity_hash_map.dart b/sdk/lib/_internal/js_dev_runtime/private/identity_hash_map.dart
index 04107cc..fa62a8f 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/identity_hash_map.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/identity_hash_map.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.
 
+// @dart = 2.6
+
 part of dart._js_helper;
 
 class IdentityMap<K, V> extends InternalMap<K, V> {
diff --git a/sdk/lib/_internal/js_dev_runtime/private/interceptors.dart b/sdk/lib/_internal/js_dev_runtime/private/interceptors.dart
index 6ddd96b..db81230 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/interceptors.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/interceptors.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.
 
+// @dart = 2.6
+
 library dart._interceptors;
 
 import 'dart:collection';
diff --git a/sdk/lib/_internal/js_dev_runtime/private/isolate_helper.dart b/sdk/lib/_internal/js_dev_runtime/private/isolate_helper.dart
index 9132848..78e8e19 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/isolate_helper.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/isolate_helper.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.
 
+// @dart = 2.6
+
 library dart._isolate_helper;
 
 import 'dart:_runtime' as dart;
diff --git a/sdk/lib/_internal/js_dev_runtime/private/js_array.dart b/sdk/lib/_internal/js_dev_runtime/private/js_array.dart
index f064b24..2d33e74 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/js_array.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/js_array.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.
 
+// @dart = 2.6
+
 part of dart._interceptors;
 
 /**
diff --git a/sdk/lib/_internal/js_dev_runtime/private/js_helper.dart b/sdk/lib/_internal/js_dev_runtime/private/js_helper.dart
index 5d6b037..94ef1de 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/js_helper.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/js_helper.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.
 
+// @dart = 2.6
+
 library dart._js_helper;
 
 import 'dart:collection';
diff --git a/sdk/lib/_internal/js_dev_runtime/private/js_mirrors.dart b/sdk/lib/_internal/js_dev_runtime/private/js_mirrors.dart
index a93f5fb..38402be 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/js_mirrors.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/js_mirrors.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.
 
+// @dart = 2.6
+
 library dart._js_mirrors;
 
 import 'dart:mirrors';
diff --git a/sdk/lib/_internal/js_dev_runtime/private/js_number.dart b/sdk/lib/_internal/js_dev_runtime/private/js_number.dart
index 5f8c7e0..3d974a7 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/js_number.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/js_number.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.
 
+// @dart = 2.6
+
 part of dart._interceptors;
 
 /**
diff --git a/sdk/lib/_internal/js_dev_runtime/private/js_primitives.dart b/sdk/lib/_internal/js_dev_runtime/private/js_primitives.dart
index 1347b62..f6c0c59 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/js_primitives.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/js_primitives.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.
 
+// @dart = 2.6
+
 /// dart2js "primitives", that is, features that cannot be implemented without
 /// access to JavaScript features.
 library dart2js._js_primitives;
diff --git a/sdk/lib/_internal/js_dev_runtime/private/js_rti.dart b/sdk/lib/_internal/js_dev_runtime/private/js_rti.dart
index 015c83e..e058820 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/js_rti.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/js_rti.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.
 
+// @dart = 2.6
+
 part of dart._js_helper;
 
 // TODO(leafp): Maybe get rid of this?  Currently used by the interceptors
diff --git a/sdk/lib/_internal/js_dev_runtime/private/js_string.dart b/sdk/lib/_internal/js_dev_runtime/private/js_string.dart
index 4271d34..de63d0a 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/js_string.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/js_string.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.
 
+// @dart = 2.6
+
 part of dart._interceptors;
 
 /**
diff --git a/sdk/lib/_internal/js_dev_runtime/private/linked_hash_map.dart b/sdk/lib/_internal/js_dev_runtime/private/linked_hash_map.dart
index 1c03db8..d9051f4 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/linked_hash_map.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/linked_hash_map.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.
 
+// @dart = 2.6
+
 // Efficient JavaScript based implementation of a linked hash map used as a
 // backing map for constant maps and the [LinkedHashMap] patch
 
diff --git a/sdk/lib/_internal/js_dev_runtime/private/mirror_helper.dart b/sdk/lib/_internal/js_dev_runtime/private/mirror_helper.dart
index f78926a..dc635a9 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/mirror_helper.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/mirror_helper.dart
@@ -1,6 +1,8 @@
 // Copyright (c) 2013, 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.6
+
 /**
  * Helps dealing with reflection in the case that the source code has been
  * changed as a result of compiling with dart2dart.
diff --git a/sdk/lib/_internal/js_dev_runtime/private/native_helper.dart b/sdk/lib/_internal/js_dev_runtime/private/native_helper.dart
index cc214e8..d7a312c1 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/native_helper.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/native_helper.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.
 
+// @dart = 2.6
+
 part of dart._js_helper;
 
 // Obsolete in dart dev compiler. Added only so that the same version of
diff --git a/sdk/lib/_internal/js_dev_runtime/private/native_typed_data.dart b/sdk/lib/_internal/js_dev_runtime/private/native_typed_data.dart
index 2a7a621..a444d0c 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/native_typed_data.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/native_typed_data.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.
 
+// @dart = 2.6
+
 /**
  * Specialized integers and floating point numbers,
  * with SIMD support and efficient lists.
diff --git a/sdk/lib/_internal/js_dev_runtime/private/profile.dart b/sdk/lib/_internal/js_dev_runtime/private/profile.dart
index d46f7f7..0b30862 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/profile.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/profile.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.
 
+// @dart = 2.6
+
 /// This file supports profiling dynamic calls.
 part of dart._debugger;
 
diff --git a/sdk/lib/_internal/js_dev_runtime/private/regexp_helper.dart b/sdk/lib/_internal/js_dev_runtime/private/regexp_helper.dart
index 6eeee38..0a02d3f 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/regexp_helper.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/regexp_helper.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.
 
+// @dart = 2.6
+
 part of dart._js_helper;
 
 // Helper method used by internal libraries.
diff --git a/sdk/lib/_internal/js_dev_runtime/private/string_helper.dart b/sdk/lib/_internal/js_dev_runtime/private/string_helper.dart
index c1b5c18..326af11 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/string_helper.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/string_helper.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.
 
+// @dart = 2.6
+
 part of dart._js_helper;
 
 @notNull
diff --git a/sdk/lib/_internal/js_runtime/lib/annotations.dart b/sdk/lib/_internal/js_runtime/lib/annotations.dart
index f53c5f3..971d2bd 100644
--- a/sdk/lib/_internal/js_runtime/lib/annotations.dart
+++ b/sdk/lib/_internal/js_runtime/lib/annotations.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.
 
+// @dart = 2.6
+
 part of _js_helper;
 
 /// Marks a class as native and defines its JavaScript name(s).
diff --git a/sdk/lib/_internal/js_runtime/lib/async_patch.dart b/sdk/lib/_internal/js_runtime/lib/async_patch.dart
index 68bcbeb..de08681 100644
--- a/sdk/lib/_internal/js_runtime/lib/async_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/async_patch.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.
 
+// @dart = 2.6
+
 // Patch file for the dart:async library.
 
 import 'dart:_js_helper'
diff --git a/sdk/lib/_internal/js_runtime/lib/cli_patch.dart b/sdk/lib/_internal/js_runtime/lib/cli_patch.dart
index 6921e60..7f02085 100644
--- a/sdk/lib/_internal/js_runtime/lib/cli_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/cli_patch.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.
 
+// @dart = 2.6
+
 import 'dart:_js_helper' show patch;
 
 @patch
diff --git a/sdk/lib/_internal/js_runtime/lib/collection_patch.dart b/sdk/lib/_internal/js_runtime/lib/collection_patch.dart
index 300d490..604097f 100644
--- a/sdk/lib/_internal/js_runtime/lib/collection_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/collection_patch.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.
 
+// @dart = 2.6
+
 // Patch file for dart:collection classes.
 import 'dart:_foreign_helper' show JS;
 import 'dart:_js_helper'
diff --git a/sdk/lib/_internal/js_runtime/lib/constant_map.dart b/sdk/lib/_internal/js_runtime/lib/constant_map.dart
index f7c7936..fce8922 100644
--- a/sdk/lib/_internal/js_runtime/lib/constant_map.dart
+++ b/sdk/lib/_internal/js_runtime/lib/constant_map.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.
 
+// @dart = 2.6
+
 part of _js_helper;
 
 class ConstantMapView<K, V> extends UnmodifiableMapView<K, V>
diff --git a/sdk/lib/_internal/js_runtime/lib/convert_patch.dart b/sdk/lib/_internal/js_runtime/lib/convert_patch.dart
index fa6a0b0..421fd51 100644
--- a/sdk/lib/_internal/js_runtime/lib/convert_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/convert_patch.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.
 
+// @dart = 2.6
+
 // Patch file for dart:convert library.
 
 import 'dart:_js_helper' show argumentErrorValue, patch;
diff --git a/sdk/lib/_internal/js_runtime/lib/core_patch.dart b/sdk/lib/_internal/js_runtime/lib/core_patch.dart
index ec8dbc4..2f9c880 100644
--- a/sdk/lib/_internal/js_runtime/lib/core_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/core_patch.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.
 
+// @dart = 2.6
+
 // Patch file for dart:core classes.
 import "dart:_internal" hide Symbol, LinkedList, LinkedListEntry;
 import "dart:_internal" as _symbol_dev;
@@ -855,6 +857,9 @@
 int _max(int a, int b) => a > b ? a : b;
 int _min(int a, int b) => a < b ? a : b;
 
+/// Empty list used as an initializer for local variables in the `_BigIntImpl`.
+final _dummyList = new Uint16List(0);
+
 // Copyright 2009 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
@@ -1453,8 +1458,7 @@
   ///
   /// Returns 0 if abs(this) == abs(other); a positive number if
   /// abs(this) > abs(other); and a negative number if abs(this) < abs(other).
-  int _absCompare(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  int _absCompare(_BigIntImpl other) {
     return _compareDigits(_digits, _used, other._digits, other._used);
   }
 
@@ -1462,8 +1466,7 @@
   ///
   /// Returns a negative number if `this` is less than `other`, zero if they are
   /// equal, and a positive number if `this` is greater than `other`.
-  int compareTo(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  int compareTo(covariant _BigIntImpl other) {
     if (_isNegative == other._isNegative) {
       var result = _absCompare(other);
       // Use 0 - result to avoid negative zero in JavaScript.
@@ -1605,7 +1608,8 @@
     var digits = _digits;
     var otherDigits = other._digits;
     var resultDigits = new Uint16List(resultUsed);
-    var l, m;
+    _BigIntImpl l;
+    int m;
     if (used < otherUsed) {
       l = other;
       m = used;
@@ -1631,7 +1635,8 @@
     var digits = _digits;
     var otherDigits = other._digits;
     var resultDigits = new Uint16List(resultUsed);
-    var l, m;
+    _BigIntImpl l;
+    int m;
     if (used < otherUsed) {
       l = other;
       m = used;
@@ -1657,8 +1662,7 @@
   ///
   /// Of both operands are negative, the result is negative, otherwise
   /// the result is non-negative.
-  _BigIntImpl operator &(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl operator &(covariant _BigIntImpl other) {
     if (_isZero || other._isZero) return zero;
     if (_isNegative == other._isNegative) {
       if (_isNegative) {
@@ -1673,7 +1677,7 @@
       return _absAndSetSign(other, false);
     }
     // _isNegative != other._isNegative
-    var p, n;
+    _BigIntImpl p, n;
     if (_isNegative) {
       p = other;
       n = this;
@@ -1695,8 +1699,7 @@
   ///
   /// If both operands are non-negative, the result is non-negative,
   /// otherwise the result us negative.
-  _BigIntImpl operator |(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl operator |(covariant _BigIntImpl other) {
     if (_isZero) return other;
     if (other._isZero) return this;
     if (_isNegative == other._isNegative) {
@@ -1712,7 +1715,7 @@
       return _absOrSetSign(other, false);
     }
     // _neg != a._neg
-    var p, n;
+    _BigIntImpl p, n;
     if (_isNegative) {
       p = other;
       n = this;
@@ -1735,8 +1738,7 @@
   ///
   /// If the operands have the same sign, the result is non-negative,
   /// otherwise the result is negative.
-  _BigIntImpl operator ^(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl operator ^(covariant _BigIntImpl other) {
     if (_isZero) return other;
     if (other._isZero) return this;
     if (_isNegative == other._isNegative) {
@@ -1749,7 +1751,7 @@
       return _absXorSetSign(other, false);
     }
     // _isNegative != a._isNegative
-    var p, n;
+    _BigIntImpl p, n;
     if (_isNegative) {
       p = other;
       n = this;
@@ -1782,8 +1784,7 @@
   }
 
   /// Addition operator.
-  _BigIntImpl operator +(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl operator +(covariant _BigIntImpl other) {
     if (_isZero) return other;
     if (other._isZero) return this;
     var isNegative = _isNegative;
@@ -1801,8 +1802,7 @@
   }
 
   /// Subtraction operator.
-  _BigIntImpl operator -(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl operator -(covariant _BigIntImpl other) {
     if (_isZero) return -other;
     if (other._isZero) return this;
     var isNegative = _isNegative;
@@ -1854,8 +1854,7 @@
   }
 
   /// Multiplication operator.
-  _BigIntImpl operator *(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl operator *(covariant _BigIntImpl other) {
     var used = _used;
     var otherUsed = other._used;
     if (used == 0 || otherUsed == 0) {
@@ -1903,8 +1902,7 @@
   }
 
   /// Returns `trunc(this / other)`, with `other != 0`.
-  _BigIntImpl _div(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl _div(_BigIntImpl other) {
     assert(other._used > 0);
     if (_used < other._used) {
       return zero;
@@ -1923,8 +1921,7 @@
   }
 
   /// Returns `this - other * trunc(this / other)`, with `other != 0`.
-  _BigIntImpl _rem(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl _rem(_BigIntImpl other) {
     assert(other._used > 0);
     if (_used < other._used) {
       return this;
@@ -2118,8 +2115,7 @@
   /// (-seven).remainder(three); // => -1
   /// seven.remainder(-three);   // => 1
   /// ```
-  _BigIntImpl operator ~/(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl operator ~/(covariant _BigIntImpl other) {
     if (other._used == 0) {
       throw const IntegerDivisionByZeroException();
     }
@@ -2132,8 +2128,7 @@
   /// `this == (this ~/ other) * other + r`.
   /// As a consequence the remainder `r` has the same sign as the divider
   /// `this`.
-  _BigIntImpl remainder(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl remainder(covariant _BigIntImpl other) {
     if (other._used == 0) {
       throw const IntegerDivisionByZeroException();
     }
@@ -2144,16 +2139,16 @@
   double operator /(BigInt other) => this.toDouble() / other.toDouble();
 
   /// Relational less than operator.
-  bool operator <(BigInt other) => compareTo(other) < 0;
+  bool operator <(covariant _BigIntImpl other) => compareTo(other) < 0;
 
   /// Relational less than or equal operator.
-  bool operator <=(BigInt other) => compareTo(other) <= 0;
+  bool operator <=(covariant _BigIntImpl other) => compareTo(other) <= 0;
 
   /// Relational greater than operator.
-  bool operator >(BigInt other) => compareTo(other) > 0;
+  bool operator >(covariant _BigIntImpl other) => compareTo(other) > 0;
 
   /// Relational greater than or equal operator.
-  bool operator >=(BigInt other) => compareTo(other) >= 0;
+  bool operator >=(covariant _BigIntImpl other) => compareTo(other) >= 0;
 
   /// Euclidean modulo operator.
   ///
@@ -2164,8 +2159,7 @@
   /// The sign of the returned value `r` is always positive.
   ///
   /// See [remainder] for the remainder of the truncating division.
-  _BigIntImpl operator %(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl operator %(covariant _BigIntImpl other) {
     if (other._used == 0) {
       throw const IntegerDivisionByZeroException();
     }
@@ -2224,9 +2218,8 @@
   ///
   /// The [exponent] must be non-negative and [modulus] must be
   /// positive.
-  _BigIntImpl modPow(BigInt bigExponent, BigInt bigModulus) {
-    _BigIntImpl exponent = bigExponent;
-    _BigIntImpl modulus = bigModulus;
+  _BigIntImpl modPow(
+      covariant _BigIntImpl exponent, covariant _BigIntImpl modulus) {
     if (exponent._isNegative) {
       throw new ArgumentError("exponent must be positive: $exponent");
     }
@@ -2250,7 +2243,7 @@
       resultDigits[j] = gDigits[j];
     }
     var resultUsed = gUsed;
-    var result2Used;
+    int result2Used;
     for (int i = exponentBitlen - 2; i >= 0; i--) {
       result2Used = z.sqr(resultDigits, resultUsed, result2Digits);
       if (!(exponent & (one << i))._isZero) {
@@ -2325,19 +2318,19 @@
     // Variables a, b, c, and d require one more digit.
     final abcdUsed = maxUsed + 1;
     final abcdLen = abcdUsed + 2; // +2 to satisfy _absAdd.
-    var aDigits, bDigits, cDigits, dDigits;
-    bool aIsNegative, bIsNegative, cIsNegative, dIsNegative;
+    var aDigits = _dummyList;
+    var aIsNegative = false;
+    var cDigits = _dummyList;
+    var cIsNegative = false;
     if (ac) {
       aDigits = new Uint16List(abcdLen);
-      aIsNegative = false;
       aDigits[0] = 1;
       cDigits = new Uint16List(abcdLen);
-      cIsNegative = false;
     }
-    bDigits = new Uint16List(abcdLen);
-    bIsNegative = false;
-    dDigits = new Uint16List(abcdLen);
-    dIsNegative = false;
+    var bDigits = new Uint16List(abcdLen);
+    var bIsNegative = false;
+    var dDigits = new Uint16List(abcdLen);
+    var dIsNegative = false;
     dDigits[0] = 1;
 
     while (true) {
@@ -2528,8 +2521,7 @@
   ///
   /// It is an error if no modular inverse exists.
   // Returns 1/this % modulus, with modulus > 0.
-  _BigIntImpl modInverse(BigInt bigInt) {
-    _BigIntImpl modulus = bigInt;
+  _BigIntImpl modInverse(covariant _BigIntImpl modulus) {
     if (modulus <= zero) {
       throw new ArgumentError("Modulus must be strictly positive: $modulus");
     }
@@ -2552,8 +2544,7 @@
   /// For any integer `x`, `x.gcd(x)` is `x.abs()`.
   ///
   /// If both `this` and `other` is zero, the result is also zero.
-  _BigIntImpl gcd(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl gcd(covariant _BigIntImpl other) {
     if (_isZero) return other.abs();
     if (other._isZero) return this.abs();
     return _binaryGcd(this, other, false);
@@ -2863,8 +2854,8 @@
                 _modulus._digits[_modulus._used - 1].bitLength);
 
   int convert(_BigIntImpl x, Uint16List resultDigits) {
-    var digits;
-    var used;
+    Uint16List digits;
+    int used;
     if (x._isNegative || x._absCompare(_modulus) >= 0) {
       var remainder = x._rem(_modulus);
       if (x._isNegative && remainder._used > 0) {
diff --git a/sdk/lib/_internal/js_runtime/lib/developer_patch.dart b/sdk/lib/_internal/js_runtime/lib/developer_patch.dart
index 0ff0f66..6156f5e 100644
--- a/sdk/lib/_internal/js_runtime/lib/developer_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/developer_patch.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.
 
+// @dart = 2.6
+
 // Patch file for dart:developer library.
 
 import 'dart:_js_helper' show patch, ForceInline;
diff --git a/sdk/lib/_internal/js_runtime/lib/foreign_helper.dart b/sdk/lib/_internal/js_runtime/lib/foreign_helper.dart
index 0cecf96..f2a7c77 100644
--- a/sdk/lib/_internal/js_runtime/lib/foreign_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/foreign_helper.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.
 
+// @dart = 2.6
+
 library _foreign_helper;
 
 import 'dart:_js_embedded_names' show JsGetName, JsBuiltin;
diff --git a/sdk/lib/_internal/js_runtime/lib/instantiation.dart b/sdk/lib/_internal/js_runtime/lib/instantiation.dart
index bb003e6..666cd69 100644
--- a/sdk/lib/_internal/js_runtime/lib/instantiation.dart
+++ b/sdk/lib/_internal/js_runtime/lib/instantiation.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.
 
+// @dart = 2.6
+
 part of _js_helper;
 
 /// Support class for generic function type instantiation (binding of types).
diff --git a/sdk/lib/_internal/js_runtime/lib/interceptors.dart b/sdk/lib/_internal/js_runtime/lib/interceptors.dart
index b676c1b..e0aa397 100644
--- a/sdk/lib/_internal/js_runtime/lib/interceptors.dart
+++ b/sdk/lib/_internal/js_runtime/lib/interceptors.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.
 
+// @dart = 2.6
+
 library _interceptors;
 
 import 'dart:_js_embedded_names'
diff --git a/sdk/lib/_internal/js_runtime/lib/internal_patch.dart b/sdk/lib/_internal/js_runtime/lib/internal_patch.dart
index 77884e2..7e3b456 100644
--- a/sdk/lib/_internal/js_runtime/lib/internal_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/internal_patch.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.
 
+// @dart = 2.6
+
 import 'dart:core' hide Symbol;
 import 'dart:core' as core;
 import 'dart:_js_primitives' show printString;
diff --git a/sdk/lib/_internal/js_runtime/lib/io_patch.dart b/sdk/lib/_internal/js_runtime/lib/io_patch.dart
index ee1eb4d..37aa15c 100644
--- a/sdk/lib/_internal/js_runtime/lib/io_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/io_patch.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.
 
+// @dart = 2.6
+
 import 'dart:_js_helper' show patch;
 import 'dart:_internal' hide Symbol;
 import 'dart:async';
diff --git a/sdk/lib/_internal/js_runtime/lib/isolate_patch.dart b/sdk/lib/_internal/js_runtime/lib/isolate_patch.dart
index d781e7a..bb6363f 100644
--- a/sdk/lib/_internal/js_runtime/lib/isolate_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/isolate_patch.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.
 
+// @dart = 2.6
+
 // Patch file for the dart:isolate library.
 
 import "dart:async";
diff --git a/sdk/lib/_internal/js_runtime/lib/js_array.dart b/sdk/lib/_internal/js_runtime/lib/js_array.dart
index ff820d4..7b92c3d 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_array.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_array.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.
 
+// @dart = 2.6
+
 part of _interceptors;
 
 class _Growable {
diff --git a/sdk/lib/_internal/js_runtime/lib/js_helper.dart b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
index a9fd83b..4f332f4 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_helper.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.
 
+// @dart = 2.6
+
 library _js_helper;
 
 import 'dart:_js_embedded_names'
diff --git a/sdk/lib/_internal/js_runtime/lib/js_names.dart b/sdk/lib/_internal/js_runtime/lib/js_names.dart
index cb4aa0e..767eced 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_names.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_names.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.
 
+// @dart = 2.6
+
 library dart._js_names;
 
 import 'dart:_js_embedded_names'
diff --git a/sdk/lib/_internal/js_runtime/lib/js_number.dart b/sdk/lib/_internal/js_runtime/lib/js_number.dart
index 918c1ba..610312b 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_number.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_number.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.
 
+// @dart = 2.6
+
 part of _interceptors;
 
 /// The super interceptor class for [JSInt] and [JSDouble]. The compiler
diff --git a/sdk/lib/_internal/js_runtime/lib/js_primitives.dart b/sdk/lib/_internal/js_runtime/lib/js_primitives.dart
index 97577a0..5422333 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_primitives.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_primitives.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.
 
+// @dart = 2.6
+
 /// dart2js "primitives", that is, features that cannot be implemented without
 /// access to JavaScript features.
 library dart2js._js_primitives;
diff --git a/sdk/lib/_internal/js_runtime/lib/js_rti.dart b/sdk/lib/_internal/js_runtime/lib/js_rti.dart
index 762cd88..056e267 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_rti.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_rti.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.
 
+// @dart = 2.6
+
 /// This part contains helpers for supporting runtime type information.
 ///
 /// The helper use a mixture of Dart and JavaScript objects. To indicate which
diff --git a/sdk/lib/_internal/js_runtime/lib/js_string.dart b/sdk/lib/_internal/js_runtime/lib/js_string.dart
index 39370d7..d6af957 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_string.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_string.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.
 
+// @dart = 2.6
+
 part of _interceptors;
 
 /// The interceptor class for [String]. The compiler recognizes this
diff --git a/sdk/lib/_internal/js_runtime/lib/linked_hash_map.dart b/sdk/lib/_internal/js_runtime/lib/linked_hash_map.dart
index 42ad0c4..dab8542 100644
--- a/sdk/lib/_internal/js_runtime/lib/linked_hash_map.dart
+++ b/sdk/lib/_internal/js_runtime/lib/linked_hash_map.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.
 
+// @dart = 2.6
+
 // Efficient JavaScript based implementation of a linked hash map used as a
 // backing map for constant maps and the [LinkedHashMap] patch
 
diff --git a/sdk/lib/_internal/js_runtime/lib/math_patch.dart b/sdk/lib/_internal/js_runtime/lib/math_patch.dart
index 677953e..fc33945 100644
--- a/sdk/lib/_internal/js_runtime/lib/math_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/math_patch.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.
 
+// @dart = 2.6
+
 // Patch file for dart:math library.
 import 'dart:_foreign_helper' show JS;
 import 'dart:_js_helper' show patch, checkNum;
diff --git a/sdk/lib/_internal/js_runtime/lib/mirrors_patch_cfe.dart b/sdk/lib/_internal/js_runtime/lib/mirrors_patch_cfe.dart
index 6f8018a..767de5f 100644
--- a/sdk/lib/_internal/js_runtime/lib/mirrors_patch_cfe.dart
+++ b/sdk/lib/_internal/js_runtime/lib/mirrors_patch_cfe.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.
 
+// @dart = 2.6
+
 // Patch library for dart:mirrors.
 
 import 'dart:_js_helper' show patch;
diff --git a/sdk/lib/_internal/js_runtime/lib/native_helper.dart b/sdk/lib/_internal/js_runtime/lib/native_helper.dart
index ccfa26f..d8d4e1d 100644
--- a/sdk/lib/_internal/js_runtime/lib/native_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/native_helper.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.
 
+// @dart = 2.6
+
 part of _js_helper;
 
 // TODO(ngeoffray): stop using this method once our optimizers can
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 0a91641..db57ca3 100644
--- a/sdk/lib/_internal/js_runtime/lib/native_typed_data.dart
+++ b/sdk/lib/_internal/js_runtime/lib/native_typed_data.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.
 
+// @dart = 2.6
+
 /// Specialized integers and floating point numbers,
 /// with SIMD support and efficient lists.
 library dart.typed_data.implementation;
diff --git a/sdk/lib/_internal/js_runtime/lib/regexp_helper.dart b/sdk/lib/_internal/js_runtime/lib/regexp_helper.dart
index 3dacc06..576caaa 100644
--- a/sdk/lib/_internal/js_runtime/lib/regexp_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/regexp_helper.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.
 
+// @dart = 2.6
+
 part of _js_helper;
 
 // Helper method used by internal libraries.
diff --git a/sdk/lib/_internal/js_runtime/lib/rti.dart b/sdk/lib/_internal/js_runtime/lib/rti.dart
index 5a8d3b9..8174aea 100644
--- a/sdk/lib/_internal/js_runtime/lib/rti.dart
+++ b/sdk/lib/_internal/js_runtime/lib/rti.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.
 
+// @dart = 2.6
+
 /// This library contains support for runtime type information.
 library rti;
 
diff --git a/sdk/lib/_internal/js_runtime/lib/shared/async_await_error_codes.dart b/sdk/lib/_internal/js_runtime/lib/shared/async_await_error_codes.dart
index f87406b..5bcc512 100644
--- a/sdk/lib/_internal/js_runtime/lib/shared/async_await_error_codes.dart
+++ b/sdk/lib/_internal/js_runtime/lib/shared/async_await_error_codes.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.
 
+// @dart = 2.6
+
 /// Contains error codes that transformed async/async* functions use to
 /// communicate with js_helper functions.
 
diff --git a/sdk/lib/_internal/js_runtime/lib/shared/embedded_names.dart b/sdk/lib/_internal/js_runtime/lib/shared/embedded_names.dart
index 8456b8b..0ac7488 100644
--- a/sdk/lib/_internal/js_runtime/lib/shared/embedded_names.dart
+++ b/sdk/lib/_internal/js_runtime/lib/shared/embedded_names.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.
 
+// @dart = 2.6
+
 /// Contains the names of globals that are embedded into the output by the
 /// compiler.
 ///
diff --git a/sdk/lib/_internal/js_runtime/lib/shared/recipe_syntax.dart b/sdk/lib/_internal/js_runtime/lib/shared/recipe_syntax.dart
index ef7fbff..3b35902 100644
--- a/sdk/lib/_internal/js_runtime/lib/shared/recipe_syntax.dart
+++ b/sdk/lib/_internal/js_runtime/lib/shared/recipe_syntax.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.
 
+// @dart = 2.6
+
 /// Constants and predicates used for encoding and decoding type recipes.
 ///
 /// This library is shared between the compiler and the runtime system.
diff --git a/sdk/lib/_internal/js_runtime/lib/string_helper.dart b/sdk/lib/_internal/js_runtime/lib/string_helper.dart
index ea5374e..eff8783 100644
--- a/sdk/lib/_internal/js_runtime/lib/string_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/string_helper.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.
 
+// @dart = 2.6
+
 part of _js_helper;
 
 stringIndexOfStringUnchecked(receiver, other, startIndex) {
diff --git a/sdk/lib/_internal/js_runtime/lib/typed_data_patch.dart b/sdk/lib/_internal/js_runtime/lib/typed_data_patch.dart
index 615c9da..a4a93ab 100644
--- a/sdk/lib/_internal/js_runtime/lib/typed_data_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/typed_data_patch.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.
 
+// @dart = 2.6
+
 import 'dart:_js_helper' show patch;
 import 'dart:_native_typed_data';
 
diff --git a/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart b/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart
index ffb8ed3..14b5e23 100644
--- a/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart
+++ b/sdk/lib/_internal/sdk_library_metadata/lib/libraries.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.
 
+// @dart = 2.6
+
 library libraries;
 
 /**
diff --git a/sdk/lib/_internal/vm/bin/builtin.dart b/sdk/lib/_internal/vm/bin/builtin.dart
index 23c5dc7..dde9727 100644
--- a/sdk/lib/_internal/vm/bin/builtin.dart
+++ b/sdk/lib/_internal/vm/bin/builtin.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.
 
+// @dart = 2.6
+
 library builtin;
 
 // NOTE: Do not import 'dart:io' in builtin.
diff --git a/sdk/lib/_internal/vm/bin/cli_patch.dart b/sdk/lib/_internal/vm/bin/cli_patch.dart
index 504a0db..0ccae81 100644
--- a/sdk/lib/_internal/vm/bin/cli_patch.dart
+++ b/sdk/lib/_internal/vm/bin/cli_patch.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.
 
+// @dart = 2.6
+
 import "dart:_internal" show patch;
 
 @patch
diff --git a/sdk/lib/_internal/vm/bin/common_patch.dart b/sdk/lib/_internal/vm/bin/common_patch.dart
index 1bcd089..1b69371 100644
--- a/sdk/lib/_internal/vm/bin/common_patch.dart
+++ b/sdk/lib/_internal/vm/bin/common_patch.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.
 
+// @dart = 2.6
+
 /// Note: the VM concatenates all patch files into a single patch file. This
 /// file is the first patch in "dart:io" which contains all the imports used by
 /// patches of that library. We plan to change this when we have a shared front
diff --git a/sdk/lib/_internal/vm/bin/directory_patch.dart b/sdk/lib/_internal/vm/bin/directory_patch.dart
index 7549f72..c6b7806 100644
--- a/sdk/lib/_internal/vm/bin/directory_patch.dart
+++ b/sdk/lib/_internal/vm/bin/directory_patch.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.
 
+// @dart = 2.6
+
 // part of "common_patch.dart";
 
 @patch
diff --git a/sdk/lib/_internal/vm/bin/eventhandler_patch.dart b/sdk/lib/_internal/vm/bin/eventhandler_patch.dart
index 11ada47..1b5c5c8 100644
--- a/sdk/lib/_internal/vm/bin/eventhandler_patch.dart
+++ b/sdk/lib/_internal/vm/bin/eventhandler_patch.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.
 
+// @dart = 2.6
+
 // part of "common_patch.dart";
 
 @patch
diff --git a/sdk/lib/_internal/vm/bin/file_patch.dart b/sdk/lib/_internal/vm/bin/file_patch.dart
index a404aa0..01681f4 100644
--- a/sdk/lib/_internal/vm/bin/file_patch.dart
+++ b/sdk/lib/_internal/vm/bin/file_patch.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.
 
+// @dart = 2.6
+
 // part of "common_patch.dart";
 
 @patch
diff --git a/sdk/lib/_internal/vm/bin/file_system_entity_patch.dart b/sdk/lib/_internal/vm/bin/file_system_entity_patch.dart
index 973e6b6..1f081c7 100644
--- a/sdk/lib/_internal/vm/bin/file_system_entity_patch.dart
+++ b/sdk/lib/_internal/vm/bin/file_system_entity_patch.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.
 
+// @dart = 2.6
+
 // part of "common_patch.dart";
 
 @patch
diff --git a/sdk/lib/_internal/vm/bin/filter_patch.dart b/sdk/lib/_internal/vm/bin/filter_patch.dart
index 6f556b6..0594b6b 100644
--- a/sdk/lib/_internal/vm/bin/filter_patch.dart
+++ b/sdk/lib/_internal/vm/bin/filter_patch.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.
 
+// @dart = 2.6
+
 // part of "common_patch.dart";
 
 class _FilterImpl extends NativeFieldWrapperClass1 implements RawZLibFilter {
diff --git a/sdk/lib/_internal/vm/bin/io_service_patch.dart b/sdk/lib/_internal/vm/bin/io_service_patch.dart
index d763ebb..5159869 100644
--- a/sdk/lib/_internal/vm/bin/io_service_patch.dart
+++ b/sdk/lib/_internal/vm/bin/io_service_patch.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.
 
+// @dart = 2.6
+
 // part of "common_patch.dart";
 
 class _IOServicePorts {
diff --git a/sdk/lib/_internal/vm/bin/namespace_patch.dart b/sdk/lib/_internal/vm/bin/namespace_patch.dart
index d8b7295..60bbb5e 100644
--- a/sdk/lib/_internal/vm/bin/namespace_patch.dart
+++ b/sdk/lib/_internal/vm/bin/namespace_patch.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.
 
+// @dart = 2.6
+
 @pragma("vm:entry-point")
 class _NamespaceImpl extends NativeFieldWrapperClass1 implements _Namespace {
   _NamespaceImpl._();
diff --git a/sdk/lib/_internal/vm/bin/platform_patch.dart b/sdk/lib/_internal/vm/bin/platform_patch.dart
index 99b4e7c..a9c1040 100644
--- a/sdk/lib/_internal/vm/bin/platform_patch.dart
+++ b/sdk/lib/_internal/vm/bin/platform_patch.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.
 
+// @dart = 2.6
+
 // part of "common_patch.dart";
 
 @patch
diff --git a/sdk/lib/_internal/vm/bin/process_patch.dart b/sdk/lib/_internal/vm/bin/process_patch.dart
index 86b6de3..7fc67dc 100644
--- a/sdk/lib/_internal/vm/bin/process_patch.dart
+++ b/sdk/lib/_internal/vm/bin/process_patch.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.
 
+// @dart = 2.6
+
 // part of "common_patch.dart";
 
 @patch
diff --git a/sdk/lib/_internal/vm/bin/secure_socket_patch.dart b/sdk/lib/_internal/vm/bin/secure_socket_patch.dart
index 80dfd54..117f90f 100644
--- a/sdk/lib/_internal/vm/bin/secure_socket_patch.dart
+++ b/sdk/lib/_internal/vm/bin/secure_socket_patch.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.
 
+// @dart = 2.6
+
 // part of "common_patch.dart";
 
 @patch
diff --git a/sdk/lib/_internal/vm/bin/socket_patch.dart b/sdk/lib/_internal/vm/bin/socket_patch.dart
index b0ce8e6..5771c76 100644
--- a/sdk/lib/_internal/vm/bin/socket_patch.dart
+++ b/sdk/lib/_internal/vm/bin/socket_patch.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.
 
+// @dart = 2.6
+
 // part of "common_patch.dart";
 
 @patch
diff --git a/sdk/lib/_internal/vm/bin/stdio_patch.dart b/sdk/lib/_internal/vm/bin/stdio_patch.dart
index ca8f16e..1303573 100644
--- a/sdk/lib/_internal/vm/bin/stdio_patch.dart
+++ b/sdk/lib/_internal/vm/bin/stdio_patch.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.
 
+// @dart = 2.6
+
 // part of "common_patch.dart";
 
 @patch
diff --git a/sdk/lib/_internal/vm/bin/sync_socket_patch.dart b/sdk/lib/_internal/vm/bin/sync_socket_patch.dart
index 332d772..d98649e 100644
--- a/sdk/lib/_internal/vm/bin/sync_socket_patch.dart
+++ b/sdk/lib/_internal/vm/bin/sync_socket_patch.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.
 
+// @dart = 2.6
+
 // part of "common_patch.dart";
 
 @patch
diff --git a/sdk/lib/_internal/vm/lib/array.dart b/sdk/lib/_internal/vm/lib/array.dart
index 57e1624..1b75894 100644
--- a/sdk/lib/_internal/vm/lib/array.dart
+++ b/sdk/lib/_internal/vm/lib/array.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.
 
+// @dart = 2.6
+
 // part of "core_patch.dart";
 
 @pragma("vm:entry-point")
diff --git a/sdk/lib/_internal/vm/lib/array_patch.dart b/sdk/lib/_internal/vm/lib/array_patch.dart
index 5c308a2..26e6865 100644
--- a/sdk/lib/_internal/vm/lib/array_patch.dart
+++ b/sdk/lib/_internal/vm/lib/array_patch.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.
 
+// @dart = 2.6
+
 // part of "core_patch.dart";
 
 @patch
diff --git a/sdk/lib/_internal/vm/lib/async_patch.dart b/sdk/lib/_internal/vm/lib/async_patch.dart
index c1143fb7..7e9aff7 100644
--- a/sdk/lib/_internal/vm/lib/async_patch.dart
+++ b/sdk/lib/_internal/vm/lib/async_patch.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.
 
+// @dart = 2.6
+
 /// Note: the VM concatenates all patch files into a single patch file. This
 /// file is the first patch in "dart:async" which contains all the imports used
 /// by patches of that library. We plan to change this when we have a shared
diff --git a/sdk/lib/_internal/vm/lib/bigint_patch.dart b/sdk/lib/_internal/vm/lib/bigint_patch.dart
index e49305d..61958dc 100644
--- a/sdk/lib/_internal/vm/lib/bigint_patch.dart
+++ b/sdk/lib/_internal/vm/lib/bigint_patch.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.
 
+// @dart = 2.6
+
 // part of dart.core;
 
 // Copyright 2009 The Go Authors. All rights reserved.
diff --git a/sdk/lib/_internal/vm/lib/bool_patch.dart b/sdk/lib/_internal/vm/lib/bool_patch.dart
index 8fffd63..a969c02 100644
--- a/sdk/lib/_internal/vm/lib/bool_patch.dart
+++ b/sdk/lib/_internal/vm/lib/bool_patch.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.
 
+// @dart = 2.6
+
 // part of "core_patch.dart";
 
 @patch
diff --git a/sdk/lib/_internal/vm/lib/class_id.dart b/sdk/lib/_internal/vm/lib/class_id.dart
index ff9d0b6..c1e8621 100644
--- a/sdk/lib/_internal/vm/lib/class_id.dart
+++ b/sdk/lib/_internal/vm/lib/class_id.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.
 
+// @dart = 2.6
+
 // part of "internal_patch.dart";
 
 @pragma("vm:entry-point")
diff --git a/sdk/lib/_internal/vm/lib/class_id_fasta.dart b/sdk/lib/_internal/vm/lib/class_id_fasta.dart
index c95930f..8732d2e 100644
--- a/sdk/lib/_internal/vm/lib/class_id_fasta.dart
+++ b/sdk/lib/_internal/vm/lib/class_id_fasta.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.
 
+// @dart = 2.6
+
 // part of "internal_patch.dart";
 
 @pragma("vm:entry-point")
diff --git a/sdk/lib/_internal/vm/lib/collection_patch.dart b/sdk/lib/_internal/vm/lib/collection_patch.dart
index 83f12ca..5364eb5 100644
--- a/sdk/lib/_internal/vm/lib/collection_patch.dart
+++ b/sdk/lib/_internal/vm/lib/collection_patch.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.
 
+// @dart = 2.6
+
 /// Note: the VM concatenates all patch files into a single patch file. This
 /// file is the first patch in "dart:collection" which contains all the imports
 /// used by patches of that library. We plan to change this when we have a
diff --git a/sdk/lib/_internal/vm/lib/compact_hash.dart b/sdk/lib/_internal/vm/lib/compact_hash.dart
index f9ccfc0..112b9ba 100644
--- a/sdk/lib/_internal/vm/lib/compact_hash.dart
+++ b/sdk/lib/_internal/vm/lib/compact_hash.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.
 
+// @dart = 2.6
+
 // part of "collection_patch.dart";
 
 // Hash table with open addressing that separates the index from keys/values.
diff --git a/sdk/lib/_internal/vm/lib/convert_patch.dart b/sdk/lib/_internal/vm/lib/convert_patch.dart
index 747e1e3..d2c5f45 100644
--- a/sdk/lib/_internal/vm/lib/convert_patch.dart
+++ b/sdk/lib/_internal/vm/lib/convert_patch.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.
 
+// @dart = 2.6
+
 /// Note: the VM concatenates all patch files into a single patch file. This
 /// file is the first patch in "dart:convert" which contains all the imports
 /// used by patches of that library. We plan to change this when we have a
diff --git a/sdk/lib/_internal/vm/lib/core_patch.dart b/sdk/lib/_internal/vm/lib/core_patch.dart
index c095178..eaf9d93 100644
--- a/sdk/lib/_internal/vm/lib/core_patch.dart
+++ b/sdk/lib/_internal/vm/lib/core_patch.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.
 
+// @dart = 2.6
+
 /// Note: the VM concatenates all patch files into a single patch file. This
 /// file is the first patch in "dart:core" which contains all the imports
 /// used by patches of that library. We plan to change this when we have a
diff --git a/sdk/lib/_internal/vm/lib/date_patch.dart b/sdk/lib/_internal/vm/lib/date_patch.dart
index 1899e0c..25d22df 100644
--- a/sdk/lib/_internal/vm/lib/date_patch.dart
+++ b/sdk/lib/_internal/vm/lib/date_patch.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.
 
+// @dart = 2.6
+
 // part of "core_patch.dart";
 
 // VM implementation of DateTime.
diff --git a/sdk/lib/_internal/vm/lib/deferred_load_patch.dart b/sdk/lib/_internal/vm/lib/deferred_load_patch.dart
index 554b44f..0ab5e98 100644
--- a/sdk/lib/_internal/vm/lib/deferred_load_patch.dart
+++ b/sdk/lib/_internal/vm/lib/deferred_load_patch.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.
 
+// @dart = 2.6
+
 // part of "async_patch.dart";
 
 final Set<String> _loadedLibraries = new Set<String>();
diff --git a/sdk/lib/_internal/vm/lib/developer.dart b/sdk/lib/_internal/vm/lib/developer.dart
index cb35073..d6ab6af 100644
--- a/sdk/lib/_internal/vm/lib/developer.dart
+++ b/sdk/lib/_internal/vm/lib/developer.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.
 
+// @dart = 2.6
+
 /// Note: the VM concatenates all patch files into a single patch file. This
 /// file is the first patch in "dart:developer" which contains all the imports
 /// used by patches of that library. We plan to change this when we have a
diff --git a/sdk/lib/_internal/vm/lib/double.dart b/sdk/lib/_internal/vm/lib/double.dart
index 71adedd..321fc39 100644
--- a/sdk/lib/_internal/vm/lib/double.dart
+++ b/sdk/lib/_internal/vm/lib/double.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.
 
+// @dart = 2.6
+
 // part of "core_patch.dart";
 
 @pragma("vm:entry-point")
diff --git a/sdk/lib/_internal/vm/lib/double_patch.dart b/sdk/lib/_internal/vm/lib/double_patch.dart
index a621e66..c70ab77 100644
--- a/sdk/lib/_internal/vm/lib/double_patch.dart
+++ b/sdk/lib/_internal/vm/lib/double_patch.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.
 
+// @dart = 2.6
+
 // part of "core_patch.dart";
 
 // VM implementation of double.
diff --git a/sdk/lib/_internal/vm/lib/empty_source.dart b/sdk/lib/_internal/vm/lib/empty_source.dart
index 95e028f..e5dbe09 100644
--- a/sdk/lib/_internal/vm/lib/empty_source.dart
+++ b/sdk/lib/_internal/vm/lib/empty_source.dart
@@ -2,4 +2,6 @@
 // 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.6
+
 // THIS FILE INTENTIONALLY LEFT BLANK.
diff --git a/sdk/lib/_internal/vm/lib/errors_patch.dart b/sdk/lib/_internal/vm/lib/errors_patch.dart
index a8cb80c..9a1d4e3 100644
--- a/sdk/lib/_internal/vm/lib/errors_patch.dart
+++ b/sdk/lib/_internal/vm/lib/errors_patch.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.
 
+// @dart = 2.6
+
 // part of "core_patch.dart";
 
 @patch
diff --git a/sdk/lib/_internal/vm/lib/expando_patch.dart b/sdk/lib/_internal/vm/lib/expando_patch.dart
index a1400b6..7653c26 100644
--- a/sdk/lib/_internal/vm/lib/expando_patch.dart
+++ b/sdk/lib/_internal/vm/lib/expando_patch.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.
 
+// @dart = 2.6
+
 // part of "core_patch.dart";
 
 @patch
diff --git a/sdk/lib/_internal/vm/lib/ffi_dynamic_library_patch.dart b/sdk/lib/_internal/vm/lib/ffi_dynamic_library_patch.dart
index 81fac07..b616ffc 100644
--- a/sdk/lib/_internal/vm/lib/ffi_dynamic_library_patch.dart
+++ b/sdk/lib/_internal/vm/lib/ffi_dynamic_library_patch.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.
 
+// @dart = 2.6
+
 // All imports must be in all FFI patch files to not depend on the order
 // the patches are applied.
 import "dart:_internal" show patch;
diff --git a/sdk/lib/_internal/vm/lib/ffi_native_type_patch.dart b/sdk/lib/_internal/vm/lib/ffi_native_type_patch.dart
index 473ba7a..586e041 100644
--- a/sdk/lib/_internal/vm/lib/ffi_native_type_patch.dart
+++ b/sdk/lib/_internal/vm/lib/ffi_native_type_patch.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.
 
+// @dart = 2.6
+
 // All imports must be in all FFI patch files to not depend on the order
 // the patches are applied.
 import "dart:_internal" show patch;
diff --git a/sdk/lib/_internal/vm/lib/ffi_patch.dart b/sdk/lib/_internal/vm/lib/ffi_patch.dart
index 71706ef..33baa8f 100644
--- a/sdk/lib/_internal/vm/lib/ffi_patch.dart
+++ b/sdk/lib/_internal/vm/lib/ffi_patch.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.
 
+// @dart = 2.6
+
 // All imports must be in all FFI patch files to not depend on the order
 // the patches are applied.
 import "dart:_internal" show patch;
diff --git a/sdk/lib/_internal/vm/lib/function.dart b/sdk/lib/_internal/vm/lib/function.dart
index 1c99ca2..128a7dd 100644
--- a/sdk/lib/_internal/vm/lib/function.dart
+++ b/sdk/lib/_internal/vm/lib/function.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.
 
+// @dart = 2.6
+
 // part of "core_patch.dart";
 
 @pragma("vm:entry-point")
diff --git a/sdk/lib/_internal/vm/lib/function_patch.dart b/sdk/lib/_internal/vm/lib/function_patch.dart
index 0c88b4e..9d33e30 100644
--- a/sdk/lib/_internal/vm/lib/function_patch.dart
+++ b/sdk/lib/_internal/vm/lib/function_patch.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.
 
+// @dart = 2.6
+
 // part of "core_patch.dart";
 
 @patch
diff --git a/sdk/lib/_internal/vm/lib/growable_array.dart b/sdk/lib/_internal/vm/lib/growable_array.dart
index f69ed92..c2f54db 100644
--- a/sdk/lib/_internal/vm/lib/growable_array.dart
+++ b/sdk/lib/_internal/vm/lib/growable_array.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.
 
+// @dart = 2.6
+
 // part of "core_patch.dart";
 
 @pragma("vm:entry-point")
diff --git a/sdk/lib/_internal/vm/lib/identical_patch.dart b/sdk/lib/_internal/vm/lib/identical_patch.dart
index 7fa8959..3e4dc1e 100644
--- a/sdk/lib/_internal/vm/lib/identical_patch.dart
+++ b/sdk/lib/_internal/vm/lib/identical_patch.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.
 
+// @dart = 2.6
+
 // part of "core_patch.dart";
 
 @patch
diff --git a/sdk/lib/_internal/vm/lib/immutable_map.dart b/sdk/lib/_internal/vm/lib/immutable_map.dart
index 8fbe3d9..86e5d8d 100644
--- a/sdk/lib/_internal/vm/lib/immutable_map.dart
+++ b/sdk/lib/_internal/vm/lib/immutable_map.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.
 
+// @dart = 2.6
+
 // part of "core_patch.dart";
 
 /// Immutable map class for compiler generated map literals.
diff --git a/sdk/lib/_internal/vm/lib/integers.dart b/sdk/lib/_internal/vm/lib/integers.dart
index 9b3bd8e..19495a8 100644
--- a/sdk/lib/_internal/vm/lib/integers.dart
+++ b/sdk/lib/_internal/vm/lib/integers.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.
 
+// @dart = 2.6
+
 // part of "core_patch.dart";
 
 abstract class _IntegerImplementation implements int {
diff --git a/sdk/lib/_internal/vm/lib/integers_patch.dart b/sdk/lib/_internal/vm/lib/integers_patch.dart
index dc0a20a..9a2fb54 100644
--- a/sdk/lib/_internal/vm/lib/integers_patch.dart
+++ b/sdk/lib/_internal/vm/lib/integers_patch.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.
 
+// @dart = 2.6
+
 // part of "core_patch.dart";
 
 /// VM implementation of int.
diff --git a/sdk/lib/_internal/vm/lib/internal_patch.dart b/sdk/lib/_internal/vm/lib/internal_patch.dart
index fe05552..9a6cdb4 100644
--- a/sdk/lib/_internal/vm/lib/internal_patch.dart
+++ b/sdk/lib/_internal/vm/lib/internal_patch.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.
 
+// @dart = 2.6
+
 /// Note: the VM concatenates all patch files into a single patch file. This
 /// file is the first patch in "dart:_internal" which contains all the imports
 /// used by patches of that library. We plan to change this when we have a
diff --git a/sdk/lib/_internal/vm/lib/invocation_mirror_patch.dart b/sdk/lib/_internal/vm/lib/invocation_mirror_patch.dart
index e7e2fe3..05d0d81 100644
--- a/sdk/lib/_internal/vm/lib/invocation_mirror_patch.dart
+++ b/sdk/lib/_internal/vm/lib/invocation_mirror_patch.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.
 
+// @dart = 2.6
+
 // part of "core_patch.dart";
 
 // NOTE: When making changes to this class, please also update
diff --git a/sdk/lib/_internal/vm/lib/isolate_patch.dart b/sdk/lib/_internal/vm/lib/isolate_patch.dart
index f43d181..f5e75c9 100644
--- a/sdk/lib/_internal/vm/lib/isolate_patch.dart
+++ b/sdk/lib/_internal/vm/lib/isolate_patch.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.
 
+// @dart = 2.6
+
 /// Note: the VM concatenates all patch files into a single patch file. This
 /// file is the first patch in "dart:isolate" which contains all the imports
 /// used by patches of that library. We plan to change this when we have a
diff --git a/sdk/lib/_internal/vm/lib/lib_prefix.dart b/sdk/lib/_internal/vm/lib/lib_prefix.dart
index f588ee3..00b934c 100644
--- a/sdk/lib/_internal/vm/lib/lib_prefix.dart
+++ b/sdk/lib/_internal/vm/lib/lib_prefix.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.
 
+// @dart = 2.6
+
 // part of "core_patch.dart";
 
 // This type corresponds to the VM-internal class LibraryPrefix.
diff --git a/sdk/lib/_internal/vm/lib/map_patch.dart b/sdk/lib/_internal/vm/lib/map_patch.dart
index 07dbc69..cda2946 100644
--- a/sdk/lib/_internal/vm/lib/map_patch.dart
+++ b/sdk/lib/_internal/vm/lib/map_patch.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.
 
+// @dart = 2.6
+
 // part of "core_patch.dart";
 
 @patch
diff --git a/sdk/lib/_internal/vm/lib/math_patch.dart b/sdk/lib/_internal/vm/lib/math_patch.dart
index 99c166e..574e3ed 100644
--- a/sdk/lib/_internal/vm/lib/math_patch.dart
+++ b/sdk/lib/_internal/vm/lib/math_patch.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.
 
+// @dart = 2.6
+
 /// Note: the VM concatenates all patch files into a single patch file. This
 /// file is the first patch in "dart:math" which contains all the imports used
 /// by patches of that library. We plan to change this when we have a shared
diff --git a/sdk/lib/_internal/vm/lib/mirror_reference.dart b/sdk/lib/_internal/vm/lib/mirror_reference.dart
index d203953..4fe5ffe 100644
--- a/sdk/lib/_internal/vm/lib/mirror_reference.dart
+++ b/sdk/lib/_internal/vm/lib/mirror_reference.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.
 
+// @dart = 2.6
+
 // part of "mirrors_patch.dart";
 
 @pragma("vm:entry-point")
diff --git a/sdk/lib/_internal/vm/lib/mirrors_impl.dart b/sdk/lib/_internal/vm/lib/mirrors_impl.dart
index b0231b2..8101907 100644
--- a/sdk/lib/_internal/vm/lib/mirrors_impl.dart
+++ b/sdk/lib/_internal/vm/lib/mirrors_impl.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.
 
+// @dart = 2.6
+
 // part of "mirrors_patch.dart";
 
 var _dirty = false; // Set to true by the VM when more libraries are loaded.
diff --git a/sdk/lib/_internal/vm/lib/mirrors_patch.dart b/sdk/lib/_internal/vm/lib/mirrors_patch.dart
index 9850e91..1adbcbb 100644
--- a/sdk/lib/_internal/vm/lib/mirrors_patch.dart
+++ b/sdk/lib/_internal/vm/lib/mirrors_patch.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.
 
+// @dart = 2.6
+
 /// Note: the VM concatenates all patch files into a single patch file. This
 /// file is the first patch in "dart:_internal" which contains all the imports
 /// used by patches of that library. We plan to change this when we have a
diff --git a/sdk/lib/_internal/vm/lib/null_patch.dart b/sdk/lib/_internal/vm/lib/null_patch.dart
index 01bb5aa..3e724f7 100644
--- a/sdk/lib/_internal/vm/lib/null_patch.dart
+++ b/sdk/lib/_internal/vm/lib/null_patch.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.
 
+// @dart = 2.6
+
 // part of "core_patch.dart";
 
 @patch
diff --git a/sdk/lib/_internal/vm/lib/object_patch.dart b/sdk/lib/_internal/vm/lib/object_patch.dart
index 7168118..fe75579 100644
--- a/sdk/lib/_internal/vm/lib/object_patch.dart
+++ b/sdk/lib/_internal/vm/lib/object_patch.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.
 
+// @dart = 2.6
+
 // part of "core_patch.dart";
 
 @pragma("vm:exact-result-type", "dart:core#_Smi")
diff --git a/sdk/lib/_internal/vm/lib/print_patch.dart b/sdk/lib/_internal/vm/lib/print_patch.dart
index f0e7d91..96ee6b4 100644
--- a/sdk/lib/_internal/vm/lib/print_patch.dart
+++ b/sdk/lib/_internal/vm/lib/print_patch.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.
 
+// @dart = 2.6
+
 // part of "internal_patch.dart";
 
 // A print-closure gets a String that should be printed. In general the
diff --git a/sdk/lib/_internal/vm/lib/profiler.dart b/sdk/lib/_internal/vm/lib/profiler.dart
index 745eaa5..4a7140f 100644
--- a/sdk/lib/_internal/vm/lib/profiler.dart
+++ b/sdk/lib/_internal/vm/lib/profiler.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.
 
+// @dart = 2.6
+
 // part of "developer.dart";
 
 @patch
diff --git a/sdk/lib/_internal/vm/lib/regexp_patch.dart b/sdk/lib/_internal/vm/lib/regexp_patch.dart
index 7621bb0..d47099a 100644
--- a/sdk/lib/_internal/vm/lib/regexp_patch.dart
+++ b/sdk/lib/_internal/vm/lib/regexp_patch.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.
 
+// @dart = 2.6
+
 // part of "core_patch.dart";
 
 @patch
diff --git a/sdk/lib/_internal/vm/lib/schedule_microtask_patch.dart b/sdk/lib/_internal/vm/lib/schedule_microtask_patch.dart
index 0f90f1e..b1cfc52 100644
--- a/sdk/lib/_internal/vm/lib/schedule_microtask_patch.dart
+++ b/sdk/lib/_internal/vm/lib/schedule_microtask_patch.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.
 
+// @dart = 2.6
+
 // part of "async_patch.dart";
 
 @patch
diff --git a/sdk/lib/_internal/vm/lib/stacktrace.dart b/sdk/lib/_internal/vm/lib/stacktrace.dart
index 719d55a..94464a5 100644
--- a/sdk/lib/_internal/vm/lib/stacktrace.dart
+++ b/sdk/lib/_internal/vm/lib/stacktrace.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.
 
+// @dart = 2.6
+
 // part of "core_patch.dart";
 
 /// VM internal StackTrace implementation.
diff --git a/sdk/lib/_internal/vm/lib/stopwatch_patch.dart b/sdk/lib/_internal/vm/lib/stopwatch_patch.dart
index 87bc584..baf57aa 100644
--- a/sdk/lib/_internal/vm/lib/stopwatch_patch.dart
+++ b/sdk/lib/_internal/vm/lib/stopwatch_patch.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.
 
+// @dart = 2.6
+
 // part of "core_patch.dart";
 
 @patch
diff --git a/sdk/lib/_internal/vm/lib/string_buffer_patch.dart b/sdk/lib/_internal/vm/lib/string_buffer_patch.dart
index 42e9d0d..d2ecf80 100644
--- a/sdk/lib/_internal/vm/lib/string_buffer_patch.dart
+++ b/sdk/lib/_internal/vm/lib/string_buffer_patch.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.
 
+// @dart = 2.6
+
 // part of "core_patch.dart";
 
 @patch
diff --git a/sdk/lib/_internal/vm/lib/string_patch.dart b/sdk/lib/_internal/vm/lib/string_patch.dart
index 837599b..507d435 100644
--- a/sdk/lib/_internal/vm/lib/string_patch.dart
+++ b/sdk/lib/_internal/vm/lib/string_patch.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.
 
+// @dart = 2.6
+
 // part of "core_patch.dart";
 
 const int _maxAscii = 0x7f;
diff --git a/sdk/lib/_internal/vm/lib/symbol_patch.dart b/sdk/lib/_internal/vm/lib/symbol_patch.dart
index 8b78e85..3671bf7 100644
--- a/sdk/lib/_internal/vm/lib/symbol_patch.dart
+++ b/sdk/lib/_internal/vm/lib/symbol_patch.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.
 
+// @dart = 2.6
+
 // part of "internal_patch.dart";
 
 @patch
diff --git a/sdk/lib/_internal/vm/lib/timeline.dart b/sdk/lib/_internal/vm/lib/timeline.dart
index fc9e698..d2a709e 100644
--- a/sdk/lib/_internal/vm/lib/timeline.dart
+++ b/sdk/lib/_internal/vm/lib/timeline.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.
 
+// @dart = 2.6
+
 // part of "developer.dart";
 
 @patch
diff --git a/sdk/lib/_internal/vm/lib/timer_impl.dart b/sdk/lib/_internal/vm/lib/timer_impl.dart
index d61c71d..2d4623e 100644
--- a/sdk/lib/_internal/vm/lib/timer_impl.dart
+++ b/sdk/lib/_internal/vm/lib/timer_impl.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.
 
+// @dart = 2.6
+
 // part of "isolate_patch.dart";
 
 // Timer heap implemented as a array-based binary heap[0].
diff --git a/sdk/lib/_internal/vm/lib/timer_patch.dart b/sdk/lib/_internal/vm/lib/timer_patch.dart
index c243a86..db181ab 100644
--- a/sdk/lib/_internal/vm/lib/timer_patch.dart
+++ b/sdk/lib/_internal/vm/lib/timer_patch.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.
 
+// @dart = 2.6
+
 // part of "async_patch.dart";
 
 @patch
diff --git a/sdk/lib/_internal/vm/lib/type_patch.dart b/sdk/lib/_internal/vm/lib/type_patch.dart
index 35ce89f..b704cb9 100644
--- a/sdk/lib/_internal/vm/lib/type_patch.dart
+++ b/sdk/lib/_internal/vm/lib/type_patch.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.
 
+// @dart = 2.6
+
 // part of "core_patch.dart";
 
 // These Dart classes correspond to the VM internal implementation classes.
diff --git a/sdk/lib/_internal/vm/lib/typed_data_patch.dart b/sdk/lib/_internal/vm/lib/typed_data_patch.dart
index ed8658d44..2fc0182 100644
--- a/sdk/lib/_internal/vm/lib/typed_data_patch.dart
+++ b/sdk/lib/_internal/vm/lib/typed_data_patch.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.
 
+// @dart = 2.6
+
 /// Note: the VM concatenates all patch files into a single patch file. This
 /// file is the first patch in "dart:typed_data" which contains all the imports
 /// used by patches of that library. We plan to change this when we have a
diff --git a/sdk/lib/_internal/vm/lib/uri_patch.dart b/sdk/lib/_internal/vm/lib/uri_patch.dart
index de10c9e..741f2d0 100644
--- a/sdk/lib/_internal/vm/lib/uri_patch.dart
+++ b/sdk/lib/_internal/vm/lib/uri_patch.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.
 
+// @dart = 2.6
+
 // part of "core_patch.dart";
 
 typedef Uri _UriBaseClosure();
diff --git a/sdk/lib/_internal/vm/lib/wasm_patch.dart b/sdk/lib/_internal/vm/lib/wasm_patch.dart
index 1372932..c24a396 100644
--- a/sdk/lib/_internal/vm/lib/wasm_patch.dart
+++ b/sdk/lib/_internal/vm/lib/wasm_patch.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.
 
+// @dart = 2.6
+
 import 'dart:_internal' show patch;
 import "dart:nativewrappers" show NativeFieldWrapperClass1;
 import 'dart:typed_data';
diff --git a/sdk/lib/_internal/vm/lib/weak_property.dart b/sdk/lib/_internal/vm/lib/weak_property.dart
index bc903e9..ed8e570 100644
--- a/sdk/lib/_internal/vm/lib/weak_property.dart
+++ b/sdk/lib/_internal/vm/lib/weak_property.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.
 
+// @dart = 2.6
+
 // part of "core_patch.dart";
 
 @pragma("vm:entry-point")
diff --git a/sdk/lib/async/async.dart b/sdk/lib/async/async.dart
index b3a5dbd..c58801f 100644
--- a/sdk/lib/async/async.dart
+++ b/sdk/lib/async/async.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.
 
+// @dart = 2.6
+
 /**
  * Support for asynchronous programming,
  * with classes such as Future and Stream.
@@ -87,7 +89,7 @@
  * [asynchronous-programming]: https://www.dartlang.org/docs/dart-up-and-running/ch03.html#dartasync---asynchronous-programming
  * [futures-tutorial]: https://www.dartlang.org/docs/tutorials/futures/
  * [futures-error-handling]: https://www.dartlang.org/articles/futures-and-error-handling/
- * [test-readme]: https://pub.dartlang.org/packages/test
+ * [test-readme]: https://pub.dev/packages/test
  *
  * {@category Core}
  */
diff --git a/sdk/lib/async/async_error.dart b/sdk/lib/async/async_error.dart
index 1520c54..f0e8119 100644
--- a/sdk/lib/async/async_error.dart
+++ b/sdk/lib/async/async_error.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.
 
+// @dart = 2.6
+
 part of dart.async;
 
 _invokeErrorHandler(
diff --git a/sdk/lib/async/broadcast_stream_controller.dart b/sdk/lib/async/broadcast_stream_controller.dart
index 32e4582..c18a682 100644
--- a/sdk/lib/async/broadcast_stream_controller.dart
+++ b/sdk/lib/async/broadcast_stream_controller.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.
 
+// @dart = 2.6
+
 part of dart.async;
 
 class _BroadcastStream<T> extends _ControllerStream<T> {
diff --git a/sdk/lib/async/deferred_load.dart b/sdk/lib/async/deferred_load.dart
index f83d4b8..0019f68 100644
--- a/sdk/lib/async/deferred_load.dart
+++ b/sdk/lib/async/deferred_load.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.
 
+// @dart = 2.6
+
 part of dart.async;
 
 /**
diff --git a/sdk/lib/async/future.dart b/sdk/lib/async/future.dart
index 19c9dbe..7aeee47 100644
--- a/sdk/lib/async/future.dart
+++ b/sdk/lib/async/future.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.
 
+// @dart = 2.6
+
 part of dart.async;
 
 /// A type representing values that are either `Future<T>` or `T`.
diff --git a/sdk/lib/async/future_impl.dart b/sdk/lib/async/future_impl.dart
index 1ec0791..a915b96 100644
--- a/sdk/lib/async/future_impl.dart
+++ b/sdk/lib/async/future_impl.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.
 
+// @dart = 2.6
+
 part of dart.async;
 
 /** The onValue and onError handlers return either a value or a future */
diff --git a/sdk/lib/async/schedule_microtask.dart b/sdk/lib/async/schedule_microtask.dart
index 801490a..40f6523 100644
--- a/sdk/lib/async/schedule_microtask.dart
+++ b/sdk/lib/async/schedule_microtask.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.
 
+// @dart = 2.6
+
 part of dart.async;
 
 typedef void _AsyncCallback();
diff --git a/sdk/lib/async/stream.dart b/sdk/lib/async/stream.dart
index bfa1741..51e9cd1 100644
--- a/sdk/lib/async/stream.dart
+++ b/sdk/lib/async/stream.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.
 
+// @dart = 2.6
+
 part of dart.async;
 
 // -------------------------------------------------------------------
diff --git a/sdk/lib/async/stream_controller.dart b/sdk/lib/async/stream_controller.dart
index 34c6adf..f2854a9 100644
--- a/sdk/lib/async/stream_controller.dart
+++ b/sdk/lib/async/stream_controller.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.
 
+// @dart = 2.6
+
 part of dart.async;
 
 // -------------------------------------------------------------------
diff --git a/sdk/lib/async/stream_impl.dart b/sdk/lib/async/stream_impl.dart
index 14c84a5..b3969fc 100644
--- a/sdk/lib/async/stream_impl.dart
+++ b/sdk/lib/async/stream_impl.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.
 
+// @dart = 2.6
+
 part of dart.async;
 
 /** Abstract and private interface for a place to put events. */
diff --git a/sdk/lib/async/stream_pipe.dart b/sdk/lib/async/stream_pipe.dart
index e526179..5771db4 100644
--- a/sdk/lib/async/stream_pipe.dart
+++ b/sdk/lib/async/stream_pipe.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.
 
+// @dart = 2.6
+
 part of dart.async;
 
 /** Runs user code and takes actions depending on success or failure. */
diff --git a/sdk/lib/async/stream_transformers.dart b/sdk/lib/async/stream_transformers.dart
index 9ec13bd..7cba3ba 100644
--- a/sdk/lib/async/stream_transformers.dart
+++ b/sdk/lib/async/stream_transformers.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.
 
+// @dart = 2.6
+
 part of dart.async;
 
 /**
diff --git a/sdk/lib/async/timer.dart b/sdk/lib/async/timer.dart
index 97560a9..6c42767 100644
--- a/sdk/lib/async/timer.dart
+++ b/sdk/lib/async/timer.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.
 
+// @dart = 2.6
+
 part of dart.async;
 
 /**
diff --git a/sdk/lib/async/zone.dart b/sdk/lib/async/zone.dart
index 7c66de1..d8f8596 100644
--- a/sdk/lib/async/zone.dart
+++ b/sdk/lib/async/zone.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.
 
+// @dart = 2.6
+
 part of dart.async;
 
 typedef R ZoneCallback<R>();
diff --git a/sdk/lib/cli/cli.dart b/sdk/lib/cli/cli.dart
index 9c19c3a..cabc17e 100644
--- a/sdk/lib/cli/cli.dart
+++ b/sdk/lib/cli/cli.dart
@@ -2,7 +2,10 @@
 // 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.6
+
 /// {@category VM}
+/// {@nodoc}
 library dart.cli;
 
 import 'dart:async';
diff --git a/sdk/lib/cli/wait_for.dart b/sdk/lib/cli/wait_for.dart
index 1886ff1..57202bc 100644
--- a/sdk/lib/cli/wait_for.dart
+++ b/sdk/lib/cli/wait_for.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.
 
+// @dart = 2.6
+
 part of dart.cli;
 
 /**
diff --git a/sdk/lib/collection/collection.dart b/sdk/lib/collection/collection.dart
index b050a48..80f6d93 100644
--- a/sdk/lib/collection/collection.dart
+++ b/sdk/lib/collection/collection.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.
 
+// @dart = 2.6
+
 /// Classes and utilities that supplement the collection support in dart:core.
 ///
 /// To use this library in your code:
diff --git a/sdk/lib/collection/collections.dart b/sdk/lib/collection/collections.dart
index 9b43996..600dead 100644
--- a/sdk/lib/collection/collections.dart
+++ b/sdk/lib/collection/collections.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.
 
+// @dart = 2.6
+
 part of dart.collection;
 
 /// An unmodifiable [List] view of another List.
diff --git a/sdk/lib/collection/hash_map.dart b/sdk/lib/collection/hash_map.dart
index 525f43a..e3da5a2 100644
--- a/sdk/lib/collection/hash_map.dart
+++ b/sdk/lib/collection/hash_map.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.
 
+// @dart = 2.6
+
 part of dart.collection;
 
 /// Default function for equality comparison in customized HashMaps
diff --git a/sdk/lib/collection/hash_set.dart b/sdk/lib/collection/hash_set.dart
index 3fd00fe..97492e9 100644
--- a/sdk/lib/collection/hash_set.dart
+++ b/sdk/lib/collection/hash_set.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.
 
+// @dart = 2.6
+
 part of dart.collection;
 
 /// An unordered hash-table based [Set] implementation.
diff --git a/sdk/lib/collection/iterable.dart b/sdk/lib/collection/iterable.dart
index 14e7226..944466d 100644
--- a/sdk/lib/collection/iterable.dart
+++ b/sdk/lib/collection/iterable.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.
 
+// @dart = 2.6
+
 part of dart.collection;
 
 /// This [Iterable] mixin implements all [Iterable] members except `iterator`.
diff --git a/sdk/lib/collection/iterator.dart b/sdk/lib/collection/iterator.dart
index 671f0ee..05bcfae 100644
--- a/sdk/lib/collection/iterator.dart
+++ b/sdk/lib/collection/iterator.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.
 
+// @dart = 2.6
+
 part of dart.collection;
 
 /// The [HasNextIterator] class wraps an [Iterator] and provides methods to
diff --git a/sdk/lib/collection/linked_hash_map.dart b/sdk/lib/collection/linked_hash_map.dart
index e3a650d..548bc49 100644
--- a/sdk/lib/collection/linked_hash_map.dart
+++ b/sdk/lib/collection/linked_hash_map.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.
 
+// @dart = 2.6
+
 part of dart.collection;
 
 /// A hash-table based implementation of [Map].
diff --git a/sdk/lib/collection/linked_hash_set.dart b/sdk/lib/collection/linked_hash_set.dart
index a058b5e..4fb199b 100644
--- a/sdk/lib/collection/linked_hash_set.dart
+++ b/sdk/lib/collection/linked_hash_set.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.
 
+// @dart = 2.6
+
 part of dart.collection;
 
 /// A [LinkedHashSet] is a hash-table based [Set] implementation.
diff --git a/sdk/lib/collection/linked_list.dart b/sdk/lib/collection/linked_list.dart
index 91461cb..94f30cf 100644
--- a/sdk/lib/collection/linked_list.dart
+++ b/sdk/lib/collection/linked_list.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.
 
+// @dart = 2.6
+
 part of dart.collection;
 
 /// A specialized double-linked list of elements that extends [LinkedListEntry].
diff --git a/sdk/lib/collection/list.dart b/sdk/lib/collection/list.dart
index 56661e3..3009b37 100644
--- a/sdk/lib/collection/list.dart
+++ b/sdk/lib/collection/list.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.
 
+// @dart = 2.6
+
 part of dart.collection;
 
 /// Abstract implementation of a list.
diff --git a/sdk/lib/collection/maps.dart b/sdk/lib/collection/maps.dart
index 8159342..3204db0 100644
--- a/sdk/lib/collection/maps.dart
+++ b/sdk/lib/collection/maps.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.
 
+// @dart = 2.6
+
 part of dart.collection;
 
 /// Base class for implementing a [Map].
diff --git a/sdk/lib/collection/queue.dart b/sdk/lib/collection/queue.dart
index 8a95cf4..151edc4 100644
--- a/sdk/lib/collection/queue.dart
+++ b/sdk/lib/collection/queue.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.
 
+// @dart = 2.6
+
 part of dart.collection;
 
 /// A [Queue] is a collection that can be manipulated at both ends. One
diff --git a/sdk/lib/collection/set.dart b/sdk/lib/collection/set.dart
index c911faf..8efe4eb 100644
--- a/sdk/lib/collection/set.dart
+++ b/sdk/lib/collection/set.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.
 
+// @dart = 2.6
+
 /// Base implementations of [Set].
 part of dart.collection;
 
diff --git a/sdk/lib/collection/splay_tree.dart b/sdk/lib/collection/splay_tree.dart
index 5f71934..a877e18 100644
--- a/sdk/lib/collection/splay_tree.dart
+++ b/sdk/lib/collection/splay_tree.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.
 
+// @dart = 2.6
+
 part of dart.collection;
 
 typedef _Predicate<T> = bool Function(T value);
diff --git a/sdk/lib/convert/ascii.dart b/sdk/lib/convert/ascii.dart
index 35105ac..82f2276 100644
--- a/sdk/lib/convert/ascii.dart
+++ b/sdk/lib/convert/ascii.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.
 
+// @dart = 2.6
+
 part of dart.convert;
 
 /// An instance of the default implementation of the [AsciiCodec].
diff --git a/sdk/lib/convert/base64.dart b/sdk/lib/convert/base64.dart
index 7ebd1d5..871ebd8 100644
--- a/sdk/lib/convert/base64.dart
+++ b/sdk/lib/convert/base64.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.
 
+// @dart = 2.6
+
 part of dart.convert;
 
 /// A [base64](https://tools.ietf.org/html/rfc4648) encoder and decoder.
diff --git a/sdk/lib/convert/byte_conversion.dart b/sdk/lib/convert/byte_conversion.dart
index 3d52d78..ffde7d9 100644
--- a/sdk/lib/convert/byte_conversion.dart
+++ b/sdk/lib/convert/byte_conversion.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.
 
+// @dart = 2.6
+
 part of dart.convert;
 
 /// The [ByteConversionSink] provides an interface for converters to
diff --git a/sdk/lib/convert/chunked_conversion.dart b/sdk/lib/convert/chunked_conversion.dart
index e946f97..7253981 100644
--- a/sdk/lib/convert/chunked_conversion.dart
+++ b/sdk/lib/convert/chunked_conversion.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.
 
+// @dart = 2.6
+
 part of dart.convert;
 
 /// A [ChunkedConversionSink] is used to transmit data more efficiently between
diff --git a/sdk/lib/convert/codec.dart b/sdk/lib/convert/codec.dart
index 38e4a3c..1d8daf3 100644
--- a/sdk/lib/convert/codec.dart
+++ b/sdk/lib/convert/codec.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.
 
+// @dart = 2.6
+
 part of dart.convert;
 
 /// A [Codec] encodes and (if supported) decodes data.
diff --git a/sdk/lib/convert/convert.dart b/sdk/lib/convert/convert.dart
index 6173782..ec6ba50 100644
--- a/sdk/lib/convert/convert.dart
+++ b/sdk/lib/convert/convert.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.
 
+// @dart = 2.6
+
 ///
 /// Encoders and decoders for converting between different data representations,
 /// including JSON and UTF-8.
diff --git a/sdk/lib/convert/converter.dart b/sdk/lib/convert/converter.dart
index 2167933..047859f 100644
--- a/sdk/lib/convert/converter.dart
+++ b/sdk/lib/convert/converter.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.
 
+// @dart = 2.6
+
 part of dart.convert;
 
 /// A [Converter] converts data from one representation into another.
diff --git a/sdk/lib/convert/encoding.dart b/sdk/lib/convert/encoding.dart
index 7ce8ec3..663ae64 100644
--- a/sdk/lib/convert/encoding.dart
+++ b/sdk/lib/convert/encoding.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.
 
+// @dart = 2.6
+
 part of dart.convert;
 
 /// Open-ended Encoding enum.
diff --git a/sdk/lib/convert/html_escape.dart b/sdk/lib/convert/html_escape.dart
index a0a7119..5f10544 100644
--- a/sdk/lib/convert/html_escape.dart
+++ b/sdk/lib/convert/html_escape.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.
 
+// @dart = 2.6
+
 part of dart.convert;
 
 /// A `String` converter that converts characters to HTML entities.
diff --git a/sdk/lib/convert/json.dart b/sdk/lib/convert/json.dart
index 97216f7..a834a9e 100644
--- a/sdk/lib/convert/json.dart
+++ b/sdk/lib/convert/json.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.
 
+// @dart = 2.6
+
 part of dart.convert;
 
 /// Error thrown by JSON serialization if an object cannot be serialized.
@@ -279,7 +281,7 @@
   Stream<String> bind(Stream<Object> stream) => super.bind(stream);
 
   Converter<Object, T> fuse<T>(Converter<String, T> other) {
-    if (other is Utf8Encoder && T is List<int>) {
+    if (other is Utf8Encoder) {
       // The instance check guarantees that `T` is (a subtype of) List<int>,
       // but the static type system doesn't know that, and so we cast.
       // Cast through dynamic to keep the cast implicit for builds using
diff --git a/sdk/lib/convert/latin1.dart b/sdk/lib/convert/latin1.dart
index c22010c..06fa681 100644
--- a/sdk/lib/convert/latin1.dart
+++ b/sdk/lib/convert/latin1.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.
 
+// @dart = 2.6
+
 part of dart.convert;
 
 /// An instance of the default implementation of the [Latin1Codec].
diff --git a/sdk/lib/convert/line_splitter.dart b/sdk/lib/convert/line_splitter.dart
index 71be2c0..f51e53c 100644
--- a/sdk/lib/convert/line_splitter.dart
+++ b/sdk/lib/convert/line_splitter.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.
 
+// @dart = 2.6
+
 part of dart.convert;
 
 // Character constants.
diff --git a/sdk/lib/convert/string_conversion.dart b/sdk/lib/convert/string_conversion.dart
index 81e5621..086ed79 100644
--- a/sdk/lib/convert/string_conversion.dart
+++ b/sdk/lib/convert/string_conversion.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.
 
+// @dart = 2.6
+
 part of dart.convert;
 
 /// This class provides an interface for converters to
diff --git a/sdk/lib/convert/utf.dart b/sdk/lib/convert/utf.dart
index 39eb135..a614f39 100644
--- a/sdk/lib/convert/utf.dart
+++ b/sdk/lib/convert/utf.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.
 
+// @dart = 2.6
+
 part of dart.convert;
 
 /// The Unicode Replacement character `U+FFFD` (�).
diff --git a/sdk/lib/core/annotations.dart b/sdk/lib/core/annotations.dart
index 2d30f1c..6c39fcf 100644
--- a/sdk/lib/core/annotations.dart
+++ b/sdk/lib/core/annotations.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.
 
+// @dart = 2.6
+
 part of dart.core;
 
 /**
diff --git a/sdk/lib/core/bigint.dart b/sdk/lib/core/bigint.dart
index b495a9e..c3f261b 100644
--- a/sdk/lib/core/bigint.dart
+++ b/sdk/lib/core/bigint.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.
 
+// @dart = 2.6
+
 part of dart.core;
 
 /**
diff --git a/sdk/lib/core/bool.dart b/sdk/lib/core/bool.dart
index 5ed1065..f2ecf08 100644
--- a/sdk/lib/core/bool.dart
+++ b/sdk/lib/core/bool.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.
 
+// @dart = 2.6
+
 part of dart.core;
 
 /**
diff --git a/sdk/lib/core/comparable.dart b/sdk/lib/core/comparable.dart
index 835aa34..08bb965 100644
--- a/sdk/lib/core/comparable.dart
+++ b/sdk/lib/core/comparable.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.
 
+// @dart = 2.6
+
 part of dart.core;
 
 /**
diff --git a/sdk/lib/core/core.dart b/sdk/lib/core/core.dart
index 9ab8ed4..7d67132 100644
--- a/sdk/lib/core/core.dart
+++ b/sdk/lib/core/core.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.
 
+// @dart = 2.6
+
 /**
  *
  * Built-in types, collections,
diff --git a/sdk/lib/core/date_time.dart b/sdk/lib/core/date_time.dart
index dd242de..f52e059 100644
--- a/sdk/lib/core/date_time.dart
+++ b/sdk/lib/core/date_time.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.
 
+// @dart = 2.6
+
 part of dart.core;
 
 /**
@@ -117,7 +119,7 @@
  *
  * The DateTime class does not provide internationalization.
  * To internationalize your code, use
- * the [intl](https://pub.dartlang.org/packages/intl) package.
+ * the [intl](https://pub.dev/packages/intl) package.
  *
  */
 class DateTime implements Comparable<DateTime> {
@@ -238,7 +240,8 @@
    *   The time part is a two digit hour,
    *   then optionally a two digit minutes value,
    *   then optionally a two digit seconds value, and
-   *   then optionally a '.' or ',' followed by a one-to-six digit second fraction.
+   *   then optionally a '.' or ',' followed by at least a one digit
+   *   second fraction.
    *   The minutes and seconds may be separated from the previous parts by a
    *   ':'.
    *   Examples: "12", "12:30:24.124", "12:30:24,124", "123010.50".
@@ -261,8 +264,8 @@
    * Examples of accepted strings:
    *
    * * `"2012-02-27 13:27:00"`
-   * * `"2012-02-27 13:27:00.123456z"`
-   * * `"2012-02-27 13:27:00,123456z"`
+   * * `"2012-02-27 13:27:00.123456789z"`
+   * * `"2012-02-27 13:27:00,123456789z"`
    * * `"20120227 13:27:00"`
    * * `"20120227T132700"`
    * * `"20120227"`
@@ -283,14 +286,13 @@
         return int.parse(matched);
       }
 
-      // Parses fractional second digits of '.(\d{1,6})' into the combined
-      // microseconds.
+      // Parses fractional second digits of '.(\d+)' into the combined
+      // microseconds. We only use the first 6 digits because of DateTime
+      // precision of 999 milliseconds and 999 microseconds.
       int parseMilliAndMicroseconds(String matched) {
         if (matched == null) return 0;
         int length = matched.length;
         assert(length >= 1);
-        assert(length <= 6);
-
         int result = 0;
         for (int i = 0; i < 6; i++) {
           result *= 10;
@@ -307,7 +309,6 @@
       int hour = parseIntOrZero(match[4]);
       int minute = parseIntOrZero(match[5]);
       int second = parseIntOrZero(match[6]);
-      bool addOneMillisecond = false;
       int milliAndMicroseconds = parseMilliAndMicroseconds(match[7]);
       int millisecond =
           milliAndMicroseconds ~/ Duration.microsecondsPerMillisecond;
@@ -560,7 +561,7 @@
    * The returned string is constructed for the time zone of this instance.
    * The `toString()` method provides a simply formatted string.
    * It does not support internationalized strings.
-   * Use the [intl](https://pub.dartlang.org/packages/intl) package
+   * Use the [intl](https://pub.dev/packages/intl) package
    * at the pub shared packages repo.
    *
    * The resulting string can be parsed back using [parse].
@@ -860,7 +861,7 @@
    * time_opt ::= <empty> | (' ' | 'T') hour minutes_opt
    * minutes_opt ::= <empty> | colon_opt digit{2} seconds_opt
    * seconds_opt ::= <empty> | colon_opt digit{2} millis_opt
-   * micros_opt ::= <empty> | ('.' | ',') digit{1,6}
+   * micros_opt ::= <empty> | ('.' | ',') digit+
    * timezone_opt ::= <empty> | space_opt timezone
    * space_opt :: ' ' | <empty>
    * timezone ::= 'z' | 'Z' | sign digit{2} timezonemins_opt
@@ -868,6 +869,6 @@
    */
   static final RegExp _parseFormat = RegExp(
       r'^([+-]?\d{4,6})-?(\d\d)-?(\d\d)' // Day part.
-      r'(?:[ T](\d\d)(?::?(\d\d)(?::?(\d\d)(?:[.,](\d{1,6}))?)?)?' // Time part.
+      r'(?:[ T](\d\d)(?::?(\d\d)(?::?(\d\d)(?:[.,](\d+))?)?)?' // Time part.
       r'( ?[zZ]| ?([-+])(\d\d)(?::?(\d\d))?)?)?$'); // Timezone part.
 }
diff --git a/sdk/lib/core/double.dart b/sdk/lib/core/double.dart
index 61191ec..18f782f 100644
--- a/sdk/lib/core/double.dart
+++ b/sdk/lib/core/double.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.
 
+// @dart = 2.6
+
 part of dart.core;
 
 // TODO: Convert this abstract class into a concrete class double
diff --git a/sdk/lib/core/duration.dart b/sdk/lib/core/duration.dart
index 914f05a..eeb0337 100644
--- a/sdk/lib/core/duration.dart
+++ b/sdk/lib/core/duration.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.
 
+// @dart = 2.6
+
 part of dart.core;
 
 /**
diff --git a/sdk/lib/core/errors.dart b/sdk/lib/core/errors.dart
index 298083d..a1b410c 100644
--- a/sdk/lib/core/errors.dart
+++ b/sdk/lib/core/errors.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.
 
+// @dart = 2.6
+
 part of dart.core;
 
 /**
diff --git a/sdk/lib/core/exceptions.dart b/sdk/lib/core/exceptions.dart
index 27c11fa..ef66d15 100644
--- a/sdk/lib/core/exceptions.dart
+++ b/sdk/lib/core/exceptions.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.
 
+// @dart = 2.6
+
 part of dart.core;
 
 // Exceptions are thrown either by the VM or from Dart code.
diff --git a/sdk/lib/core/expando.dart b/sdk/lib/core/expando.dart
index 92cf90c..2ccb07d 100644
--- a/sdk/lib/core/expando.dart
+++ b/sdk/lib/core/expando.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.
 
+// @dart = 2.6
+
 part of dart.core;
 
 /**
diff --git a/sdk/lib/core/function.dart b/sdk/lib/core/function.dart
index 7ff40e9..4e026f8 100644
--- a/sdk/lib/core/function.dart
+++ b/sdk/lib/core/function.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.
 
+// @dart = 2.6
+
 part of dart.core;
 
 /**
diff --git a/sdk/lib/core/identical.dart b/sdk/lib/core/identical.dart
index 68da9f3..ec24609 100644
--- a/sdk/lib/core/identical.dart
+++ b/sdk/lib/core/identical.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.
 
+// @dart = 2.6
+
 part of dart.core;
 
 /**
diff --git a/sdk/lib/core/int.dart b/sdk/lib/core/int.dart
index bc493fb..a6253c0 100644
--- a/sdk/lib/core/int.dart
+++ b/sdk/lib/core/int.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.
 
+// @dart = 2.6
+
 part of dart.core;
 
 /**
diff --git a/sdk/lib/core/invocation.dart b/sdk/lib/core/invocation.dart
index e9ea57e..8b7df36 100644
--- a/sdk/lib/core/invocation.dart
+++ b/sdk/lib/core/invocation.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.
 
+// @dart = 2.6
+
 part of dart.core;
 
 /**
diff --git a/sdk/lib/core/iterable.dart b/sdk/lib/core/iterable.dart
index 0744937..c6aba41 100644
--- a/sdk/lib/core/iterable.dart
+++ b/sdk/lib/core/iterable.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.
 
+// @dart = 2.6
+
 part of dart.core;
 
 /**
diff --git a/sdk/lib/core/iterator.dart b/sdk/lib/core/iterator.dart
index cd0ad32..73a7d3f 100644
--- a/sdk/lib/core/iterator.dart
+++ b/sdk/lib/core/iterator.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.
 
+// @dart = 2.6
+
 part of dart.core;
 
 /**
diff --git a/sdk/lib/core/list.dart b/sdk/lib/core/list.dart
index 27e1653..9500c56 100644
--- a/sdk/lib/core/list.dart
+++ b/sdk/lib/core/list.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.
 
+// @dart = 2.6
+
 part of dart.core;
 
 /**
diff --git a/sdk/lib/core/map.dart b/sdk/lib/core/map.dart
index 21d3945..8f76dfd 100644
--- a/sdk/lib/core/map.dart
+++ b/sdk/lib/core/map.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.
 
+// @dart = 2.6
+
 part of dart.core;
 
 /**
diff --git a/sdk/lib/core/null.dart b/sdk/lib/core/null.dart
index af7d86d..40140e8 100644
--- a/sdk/lib/core/null.dart
+++ b/sdk/lib/core/null.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.
 
+// @dart = 2.6
+
 part of dart.core;
 
 /**
diff --git a/sdk/lib/core/num.dart b/sdk/lib/core/num.dart
index e04112c..dedc8d4 100644
--- a/sdk/lib/core/num.dart
+++ b/sdk/lib/core/num.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.
 
+// @dart = 2.6
+
 part of dart.core;
 
 /**
diff --git a/sdk/lib/core/object.dart b/sdk/lib/core/object.dart
index 505efdf..08bf687 100644
--- a/sdk/lib/core/object.dart
+++ b/sdk/lib/core/object.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.
 
+// @dart = 2.6
+
 part of dart.core;
 
 /**
diff --git a/sdk/lib/core/pattern.dart b/sdk/lib/core/pattern.dart
index 6749340..8eb0371 100644
--- a/sdk/lib/core/pattern.dart
+++ b/sdk/lib/core/pattern.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.
 
+// @dart = 2.6
+
 part of dart.core;
 
 /**
diff --git a/sdk/lib/core/print.dart b/sdk/lib/core/print.dart
index 42c7d1c..cc2f0ac 100644
--- a/sdk/lib/core/print.dart
+++ b/sdk/lib/core/print.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.
 
+// @dart = 2.6
+
 part of dart.core;
 
 /// Prints a string representation of the object to the console.
diff --git a/sdk/lib/core/regexp.dart b/sdk/lib/core/regexp.dart
index 9bd68ba..095e733 100644
--- a/sdk/lib/core/regexp.dart
+++ b/sdk/lib/core/regexp.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.
 
+// @dart = 2.6
+
 part of dart.core;
 
 /**
diff --git a/sdk/lib/core/set.dart b/sdk/lib/core/set.dart
index e57d974..9e1a6de 100644
--- a/sdk/lib/core/set.dart
+++ b/sdk/lib/core/set.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.
 
+// @dart = 2.6
+
 part of dart.core;
 
 /**
diff --git a/sdk/lib/core/sink.dart b/sdk/lib/core/sink.dart
index c79214b..80f9468d 100644
--- a/sdk/lib/core/sink.dart
+++ b/sdk/lib/core/sink.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.
 
+// @dart = 2.6
+
 part of dart.core;
 
 /**
diff --git a/sdk/lib/core/stacktrace.dart b/sdk/lib/core/stacktrace.dart
index 2eb1493..ed5f85d 100644
--- a/sdk/lib/core/stacktrace.dart
+++ b/sdk/lib/core/stacktrace.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.
 
+// @dart = 2.6
+
 part of dart.core;
 
 /**
diff --git a/sdk/lib/core/stopwatch.dart b/sdk/lib/core/stopwatch.dart
index 45d71ca..20316eb 100644
--- a/sdk/lib/core/stopwatch.dart
+++ b/sdk/lib/core/stopwatch.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.
 
+// @dart = 2.6
+
 part of dart.core;
 
 /**
diff --git a/sdk/lib/core/string.dart b/sdk/lib/core/string.dart
index c611bd5..5a8deb8 100644
--- a/sdk/lib/core/string.dart
+++ b/sdk/lib/core/string.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.
 
+// @dart = 2.6
+
 part of dart.core;
 
 /**
diff --git a/sdk/lib/core/string_buffer.dart b/sdk/lib/core/string_buffer.dart
index 8fe17f5..d2a25ab 100644
--- a/sdk/lib/core/string_buffer.dart
+++ b/sdk/lib/core/string_buffer.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.
 
+// @dart = 2.6
+
 part of dart.core;
 
 /**
diff --git a/sdk/lib/core/string_sink.dart b/sdk/lib/core/string_sink.dart
index e7d950c..b0511ad 100644
--- a/sdk/lib/core/string_sink.dart
+++ b/sdk/lib/core/string_sink.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.
 
+// @dart = 2.6
+
 part of dart.core;
 
 abstract class StringSink {
diff --git a/sdk/lib/core/symbol.dart b/sdk/lib/core/symbol.dart
index a46ec97..748d465 100644
--- a/sdk/lib/core/symbol.dart
+++ b/sdk/lib/core/symbol.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.
 
+// @dart = 2.6
+
 part of dart.core;
 
 /// Opaque name used by mirrors, invocations and [Function.apply].
@@ -60,7 +62,7 @@
    * assert(new Symbol("[]=") == #[]=]);
    * assert(new Symbol("foo.bar") == #foo.bar);
    * assert(identical(const Symbol("foo"), #foo));
-   * assert(identical(const Symbol("[]="), #[]=]));
+   * assert(identical(const Symbol("[]="), #[]=));
    * assert(identical(const Symbol("foo.bar"), #foo.bar));
    * ```
    *
diff --git a/sdk/lib/core/type.dart b/sdk/lib/core/type.dart
index d2e107b..48ac0e9 100644
--- a/sdk/lib/core/type.dart
+++ b/sdk/lib/core/type.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.
 
+// @dart = 2.6
+
 part of dart.core;
 
 /**
diff --git a/sdk/lib/core/uri.dart b/sdk/lib/core/uri.dart
index 2ca94a1..a85eb67 100644
--- a/sdk/lib/core/uri.dart
+++ b/sdk/lib/core/uri.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.
 
+// @dart = 2.6
+
 part of dart.core;
 
 // Frequently used character codes.
diff --git a/sdk/lib/developer/developer.dart b/sdk/lib/developer/developer.dart
index c446fdf..4490499 100644
--- a/sdk/lib/developer/developer.dart
+++ b/sdk/lib/developer/developer.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.
 
+// @dart = 2.6
+
 /// Interact with developer tools such as the debugger and inspector.
 ///
 /// This library is platform dependent and has separate implementations for
diff --git a/sdk/lib/developer/extension.dart b/sdk/lib/developer/extension.dart
index 3cc4ede..5d0da2a 100644
--- a/sdk/lib/developer/extension.dart
+++ b/sdk/lib/developer/extension.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.
 
+// @dart = 2.6
+
 part of dart.developer;
 
 /// A response to a service protocol extension RPC.
diff --git a/sdk/lib/developer/profiler.dart b/sdk/lib/developer/profiler.dart
index 05a9211..385d68a 100644
--- a/sdk/lib/developer/profiler.dart
+++ b/sdk/lib/developer/profiler.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.
 
+// @dart = 2.6
+
 part of dart.developer;
 
 /// A UserTag can be used to group samples in the Observatory profiler.
diff --git a/sdk/lib/developer/service.dart b/sdk/lib/developer/service.dart
index a4d92b9..81d0540 100644
--- a/sdk/lib/developer/service.dart
+++ b/sdk/lib/developer/service.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.
 
+// @dart = 2.6
+
 part of dart.developer;
 
 /// Service protocol is the protocol that a client like the Observatory
diff --git a/sdk/lib/developer/timeline.dart b/sdk/lib/developer/timeline.dart
index bfdb07b..14775b5 100644
--- a/sdk/lib/developer/timeline.dart
+++ b/sdk/lib/developer/timeline.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.
 
+// @dart = 2.6
+
 part of dart.developer;
 
 const bool _hasTimeline =
diff --git a/sdk/lib/ffi/annotations.dart b/sdk/lib/ffi/annotations.dart
index f68e525..1466c35 100644
--- a/sdk/lib/ffi/annotations.dart
+++ b/sdk/lib/ffi/annotations.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.
 
+// @dart = 2.6
+
 part of dart.ffi;
 
 class DartRepresentationOf {
diff --git a/sdk/lib/ffi/dynamic_library.dart b/sdk/lib/ffi/dynamic_library.dart
index ec68eeb..4640857 100644
--- a/sdk/lib/ffi/dynamic_library.dart
+++ b/sdk/lib/ffi/dynamic_library.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.
 
+// @dart = 2.6
+
 part of dart.ffi;
 
 /// Represents a dynamically loaded C library.
diff --git a/sdk/lib/ffi/ffi.dart b/sdk/lib/ffi/ffi.dart
index f072a7c..d00b4e7 100644
--- a/sdk/lib/ffi/ffi.dart
+++ b/sdk/lib/ffi/ffi.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
 
+// @dart = 2.6
+
 /**
  * Foreign Function Interface for interoperability with the C programming language.
  *
diff --git a/sdk/lib/ffi/native_type.dart b/sdk/lib/ffi/native_type.dart
index aa30e63..c372b82 100644
--- a/sdk/lib/ffi/native_type.dart
+++ b/sdk/lib/ffi/native_type.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.
 
+// @dart = 2.6
+
 part of dart.ffi;
 
 /// [NativeType]'s subtypes represent a native type in C.
diff --git a/sdk/lib/ffi/struct.dart b/sdk/lib/ffi/struct.dart
index c6605d8..5d807b0 100644
--- a/sdk/lib/ffi/struct.dart
+++ b/sdk/lib/ffi/struct.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.
 
+// @dart = 2.6
+
 part of dart.ffi;
 
 /// This class is extended to define structs.
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index 090115d..bdf8bac 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -1,3 +1,5 @@
+// @dart = 2.6
+
 /**
  * HTML elements and other resources for web-based applications that need to
  * interact with the browser and the DOM (Document Object Model).
diff --git a/sdk/lib/html/dartium/nativewrappers.dart b/sdk/lib/html/dartium/nativewrappers.dart
index b6d2dc4..db80798 100644
--- a/sdk/lib/html/dartium/nativewrappers.dart
+++ b/sdk/lib/html/dartium/nativewrappers.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.
 
+// @dart = 2.6
+
 library nativewrappers;
 
 class NativeFieldWrapperClass1 {}
diff --git a/sdk/lib/html/html_common/conversions.dart b/sdk/lib/html/html_common/conversions.dart
index a7775ed..cbe2cd6 100644
--- a/sdk/lib/html/html_common/conversions.dart
+++ b/sdk/lib/html/html_common/conversions.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.
 
+// @dart = 2.6
+
 // Conversions for IDBKey.
 //
 // Per http://www.w3.org/TR/IndexedDB/#key-construct
diff --git a/sdk/lib/html/html_common/conversions_dart2js.dart b/sdk/lib/html/html_common/conversions_dart2js.dart
index 21ab9ae..028707f 100644
--- a/sdk/lib/html/html_common/conversions_dart2js.dart
+++ b/sdk/lib/html/html_common/conversions_dart2js.dart
@@ -1,3 +1,5 @@
+// @dart = 2.6
+
 part of html_common;
 
 /// Converts a JavaScript object with properties into a Dart Map.
diff --git a/sdk/lib/html/html_common/css_class_set.dart b/sdk/lib/html/html_common/css_class_set.dart
index 2286057..486fa31 100644
--- a/sdk/lib/html/html_common/css_class_set.dart
+++ b/sdk/lib/html/html_common/css_class_set.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.
 
+// @dart = 2.6
+
 part of html_common;
 
 abstract class CssClassSetImpl extends SetBase<String> implements CssClassSet {
diff --git a/sdk/lib/html/html_common/device.dart b/sdk/lib/html/html_common/device.dart
index 123a5db..d4d9ed5 100644
--- a/sdk/lib/html/html_common/device.dart
+++ b/sdk/lib/html/html_common/device.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.
 
+// @dart = 2.6
+
 part of html_common;
 
 /**
diff --git a/sdk/lib/html/html_common/filtered_element_list.dart b/sdk/lib/html/html_common/filtered_element_list.dart
index fba6ad7..35e01cb 100644
--- a/sdk/lib/html/html_common/filtered_element_list.dart
+++ b/sdk/lib/html/html_common/filtered_element_list.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.
 
+// @dart = 2.6
+
 part of html_common;
 
 /**
diff --git a/sdk/lib/html/html_common/html_common.dart b/sdk/lib/html/html_common/html_common.dart
index e689c9a..6d6b08b 100644
--- a/sdk/lib/html/html_common/html_common.dart
+++ b/sdk/lib/html/html_common/html_common.dart
@@ -1,6 +1,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.
 
+// @dart = 2.6
+
 library html_common;
 
 import 'dart:async';
diff --git a/sdk/lib/html/html_common/html_common_dart2js.dart b/sdk/lib/html/html_common/html_common_dart2js.dart
index 3df2ccf..da4e210 100644
--- a/sdk/lib/html/html_common/html_common_dart2js.dart
+++ b/sdk/lib/html/html_common/html_common_dart2js.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.
 
+// @dart = 2.6
+
 library html_common;
 
 import 'dart:async';
diff --git a/sdk/lib/html/html_common/lists.dart b/sdk/lib/html/html_common/lists.dart
index c7abc41..83d65b7 100644
--- a/sdk/lib/html/html_common/lists.dart
+++ b/sdk/lib/html/html_common/lists.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.
 
+// @dart = 2.6
+
 part of html_common;
 
 class Lists {
diff --git a/sdk/lib/html/html_common/metadata.dart b/sdk/lib/html/html_common/metadata.dart
index b5542dc..991d99f 100644
--- a/sdk/lib/html/html_common/metadata.dart
+++ b/sdk/lib/html/html_common/metadata.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.
 
+// @dart = 2.6
+
 library metadata;
 
 /**
diff --git a/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart b/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
index b664b7d..60bab46 100644
--- a/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
+++ b/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
@@ -1,3 +1,5 @@
+// @dart = 2.6
+
 /**
  * A client-side key-value store with support for indexes.
  *
diff --git a/sdk/lib/internal/async_cast.dart b/sdk/lib/internal/async_cast.dart
index e041ff3..aa3e375 100644
--- a/sdk/lib/internal/async_cast.dart
+++ b/sdk/lib/internal/async_cast.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.
 
+// @dart = 2.6
+
 part of dart._internal;
 
 // Casting wrappers for asynchronous classes.
diff --git a/sdk/lib/internal/cast.dart b/sdk/lib/internal/cast.dart
index b3620f5..f019c95 100644
--- a/sdk/lib/internal/cast.dart
+++ b/sdk/lib/internal/cast.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.
 
+// @dart = 2.6
+
 part of dart._internal;
 
 // Casting wrappers for collection classes.
diff --git a/sdk/lib/internal/internal.dart b/sdk/lib/internal/internal.dart
index 11ee996..bee60d6 100644
--- a/sdk/lib/internal/internal.dart
+++ b/sdk/lib/internal/internal.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.
 
+// @dart = 2.6
+
 library dart._internal;
 
 import 'dart:collection';
diff --git a/sdk/lib/internal/iterable.dart b/sdk/lib/internal/iterable.dart
index b3e8e4e..8f28b5f 100644
--- a/sdk/lib/internal/iterable.dart
+++ b/sdk/lib/internal/iterable.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.
 
+// @dart = 2.6
+
 part of dart._internal;
 
 /**
diff --git a/sdk/lib/internal/linked_list.dart b/sdk/lib/internal/linked_list.dart
index 31a6c01..1ad5889 100644
--- a/sdk/lib/internal/linked_list.dart
+++ b/sdk/lib/internal/linked_list.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.
 
+// @dart = 2.6
+
 part of dart._internal;
 
 /// A rudimentary linked list.
diff --git a/sdk/lib/internal/list.dart b/sdk/lib/internal/list.dart
index e0ddd70..3bf14a9 100644
--- a/sdk/lib/internal/list.dart
+++ b/sdk/lib/internal/list.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.
 
+// @dart = 2.6
+
 part of dart._internal;
 
 /**
diff --git a/sdk/lib/internal/patch.dart b/sdk/lib/internal/patch.dart
index 3fc9733..b6aeea8 100644
--- a/sdk/lib/internal/patch.dart
+++ b/sdk/lib/internal/patch.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.
 
+// @dart = 2.6
+
 part of "dart:_internal";
 
 class _Patch {
diff --git a/sdk/lib/internal/print.dart b/sdk/lib/internal/print.dart
index 417003b..466a414 100644
--- a/sdk/lib/internal/print.dart
+++ b/sdk/lib/internal/print.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.
 
+// @dart = 2.6
+
 part of dart._internal;
 
 /**
diff --git a/sdk/lib/internal/sort.dart b/sdk/lib/internal/sort.dart
index d6cca2e..a4489f3 100644
--- a/sdk/lib/internal/sort.dart
+++ b/sdk/lib/internal/sort.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.
 
+// @dart = 2.6
+
 part of dart._internal;
 
 /**
diff --git a/sdk/lib/internal/symbol.dart b/sdk/lib/internal/symbol.dart
index 54d235c..7fba4af 100644
--- a/sdk/lib/internal/symbol.dart
+++ b/sdk/lib/internal/symbol.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.
 
+// @dart = 2.6
+
 part of dart._internal;
 
 /**
diff --git a/sdk/lib/io/bytes_builder.dart b/sdk/lib/io/bytes_builder.dart
index 9113d44..6efe42c 100644
--- a/sdk/lib/io/bytes_builder.dart
+++ b/sdk/lib/io/bytes_builder.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.
 
+// @dart = 2.6
+
 part of dart.io;
 
 /**
diff --git a/sdk/lib/io/common.dart b/sdk/lib/io/common.dart
index 77b7587..d047752 100644
--- a/sdk/lib/io/common.dart
+++ b/sdk/lib/io/common.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.
 
+// @dart = 2.6
+
 part of dart.io;
 
 // Constants used when working with native ports.
diff --git a/sdk/lib/io/data_transformer.dart b/sdk/lib/io/data_transformer.dart
index 33c615d..0046416 100644
--- a/sdk/lib/io/data_transformer.dart
+++ b/sdk/lib/io/data_transformer.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.
 
+// @dart = 2.6
+
 part of dart.io;
 
 /**
diff --git a/sdk/lib/io/directory.dart b/sdk/lib/io/directory.dart
index 2f141cb..44b8399 100644
--- a/sdk/lib/io/directory.dart
+++ b/sdk/lib/io/directory.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.
 
+// @dart = 2.6
+
 part of dart.io;
 
 /**
diff --git a/sdk/lib/io/directory_impl.dart b/sdk/lib/io/directory_impl.dart
index faed892..bcd63b2 100644
--- a/sdk/lib/io/directory_impl.dart
+++ b/sdk/lib/io/directory_impl.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.
 
+// @dart = 2.6
+
 part of dart.io;
 
 class _Directory extends FileSystemEntity implements Directory {
diff --git a/sdk/lib/io/embedder_config.dart b/sdk/lib/io/embedder_config.dart
index cbc94f7..179c06a 100644
--- a/sdk/lib/io/embedder_config.dart
+++ b/sdk/lib/io/embedder_config.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.
 
+// @dart = 2.6
+
 part of dart.io;
 
 /// Embedder-specific, fine-grained dart:io configuration.
diff --git a/sdk/lib/io/eventhandler.dart b/sdk/lib/io/eventhandler.dart
index 36f54e6..6a3467f 100644
--- a/sdk/lib/io/eventhandler.dart
+++ b/sdk/lib/io/eventhandler.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.
 
+// @dart = 2.6
+
 part of dart.io;
 
 class _EventHandler {
diff --git a/sdk/lib/io/file.dart b/sdk/lib/io/file.dart
index cae672b..b04315f 100644
--- a/sdk/lib/io/file.dart
+++ b/sdk/lib/io/file.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.
 
+// @dart = 2.6
+
 part of dart.io;
 
 /**
diff --git a/sdk/lib/io/file_impl.dart b/sdk/lib/io/file_impl.dart
index 410182c..f0a1275 100644
--- a/sdk/lib/io/file_impl.dart
+++ b/sdk/lib/io/file_impl.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.
 
+// @dart = 2.6
+
 part of dart.io;
 
 // Read the file in blocks of size 64k.
diff --git a/sdk/lib/io/file_system_entity.dart b/sdk/lib/io/file_system_entity.dart
index dfff281..6427594 100644
--- a/sdk/lib/io/file_system_entity.dart
+++ b/sdk/lib/io/file_system_entity.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.
 
+// @dart = 2.6
+
 part of dart.io;
 
 /**
diff --git a/sdk/lib/io/io.dart b/sdk/lib/io/io.dart
index d30e97e..7fc5bd3 100644
--- a/sdk/lib/io/io.dart
+++ b/sdk/lib/io/io.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.
 
+// @dart = 2.6
+
 /**
  * File, socket, HTTP, and other I/O support for non-web applications.
  *
@@ -65,7 +67,7 @@
  * The [HttpServer] class provides the basic functionality for
  * implementing an HTTP server.
  * For some higher-level building-blocks, we recommend that you try
- * the [shelf](https://pub.dartlang.org/packages/shelf)
+ * the [shelf](https://pub.dev/packages/shelf)
  * pub package, which contains
  * a set of high-level classes that, together with the [HttpServer] class
  * in this library, make it easier to implement HTTP servers.
diff --git a/sdk/lib/io/io_resource_info.dart b/sdk/lib/io/io_resource_info.dart
index 3e29221..a81da11 100644
--- a/sdk/lib/io/io_resource_info.dart
+++ b/sdk/lib/io/io_resource_info.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.
 
+// @dart = 2.6
+
 part of dart.io;
 
 abstract class _IOResourceInfo {
diff --git a/sdk/lib/io/io_service.dart b/sdk/lib/io/io_service.dart
index 7af382c..92d3e84 100644
--- a/sdk/lib/io/io_service.dart
+++ b/sdk/lib/io/io_service.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.
 
+// @dart = 2.6
+
 part of dart.io;
 
 class _IOService {
diff --git a/sdk/lib/io/io_sink.dart b/sdk/lib/io/io_sink.dart
index 5481265..96a68a9 100644
--- a/sdk/lib/io/io_sink.dart
+++ b/sdk/lib/io/io_sink.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.
 
+// @dart = 2.6
+
 part of dart.io;
 
 /**
diff --git a/sdk/lib/io/link.dart b/sdk/lib/io/link.dart
index 79f8656..b210507 100644
--- a/sdk/lib/io/link.dart
+++ b/sdk/lib/io/link.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.
 
+// @dart = 2.6
+
 part of dart.io;
 
 /**
diff --git a/sdk/lib/io/namespace_impl.dart b/sdk/lib/io/namespace_impl.dart
index 88987b6..763f4aa 100644
--- a/sdk/lib/io/namespace_impl.dart
+++ b/sdk/lib/io/namespace_impl.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.
 
+// @dart = 2.6
+
 part of dart.io;
 
 // Each Isolate may run in a different "namespace", which provides the scope in
diff --git a/sdk/lib/io/network_profiling.dart b/sdk/lib/io/network_profiling.dart
index e562b0d..f303c9d 100644
--- a/sdk/lib/io/network_profiling.dart
+++ b/sdk/lib/io/network_profiling.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.
 
+// @dart = 2.6
+
 part of dart.io;
 
 @pragma('vm:entry-point')
diff --git a/sdk/lib/io/overrides.dart b/sdk/lib/io/overrides.dart
index aa1c8a4..0692f9d 100644
--- a/sdk/lib/io/overrides.dart
+++ b/sdk/lib/io/overrides.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.
 
+// @dart = 2.6
+
 part of dart.io;
 
 final _ioOverridesToken = new Object();
diff --git a/sdk/lib/io/platform.dart b/sdk/lib/io/platform.dart
index f7c9053..7fd53c8 100644
--- a/sdk/lib/io/platform.dart
+++ b/sdk/lib/io/platform.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.
 
+// @dart = 2.6
+
 part of dart.io;
 
 /**
diff --git a/sdk/lib/io/platform_impl.dart b/sdk/lib/io/platform_impl.dart
index a350119..8705697 100644
--- a/sdk/lib/io/platform_impl.dart
+++ b/sdk/lib/io/platform_impl.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.
 
+// @dart = 2.6
+
 part of dart.io;
 
 class _Platform {
diff --git a/sdk/lib/io/process.dart b/sdk/lib/io/process.dart
index 4cf78b9..93a6772 100644
--- a/sdk/lib/io/process.dart
+++ b/sdk/lib/io/process.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.
 
+// @dart = 2.6
+
 part of dart.io;
 
 // TODO(ager): The only reason for this class is that we
diff --git a/sdk/lib/io/secure_server_socket.dart b/sdk/lib/io/secure_server_socket.dart
index b4ca32e..f21b4a27 100644
--- a/sdk/lib/io/secure_server_socket.dart
+++ b/sdk/lib/io/secure_server_socket.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.
 
+// @dart = 2.6
+
 part of dart.io;
 
 /**
diff --git a/sdk/lib/io/secure_socket.dart b/sdk/lib/io/secure_socket.dart
index a4751ef..efec0b3 100644
--- a/sdk/lib/io/secure_socket.dart
+++ b/sdk/lib/io/secure_socket.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.
 
+// @dart = 2.6
+
 part of dart.io;
 
 /**
diff --git a/sdk/lib/io/security_context.dart b/sdk/lib/io/security_context.dart
index 96da93b..e98fd78 100644
--- a/sdk/lib/io/security_context.dart
+++ b/sdk/lib/io/security_context.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.
 
+// @dart = 2.6
+
 part of dart.io;
 
 /**
diff --git a/sdk/lib/io/service_object.dart b/sdk/lib/io/service_object.dart
index e6b1851..6c0f882 100644
--- a/sdk/lib/io/service_object.dart
+++ b/sdk/lib/io/service_object.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.
 
+// @dart = 2.6
+
 part of dart.io;
 
 int _nextServiceId = 1;
diff --git a/sdk/lib/io/socket.dart b/sdk/lib/io/socket.dart
index 5d9c239..d03d5b2 100644
--- a/sdk/lib/io/socket.dart
+++ b/sdk/lib/io/socket.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.
 
+// @dart = 2.6
+
 part of dart.io;
 
 /**
diff --git a/sdk/lib/io/stdio.dart b/sdk/lib/io/stdio.dart
index cc8c7df..8faf791 100644
--- a/sdk/lib/io/stdio.dart
+++ b/sdk/lib/io/stdio.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.
 
+// @dart = 2.6
+
 part of dart.io;
 
 const int _stdioHandleTypeTerminal = 0;
diff --git a/sdk/lib/io/string_transformer.dart b/sdk/lib/io/string_transformer.dart
index f31c41e..c399932 100644
--- a/sdk/lib/io/string_transformer.dart
+++ b/sdk/lib/io/string_transformer.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.
 
+// @dart = 2.6
+
 part of dart.io;
 
 /// The current system encoding.
diff --git a/sdk/lib/io/sync_socket.dart b/sdk/lib/io/sync_socket.dart
index fee259d..386dc2e 100644
--- a/sdk/lib/io/sync_socket.dart
+++ b/sdk/lib/io/sync_socket.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.
 
+// @dart = 2.6
+
 part of dart.io;
 
 /**
diff --git a/sdk/lib/isolate/capability.dart b/sdk/lib/isolate/capability.dart
index a51eec2..4619192 100644
--- a/sdk/lib/isolate/capability.dart
+++ b/sdk/lib/isolate/capability.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.
 
+// @dart = 2.6
+
 part of dart.isolate;
 
 /**
diff --git a/sdk/lib/isolate/isolate.dart b/sdk/lib/isolate/isolate.dart
index 8773cda..22c40b6 100644
--- a/sdk/lib/isolate/isolate.dart
+++ b/sdk/lib/isolate/isolate.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.
 
+// @dart = 2.6
+
 /**
  * Concurrent programming using _isolates_:
  * independent workers that are similar to threads
diff --git a/sdk/lib/js/_js.dart b/sdk/lib/js/_js.dart
index aef7ef9..cddb791 100644
--- a/sdk/lib/js/_js.dart
+++ b/sdk/lib/js/_js.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.
 
+// @dart = 2.6
+
 /// Helper library used by `dart:js`.
 ///
 /// This library hides any logic that is specific to the web, and allows us to
diff --git a/sdk/lib/js/_js_client.dart b/sdk/lib/js/_js_client.dart
index de25540..b3070d6 100644
--- a/sdk/lib/js/_js_client.dart
+++ b/sdk/lib/js/_js_client.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.
 
+// @dart = 2.6
+
 import 'dart:html' show Blob, Event, ImageData, Node, Window, WorkerGlobalScope;
 import 'dart:indexed_db' show KeyRange;
 import 'dart:_js_helper' show patch;
diff --git a/sdk/lib/js/_js_server.dart b/sdk/lib/js/_js_server.dart
index b941d77..936c8bf 100644
--- a/sdk/lib/js/_js_server.dart
+++ b/sdk/lib/js/_js_server.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.
 
+// @dart = 2.6
+
 import 'dart:_js_helper' show patch;
 
 @patch
diff --git a/sdk/lib/js/dart2js/js_dart2js.dart b/sdk/lib/js/dart2js/js_dart2js.dart
index 9c37ea8..317ee7f 100644
--- a/sdk/lib/js/dart2js/js_dart2js.dart
+++ b/sdk/lib/js/dart2js/js_dart2js.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.
 
+// @dart = 2.6
+
 /// Low-level support for interoperating with JavaScript.
 ///
 /// You should usually use `package:js` instead of this library. For more
diff --git a/sdk/lib/js_util/dart2js/js_util_dart2js.dart b/sdk/lib/js_util/dart2js/js_util_dart2js.dart
index 2e731fb..3ed2098 100644
--- a/sdk/lib/js_util/dart2js/js_util_dart2js.dart
+++ b/sdk/lib/js_util/dart2js/js_util_dart2js.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.
 
+// @dart = 2.6
+
 /// Utility methods to efficiently manipulate typed JSInterop objects in cases
 /// where the name to call is not known at runtime. You should only use these
 /// methods when the same effect cannot be achieved with @JS annotations.
diff --git a/sdk/lib/math/jenkins_smi_hash.dart b/sdk/lib/math/jenkins_smi_hash.dart
index d756b37..7bab10b 100644
--- a/sdk/lib/math/jenkins_smi_hash.dart
+++ b/sdk/lib/math/jenkins_smi_hash.dart
@@ -1,6 +1,8 @@
 // Copyright (c) 2013, 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.6
+
 part of dart.math;
 
 /// This is the [Jenkins hash function][1] but using masking to keep
diff --git a/sdk/lib/math/math.dart b/sdk/lib/math/math.dart
index 548fb59..d73b21d 100644
--- a/sdk/lib/math/math.dart
+++ b/sdk/lib/math/math.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.
 
+// @dart = 2.6
+
 /// Mathematical constants and functions, plus a random number generator.
 ///
 /// To use this library in your code:
diff --git a/sdk/lib/math/point.dart b/sdk/lib/math/point.dart
index 1015e7b..4bebc0ff 100644
--- a/sdk/lib/math/point.dart
+++ b/sdk/lib/math/point.dart
@@ -1,6 +1,8 @@
 // Copyright (c) 2013, 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.6
+
 part of dart.math;
 
 /// A utility class for representing two-dimensional positions.
diff --git a/sdk/lib/math/random.dart b/sdk/lib/math/random.dart
index e2e9d91..65c96be 100644
--- a/sdk/lib/math/random.dart
+++ b/sdk/lib/math/random.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.
 
+// @dart = 2.6
+
 part of dart.math;
 
 /// A generator of random bool, int, or double values.
diff --git a/sdk/lib/math/rectangle.dart b/sdk/lib/math/rectangle.dart
index 6e72036..51d90ef 100644
--- a/sdk/lib/math/rectangle.dart
+++ b/sdk/lib/math/rectangle.dart
@@ -1,6 +1,8 @@
 // Copyright (c) 2013, 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.6
+
 part of dart.math;
 
 /// A base class for representing two-dimensional axis-aligned rectangles.
diff --git a/sdk/lib/mirrors/mirrors.dart b/sdk/lib/mirrors/mirrors.dart
index 5e586a0..f15e3d3 100644
--- a/sdk/lib/mirrors/mirrors.dart
+++ b/sdk/lib/mirrors/mirrors.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.
 
+// @dart = 2.6
+
 // For the purposes of the mirrors library, we adopt a naming
 // convention with respect to getters and setters.  Specifically, for
 // some variable or field...
diff --git a/sdk/lib/svg/dart2js/svg_dart2js.dart b/sdk/lib/svg/dart2js/svg_dart2js.dart
index 7966fd7..ca8fbb2 100644
--- a/sdk/lib/svg/dart2js/svg_dart2js.dart
+++ b/sdk/lib/svg/dart2js/svg_dart2js.dart
@@ -1,3 +1,5 @@
+// @dart = 2.6
+
 /**
  * Scalable Vector Graphics:
  * Two-dimensional vector graphics with support for events and animation.
diff --git a/sdk/lib/typed_data/typed_data.dart b/sdk/lib/typed_data/typed_data.dart
index 89c9496..d5f091b 100644
--- a/sdk/lib/typed_data/typed_data.dart
+++ b/sdk/lib/typed_data/typed_data.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.
 
+// @dart = 2.6
+
 /// Lists that efficiently handle fixed sized data
 /// (for example, unsigned 8 byte integers) and SIMD numeric types.
 ///
diff --git a/sdk/lib/typed_data/unmodifiable_typed_data.dart b/sdk/lib/typed_data/unmodifiable_typed_data.dart
index 3549041..2b0fe5e 100644
--- a/sdk/lib/typed_data/unmodifiable_typed_data.dart
+++ b/sdk/lib/typed_data/unmodifiable_typed_data.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.
 
+// @dart = 2.6
+
 part of dart.typed_data;
 
 /**
diff --git a/sdk/lib/vmservice/asset.dart b/sdk/lib/vmservice/asset.dart
index d5772e2..512a0c9 100644
--- a/sdk/lib/vmservice/asset.dart
+++ b/sdk/lib/vmservice/asset.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.
 
+// @dart = 2.6
+
 part of dart._vmservice;
 
 class Asset {
diff --git a/sdk/lib/vmservice/client.dart b/sdk/lib/vmservice/client.dart
index efe33c0..68cdaad 100644
--- a/sdk/lib/vmservice/client.dart
+++ b/sdk/lib/vmservice/client.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.
 
+// @dart = 2.6
+
 part of dart._vmservice;
 
 typedef void ClientServiceHandle(Message response);
diff --git a/sdk/lib/vmservice/constants.dart b/sdk/lib/vmservice/constants.dart
index 914576b..fa4b719 100644
--- a/sdk/lib/vmservice/constants.dart
+++ b/sdk/lib/vmservice/constants.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.
 
+// @dart = 2.6
+
 part of dart._vmservice;
 
 // These must be kept in sync with runtime/vm/service.cc.
diff --git a/sdk/lib/vmservice/devfs.dart b/sdk/lib/vmservice/devfs.dart
index 20e0573..283006c 100644
--- a/sdk/lib/vmservice/devfs.dart
+++ b/sdk/lib/vmservice/devfs.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.
 
+// @dart = 2.6
+
 part of dart._vmservice;
 
 String _encodeDevFSDisabledError(Message message) {
diff --git a/sdk/lib/vmservice/message.dart b/sdk/lib/vmservice/message.dart
index 9e4375a..6f2abcb 100644
--- a/sdk/lib/vmservice/message.dart
+++ b/sdk/lib/vmservice/message.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.
 
+// @dart = 2.6
+
 part of dart._vmservice;
 
 enum MessageType { Request, Notification, Response }
diff --git a/sdk/lib/vmservice/message_router.dart b/sdk/lib/vmservice/message_router.dart
index 4c1b307..90ed184 100644
--- a/sdk/lib/vmservice/message_router.dart
+++ b/sdk/lib/vmservice/message_router.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.
 
+// @dart = 2.6
+
 part of dart._vmservice;
 
 abstract class MessageRouter {
diff --git a/sdk/lib/vmservice/named_lookup.dart b/sdk/lib/vmservice/named_lookup.dart
index 7087c94..0b5c044 100644
--- a/sdk/lib/vmservice/named_lookup.dart
+++ b/sdk/lib/vmservice/named_lookup.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.
 
+// @dart = 2.6
+
 part of dart._vmservice;
 
 /// Set like containes which automatically generated String ids for its items
diff --git a/sdk/lib/vmservice/running_isolate.dart b/sdk/lib/vmservice/running_isolate.dart
index 8a6dd36..f768dec 100644
--- a/sdk/lib/vmservice/running_isolate.dart
+++ b/sdk/lib/vmservice/running_isolate.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.
 
+// @dart = 2.6
+
 part of dart._vmservice;
 
 class RunningIsolate implements MessageRouter {
diff --git a/sdk/lib/vmservice/running_isolates.dart b/sdk/lib/vmservice/running_isolates.dart
index 24b155c..191a8d1 100644
--- a/sdk/lib/vmservice/running_isolates.dart
+++ b/sdk/lib/vmservice/running_isolates.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.
 
+// @dart = 2.6
+
 part of dart._vmservice;
 
 class RunningIsolates implements MessageRouter {
diff --git a/sdk/lib/vmservice/vmservice.dart b/sdk/lib/vmservice/vmservice.dart
index 0c340ee..3c5bcbe 100644
--- a/sdk/lib/vmservice/vmservice.dart
+++ b/sdk/lib/vmservice/vmservice.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.
 
+// @dart = 2.6
+
 library dart._vmservice;
 
 import 'dart:async';
diff --git a/sdk/lib/wasm/wasm.dart b/sdk/lib/wasm/wasm.dart
index 0d123c2..3495b01 100644
--- a/sdk/lib/wasm/wasm.dart
+++ b/sdk/lib/wasm/wasm.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.
 
+// @dart = 2.6
+
 /// {@category VM}
 /// {@nodoc}
 library dart.wasm;
diff --git a/sdk/lib/web_audio/dart2js/web_audio_dart2js.dart b/sdk/lib/web_audio/dart2js/web_audio_dart2js.dart
index ef2ee67..6a431aa 100644
--- a/sdk/lib/web_audio/dart2js/web_audio_dart2js.dart
+++ b/sdk/lib/web_audio/dart2js/web_audio_dart2js.dart
@@ -1,3 +1,5 @@
+// @dart = 2.6
+
 /**
  * High-fidelity audio programming in the browser.
  *
diff --git a/sdk/lib/web_gl/dart2js/web_gl_dart2js.dart b/sdk/lib/web_gl/dart2js/web_gl_dart2js.dart
index 80e36b1..8a6347f 100644
--- a/sdk/lib/web_gl/dart2js/web_gl_dart2js.dart
+++ b/sdk/lib/web_gl/dart2js/web_gl_dart2js.dart
@@ -1,3 +1,5 @@
+// @dart = 2.6
+
 /**
  * 3D programming in the browser.
  *
diff --git a/sdk/lib/web_sql/dart2js/web_sql_dart2js.dart b/sdk/lib/web_sql/dart2js/web_sql_dart2js.dart
index 0f703f9..6390fb4 100644
--- a/sdk/lib/web_sql/dart2js/web_sql_dart2js.dart
+++ b/sdk/lib/web_sql/dart2js/web_sql_dart2js.dart
@@ -1,3 +1,5 @@
+// @dart = 2.6
+
 /**
  * An API for storing data in the browser that can be queried with SQL.
  *
diff --git a/sdk_nnbd/BUILD.gn b/sdk_nnbd/BUILD.gn
index e637088..33fa0b4 100644
--- a/sdk_nnbd/BUILD.gn
+++ b/sdk_nnbd/BUILD.gn
@@ -690,14 +690,14 @@
   visibility = [ ":copy_dev_compiler_sdk" ]
   deps = [
     ":copy_libraries",
-    "../utils/dartdevc:dartdevc_kernel_sdk_outline",
+    "../utils/dartdevc:dartdevc_platform",
     "../utils/dartdevc:dartdevc_sdk",
   ]
   gen_dir = get_label_info("../utils/dartdevc:dartdevc_sdk", "target_gen_dir")
   sources = [
     # TODO(vsm): Remove post CFE.
     "$gen_dir/ddc_sdk.sum",
-    "$gen_dir/kernel/ddc_sdk.dill",
+    "$root_out_dir/ddc_sdk.dill",
   ]
   outputs = [
     "$root_out_dir/dart-sdk/lib/_internal/{{source_file_part}}",
diff --git a/sdk_nnbd/lib/_http/http.dart b/sdk_nnbd/lib/_http/http.dart
index 2689758..aa591f2 100644
--- a/sdk_nnbd/lib/_http/http.dart
+++ b/sdk_nnbd/lib/_http/http.dart
@@ -128,8 +128,8 @@
  * about the streaming qualities of an HttpServer.
  * Pausing the subscription of the stream, pauses at the OS level.
  *
- * * The [shelf](https://pub.dartlang.org/packages/shelf)
- * package on pub.dartlang.org contains a set of high-level classes that,
+ * * The [shelf](https://pub.dev/packages/shelf)
+ * package on pub.dev contains a set of high-level classes that,
  * together with this class, makes it easy to provide content through HTTP
  * servers.
  */
@@ -1008,7 +1008,7 @@
  * that contains the content of and information about an HTTP request.
  *
  * __Note__: Check out the
- * [http_server](https://pub.dartlang.org/packages/http_server)
+ * [http_server](https://pub.dev/packages/http_server)
  * package, which makes working with the low-level
  * dart:io HTTP server subsystem easier.
  *
@@ -1404,6 +1404,22 @@
   @Deprecated("Use defaultHttpsPort instead")
   static const int DEFAULT_HTTPS_PORT = defaultHttpsPort;
 
+  /// Enable logging of HTTP requests from all [HttpClient]s to the developer
+  /// timeline.
+  ///
+  /// Default is `false`.
+  static set enableTimelineLogging(bool value) {
+    _enableTimelineLogging = value ?? false;
+  }
+
+  /// Current state of HTTP request logging from all [HttpClient]s to the
+  /// developer timeline.
+  ///
+  /// Default is `false`.
+  static bool get enableTimelineLogging => _enableTimelineLogging;
+
+  static bool _enableTimelineLogging = false;
+
   /// Gets and sets the idle timeout of non-active persistent (keep-alive)
   /// connections.
   ///
diff --git a/sdk_nnbd/lib/_http/http_impl.dart b/sdk_nnbd/lib/_http/http_impl.dart
index dbbddb6..116da12 100644
--- a/sdk_nnbd/lib/_http/http_impl.dart
+++ b/sdk_nnbd/lib/_http/http_impl.dart
@@ -445,7 +445,9 @@
   }
 
   Future<HttpClientResponse> _authenticate(bool proxyAuth) {
+    _httpRequest._timeline?.instant('Authentication');
     Future<HttpClientResponse> retry() {
+      _httpRequest._timeline?.instant('Retrying');
       // Drain body and retry.
       return drain().then((_) {
         return _httpClient
@@ -1064,6 +1066,7 @@
   // The HttpClient this request belongs to.
   final _HttpClient _httpClient;
   final _HttpClientConnection _httpClientConnection;
+  final TimelineTask _timeline;
 
   final Completer<HttpClientResponse> _responseCompleter =
       new Completer<HttpClientResponse>();
@@ -1080,15 +1083,61 @@
   List<RedirectInfo> _responseRedirects = [];
 
   _HttpClientRequest(_HttpOutgoing outgoing, Uri uri, this.method, this._proxy,
-      this._httpClient, this._httpClientConnection)
+      this._httpClient, this._httpClientConnection, this._timeline)
       : uri = uri,
         super(uri, "1.1", outgoing) {
+    _timeline?.instant('Request initiated');
     // GET and HEAD have 'content-length: 0' by default.
     if (method == "GET" || method == "HEAD") {
       contentLength = 0;
     } else {
       headers.chunkedTransferEncoding = true;
     }
+
+    _responseCompleter.future.then((response) {
+      _timeline?.instant('Response receieved');
+      Map formatConnectionInfo() => {
+            'localPort': response.connectionInfo?.localPort,
+            'remoteAddress': response.connectionInfo?.remoteAddress?.address,
+            'remotePort': response.connectionInfo?.remotePort,
+          };
+
+      Map formatHeaders() {
+        final headers = <String, List<String>>{};
+        response.headers.forEach((name, values) {
+          headers[name] = values;
+        });
+        return headers;
+      }
+
+      List<Map<String, dynamic>> formatRedirectInfo() {
+        final redirects = <Map<String, dynamic>>[];
+        for (final redirect in response.redirects) {
+          redirects.add({
+            'location': redirect.location.toString(),
+            'method': redirect.method,
+            'statusCode': redirect.statusCode,
+          });
+        }
+        return redirects;
+      }
+
+      _timeline?.finish(arguments: {
+        // TODO(bkonyi): consider exposing certificate information?
+        // 'certificate': response.certificate,
+        'requestHeaders': outgoing.outbound.headers._headers,
+        'compressionState': response.compressionState.toString(),
+        'connectionInfo': formatConnectionInfo(),
+        'contentLength': response.contentLength,
+        'cookies': [for (final cookie in response.cookies) cookie.toString()],
+        'responseHeaders': formatHeaders(),
+        'isRedirect': response.isRedirect,
+        'persistentConnection': response.persistentConnection,
+        'reasonPhrase': response.reasonPhrase,
+        'redirects': formatRedirectInfo(),
+        'statusCode': response.statusCode,
+      });
+    }, onError: (e) {});
   }
 
   Future<HttpClientResponse> get done {
@@ -1686,7 +1735,8 @@
     });
   }
 
-  _HttpClientRequest send(Uri uri, int port, String method, _Proxy proxy) {
+  _HttpClientRequest send(
+      Uri uri, int port, String method, _Proxy proxy, TimelineTask timeline) {
     if (closed) {
       throw new HttpException("Socket closed before request was sent",
           uri: uri);
@@ -1698,8 +1748,8 @@
     _SiteCredentials creds; // Credentials used to authorize this request.
     var outgoing = new _HttpOutgoing(_socket);
     // Create new request object, wrapping the outgoing connection.
-    var request =
-        new _HttpClientRequest(outgoing, uri, method, proxy, _httpClient, this);
+    var request = new _HttpClientRequest(
+        outgoing, uri, method, proxy, _httpClient, this, timeline);
     // For the Host header an IPv6 address must be enclosed in []'s.
     var host = uri.host;
     if (host.contains(':')) host = "[$host]";
@@ -1734,6 +1784,7 @@
         creds.authorize(request);
       }
     }
+
     // Start sending the request (lazy, delayed until the user provides
     // data).
     _httpParser.isHead = method == "HEAD";
@@ -1827,10 +1878,31 @@
         .then((_) => _socket.destroy());
   }
 
-  Future<_HttpClientConnection> createProxyTunnel(String host, int port,
-      _Proxy proxy, bool callback(X509Certificate certificate)) {
+  Future<_HttpClientConnection> createProxyTunnel(
+      String host,
+      int port,
+      _Proxy proxy,
+      bool callback(X509Certificate certificate),
+      TimelineTask timeline) {
+    timeline?.instant('Establishing proxy tunnel', arguments: {
+      'proxyInfo': {
+        if (proxy.host != null) 'host': proxy.host,
+        if (proxy.port != null)
+          'port': proxy.port,
+        if (proxy.username != null)
+          'username': proxy.username,
+        // TODO(bkonyi): is this something we would want to surface? Initial
+        // thought is no.
+        // if (proxy.password != null)
+        //   'password': proxy.password,
+        'isDirect': proxy.isDirect,
+      }
+    });
+    final method = "CONNECT";
+    final uri = Uri(host: host, port: port);
+    _HttpClient._startRequestTimelineEvent(timeline, method, uri);
     _HttpClientRequest request =
-        send(new Uri(host: host, port: port), port, "CONNECT", proxy);
+        send(Uri(host: host, port: port), port, method, proxy, timeline);
     if (proxy.isAuthenticated) {
       // If the proxy configuration contains user information use that
       // for proxy basic authorization.
@@ -1840,10 +1912,10 @@
     }
     return request.close().then((response) {
       if (response.statusCode != HttpStatus.ok) {
-        throw new HttpException(
-            "Proxy failed to establish tunnel "
-            "(${response.statusCode} ${response.reasonPhrase})",
-            uri: request.uri);
+        final error = "Proxy failed to establish tunnel "
+            "(${response.statusCode} ${response.reasonPhrase})";
+        timeline?.instant(error);
+        throw new HttpException(error, uri: request.uri);
       }
       var socket = (response as _HttpClientResponse)
           ._httpRequest
@@ -1853,6 +1925,7 @@
           host: host, context: _context, onBadCertificate: callback);
     }).then((secureSocket) {
       String key = _HttpClientConnection.makeKey(true, host, port);
+      timeline?.instant('Proxy tunnel established');
       return new _HttpClientConnection(
           key, secureSocket, request._httpClient, true);
     });
@@ -1966,8 +2039,8 @@
     }
   }
 
-  Future<_ConnectionInfo> connect(
-      String uriHost, int uriPort, _Proxy proxy, _HttpClient client) {
+  Future<_ConnectionInfo> connect(String uriHost, int uriPort, _Proxy proxy,
+      _HttpClient client, TimelineTask timeline) {
     if (hasIdle) {
       var connection = takeIdle();
       client._connectionsChanged();
@@ -1977,7 +2050,7 @@
         _active.length + _connecting >= client.maxConnectionsPerHost) {
       var completer = new Completer<_ConnectionInfo>();
       _pending.add(() {
-        completer.complete(connect(uriHost, uriPort, proxy, client));
+        completer.complete(connect(uriHost, uriPort, proxy, client, timeline));
       });
       return completer.future;
     }
@@ -2023,7 +2096,7 @@
         if (isSecure && !proxy.isDirect) {
           connection._dispose = true;
           return connection
-              .createProxyTunnel(uriHost, uriPort, proxy, callback)
+              .createProxyTunnel(uriHost, uriPort, proxy, callback, timeline)
               .then((tunnel) {
             client
                 ._getConnectionTarget(uriHost, uriPort, true)
@@ -2177,6 +2250,16 @@
 
   set findProxy(String f(Uri uri)) => _findProxy = f;
 
+  static void _startRequestTimelineEvent(
+      TimelineTask timeline, String method, Uri uri) {
+    timeline?.start('HTTP CLIENT ${method.toUpperCase()}', arguments: {
+      'filterKey':
+          'HTTP/client', // key used to filter network requests from timeline
+      'method': method.toUpperCase(),
+      'uri': uri.toString(),
+    });
+  }
+
   Future<_HttpClientRequest> _openUrl(String method, Uri uri) {
     if (_closing) {
       throw new StateError("Client is closed");
@@ -2214,19 +2297,32 @@
         return new Future.error(error, stackTrace);
       }
     }
-    return _getConnection(uri.host, port, proxyConf, isSecure)
-        .then((_ConnectionInfo info) {
+    TimelineTask timeline;
+    // TODO(bkonyi): do we want this to be opt-in?
+    if (HttpClient.enableTimelineLogging) {
+      timeline = TimelineTask();
+      _startRequestTimelineEvent(timeline, method, uri);
+    }
+    return _getConnection(uri.host, port, proxyConf, isSecure, timeline).then(
+        (_ConnectionInfo info) {
       _HttpClientRequest send(_ConnectionInfo info) {
+        timeline?.instant('Connection established');
         return info.connection
-            .send(uri, port, method.toUpperCase(), info.proxy);
+            .send(uri, port, method.toUpperCase(), info.proxy, timeline);
       }
 
       // If the connection was closed before the request was sent, create
       // and use another connection.
       if (info.connection.closed) {
-        return _getConnection(uri.host, port, proxyConf, isSecure).then(send);
+        return _getConnection(uri.host, port, proxyConf, isSecure, timeline)
+            .then(send);
       }
       return send(info);
+    }, onError: (error) {
+      timeline?.finish(arguments: {
+        'error': error.toString(),
+      });
+      throw error;
     });
   }
 
@@ -2293,7 +2389,7 @@
 
   // Get a new _HttpClientConnection, from the matching _ConnectionTarget.
   Future<_ConnectionInfo> _getConnection(String uriHost, int uriPort,
-      _ProxyConfiguration proxyConf, bool isSecure) {
+      _ProxyConfiguration proxyConf, bool isSecure, TimelineTask timeline) {
     Iterator<_Proxy> proxies = proxyConf.proxies.iterator;
 
     Future<_ConnectionInfo> connect(error) {
@@ -2302,7 +2398,7 @@
       String host = proxy.isDirect ? uriHost : proxy.host;
       int port = proxy.isDirect ? uriPort : proxy.port;
       return _getConnectionTarget(host, port, isSecure)
-          .connect(uriHost, uriPort, proxy, this)
+          .connect(uriHost, uriPort, proxy, this, timeline)
           // On error, continue with next proxy.
           .catchError(connect);
     }
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/patch/async_patch.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/async_patch.dart
index 894aef4..089ed04 100644
--- a/sdk_nnbd/lib/_internal/js_dev_runtime/patch/async_patch.dart
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/async_patch.dart
@@ -24,11 +24,11 @@
 @ReifyFunctionTypes(false)
 _async<T>(Function() initGenerator) {
   var iter;
-  Object Function(Object) onValue;
-  Object Function(Object, StackTrace) onError;
+  late Object? Function(Object?) onValue;
+  late Object Function(Object, StackTrace) onError;
 
-  onAwait(Object value) {
-    _Future f;
+  onAwait(Object? value) {
+    _Future<Object?> f;
     if (value is _Future) {
       f = value;
     } else if (value is Future) {
@@ -159,7 +159,7 @@
   }
 
   @ReifyFunctionTypes(false)
-  static Object _scheduleImmediateWithPromise(void Function() callback) {
+  static void _scheduleImmediateWithPromise(void Function() callback) {
     dart.addAsyncCallback();
     JS('', '#.Promise.resolve(null).then(#)', dart.global_, () {
       dart.removeAsyncCallback();
@@ -180,7 +180,7 @@
 @patch
 class Timer {
   @patch
-  static Timer _createTimer(Duration duration, void callback()) {
+  static Timer _createTimer(Duration duration, void Function() callback) {
     int milliseconds = duration.inMilliseconds;
     if (milliseconds < 0) milliseconds = 0;
     return TimerImpl(milliseconds, callback);
@@ -196,7 +196,7 @@
 }
 
 @patch
-void _rethrow(Object error, StackTrace stackTrace) {
+void _rethrow(Object error, StackTrace? stackTrace) {
   JS('', 'throw #', dart.createErrorWithStack(error, stackTrace));
 }
 
@@ -226,7 +226,7 @@
 ///     }
 ///
 class _AsyncStarImpl<T> {
-  StreamController<T> controller;
+  late StreamController<T> controller;
   Object Function(_AsyncStarImpl<T>) initGenerator;
   @notNull
   bool isSuspendedAtYieldStar = false;
@@ -241,11 +241,11 @@
   @notNull
   bool isSuspendedAtAwait = false;
 
-  Completer cancellationCompleter;
-  Object jsIterator;
+  Completer? cancellationCompleter;
+  late Object jsIterator;
 
-  Null Function(Object, StackTrace) _handleErrorCallback;
-  void Function([Object]) _runBodyCallback;
+  Null Function(Object, StackTrace)? _handleErrorCallback;
+  void Function([Object?])? _runBodyCallback;
 
   _AsyncStarImpl(this.initGenerator) {
     controller = StreamController(
@@ -291,10 +291,10 @@
       };
       var zone = Zone.current;
       if (!identical(zone, Zone.root)) {
-        _handleErrorCallback = zone.bindBinaryCallback(_handleErrorCallback);
+        _handleErrorCallback = zone.bindBinaryCallback(_handleErrorCallback!);
       }
     }
-    return _handleErrorCallback;
+    return _handleErrorCallback!;
   }
 
   void scheduleGenerator() {
@@ -316,11 +316,11 @@
     if (_runBodyCallback == null) {
       _runBodyCallback = JS('!', '#.bind(this)', runBody);
       if (!identical(zone, Zone.root)) {
-        var registered = zone.registerUnaryCallback(_runBodyCallback);
+        var registered = zone.registerUnaryCallback(_runBodyCallback!);
         _runBodyCallback = ([arg]) => zone.runUnaryGuarded(registered, arg);
       }
     }
-    zone.scheduleMicrotask(_runBodyCallback);
+    zone.scheduleMicrotask(_runBodyCallback!);
   }
 
   void runBody(awaitValue) {
@@ -333,16 +333,16 @@
       iterResult = JS('', '#.next(#)', jsIterator, awaitValue);
     } catch (e, s) {
       addError(e, s);
-      return null;
+      return;
     }
 
     if (JS('!', '#.done', iterResult)) {
       close();
-      return null;
+      return;
     }
 
     // If we're suspended at a yield/yield*, we're done for now.
-    if (isSuspendedAtYield || isSuspendedAtYieldStar) return null;
+    if (isSuspendedAtYield || isSuspendedAtYieldStar) return;
 
     // Handle `await`: if we get a value passed to `yield` it means we are
     // waiting on this Future. Make sure to prevent scheduling, and pass the
@@ -351,10 +351,10 @@
     // TODO(jmesserly): is the timing here correct? The assumption here is
     // that we should schedule `await` in `async*` the same as in `async`.
     isSuspendedAtAwait = true;
-    FutureOr<Object> value = JS('', '#.value', iterResult);
+    FutureOr<Object?> value = JS('', '#.value', iterResult);
 
     // TODO(jmesserly): this logic was copied from `async` function impl.
-    _Future f;
+    _Future<Object?> f;
     if (value is _Future) {
       f = value;
     } else if (value is Future) {
@@ -363,7 +363,7 @@
     } else {
       f = _Future.value(value);
     }
-    f._thenAwait(_runBodyCallback, handleError);
+    f._thenAwait(_runBodyCallback!, handleError);
   }
 
   /// Adds element to [stream] and returns true if the caller should terminate
@@ -417,10 +417,11 @@
   }
 
   void addError(Object error, StackTrace stackTrace) {
-    if (cancellationCompleter != null && !cancellationCompleter.isCompleted) {
+    var completer = cancellationCompleter;
+    if (completer != null && !completer.isCompleted) {
       // If the stream has been cancelled, complete the cancellation future
       // with the error.
-      cancellationCompleter.completeError(error, stackTrace);
+      completer.completeError(error, stackTrace);
     } else if (controller.hasListener) {
       controller.addError(error, stackTrace);
     }
@@ -432,10 +433,11 @@
   }
 
   void close() {
-    if (cancellationCompleter != null && !cancellationCompleter.isCompleted) {
+    var completer = cancellationCompleter;
+    if (completer != null && !completer.isCompleted) {
       // If the stream has been cancelled, complete the cancellation future
       // with the error.
-      cancellationCompleter.complete();
+      completer.complete();
     }
     controller.close();
   }
@@ -465,7 +467,7 @@
         scheduleGenerator();
       }
     }
-    return cancellationCompleter.future;
+    return cancellationCompleter!.future;
   }
 
   _fatal(String message) => throw StateError(message);
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/patch/convert_patch.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/convert_patch.dart
index 486473b..c945df2 100644
--- a/sdk_nnbd/lib/_internal/js_dev_runtime/patch/convert_patch.dart
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/convert_patch.dart
@@ -8,7 +8,7 @@
 import 'dart:_foreign_helper' show JS;
 import 'dart:_interceptors' show JSExtendableArray;
 import 'dart:_internal' show MappedIterable, ListIterable;
-import 'dart:collection' show Maps, LinkedHashMap, MapBase;
+import 'dart:collection' show LinkedHashMap, MapBase;
 import 'dart:_native_typed_data' show NativeUint8List;
 
 /**
@@ -28,7 +28,7 @@
  * Throws [FormatException] if the input is not valid JSON text.
  */
 @patch
-_parseJson(String source, reviver(Object key, Object value)) {
+_parseJson(String source, reviver(key, value)?) {
   if (source is! String) throw argumentErrorValue(source);
 
   var parsed;
@@ -51,8 +51,7 @@
  * Maps. [json] is expected to be freshly allocated so elements can be replaced
  * in-place.
  */
-_convertJsonToDart(json, reviver(Object key, Object value)) {
-  assert(reviver != null);
+_convertJsonToDart(json, reviver(Object? key, Object? value)) {
   walk(e) {
     // JavaScript null, string, number, bool are in the correct representation.
     if (JS<bool>('!', '# == null', e) ||
@@ -212,7 +211,7 @@
     return value;
   }
 
-  remove(Object key) {
+  remove(Object? key) {
     if (!_isUpgraded && !containsKey(key)) return null;
     return _upgrade().remove(key);
   }
@@ -296,7 +295,7 @@
     // safely force a concurrent modification error in case
     // someone is iterating over the map here.
     if (keys.isEmpty) {
-      keys.add(null);
+      keys.add("");
     } else {
       keys.clear();
     }
@@ -355,13 +354,13 @@
 
   /// Delegate to [parent.containsKey] to ensure the performance expected
   /// from [Map.keys.containsKey].
-  bool contains(Object key) => _parent.containsKey(key);
+  bool contains(Object? key) => _parent.containsKey(key);
 }
 
 @patch
 class JsonDecoder {
   @patch
-  StringConversionSink startChunkedConversion(Sink<Object> sink) {
+  StringConversionSink startChunkedConversion(Sink<Object?> sink) {
     return _JsonDecoderSink(_reviver, sink);
   }
 }
@@ -373,17 +372,16 @@
  * The sink only creates one object, but its input can be chunked.
  */
 // TODO(floitsch): don't accumulate everything before starting to decode.
-class _JsonDecoderSink extends _StringSinkConversionSink {
-  final Function(Object key, Object value) _reviver;
-  final Sink<Object> _sink;
+class _JsonDecoderSink extends _StringSinkConversionSink<StringBuffer> {
+  final Object? Function(Object? key, Object? value)? _reviver;
+  final Sink<Object?> _sink;
 
   _JsonDecoderSink(this._reviver, this._sink) : super(StringBuffer(''));
 
   void close() {
     super.close();
-    StringBuffer buffer = _stringSink;
-    String accumulated = buffer.toString();
-    buffer.clear();
+    String accumulated = _stringSink.toString();
+    _stringSink.clear();
     Object decoded = _parseJson(accumulated, _reviver);
     _sink.add(decoded);
     _sink.close();
@@ -399,8 +397,8 @@
 
   // Currently not intercepting UTF8 decoding.
   @patch
-  static String _convertIntercepted(
-      bool allowMalformed, List<int> codeUnits, int start, int end) {
+  static String? _convertIntercepted(
+      bool allowMalformed, List<int> codeUnits, int start, int? end) {
     // Test `codeUnits is NativeUint8List`. Dart's NativeUint8List is
     // implemented by JavaScript's Uint8Array.
     if (JS<bool>('!', '# instanceof Uint8Array', codeUnits)) {
@@ -410,8 +408,8 @@
     }
   }
 
-  static String _convertInterceptedUint8List(
-      bool allowMalformed, NativeUint8List codeUnits, int start, int end) {
+  static String? _convertInterceptedUint8List(
+      bool allowMalformed, NativeUint8List codeUnits, int start, int? end) {
     if (allowMalformed) {
       // TextDecoder with option {fatal: false} does not produce the same result
       // as [Utf8Decoder]. It disagrees on the number of `U+FFFD` (REPLACEMENT
@@ -442,12 +440,12 @@
         JS<NativeUint8List>('!', '#.subarray(#, #)', codeUnits, start, end));
   }
 
-  static String _useTextDecoderChecked(decoder, NativeUint8List codeUnits) {
+  static String? _useTextDecoderChecked(decoder, NativeUint8List codeUnits) {
     if (_unsafe(codeUnits)) return null;
     return _useTextDecoderUnchecked(decoder, codeUnits);
   }
 
-  static String _useTextDecoderUnchecked(decoder, NativeUint8List codeUnits) {
+  static String? _useTextDecoderUnchecked(decoder, NativeUint8List codeUnits) {
     // If the input is malformed, catch the exception and return `null` to fall
     // back on unintercepted decoder. The fallback will either succeed in
     // decoding, or report the problem better than TextDecoder.
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/patch/core_patch.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/core_patch.dart
index 48e9236..a8e6e12 100644
--- a/sdk_nnbd/lib/_internal/js_dev_runtime/patch/core_patch.dart
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/core_patch.dart
@@ -28,7 +28,7 @@
 
 String _symbolToString(Symbol symbol) => symbol is PrivateSymbol
     ? PrivateSymbol.getName(symbol)
-    : _symbol_dev.Symbol.getName(symbol);
+    : _symbol_dev.Symbol.getName(symbol as _symbol_dev.Symbol);
 
 @patch
 int identityHashCode(Object? object) {
@@ -102,7 +102,7 @@
 @patch
 class Function {
   @patch
-  static apply(Function f, List<Object>? positionalArguments,
+  static apply(Function function, List<dynamic>? positionalArguments,
       [Map<Symbol, dynamic>? namedArguments]) {
     positionalArguments ??= [];
     // dcall expects the namedArguments as a JS map in the last slot.
@@ -111,9 +111,9 @@
       namedArguments.forEach((symbol, arg) {
         JS('', '#[#] = #', map, _symbolToString(symbol), arg);
       });
-      return dart.dcall(f, positionalArguments, map);
+      return dart.dcall(function, positionalArguments, map);
     }
-    return dart.dcall(f, positionalArguments);
+    return dart.dcall(function, positionalArguments);
   }
 
   static Map<String, dynamic> _toMangledNames(
@@ -132,14 +132,14 @@
   @JSExportName('as')
   static Object _as_Function(Object o) {
     // Avoid extra function call to core.Function.is() by manually inlining.
-    if (JS<Object>('!', 'typeof $o == "function"') || o == null) return o;
+    if (JS<bool>('!', 'typeof $o == "function"') || o == null) return o;
     return dart.cast(o, dart.unwrapType(Function), false);
   }
 
   @JSExportName('_check')
   static Object _check_Function(Object o) {
     // Avoid extra function call to core.Function.is() by manually inlining.
-    if (JS<Object>('!', 'typeof $o == "function"') || o == null) return o;
+    if (JS<bool>('!', 'typeof $o == "function"') || o == null) return o;
     return dart.cast(o, dart.unwrapType(Function), true);
   }
 }
@@ -188,7 +188,7 @@
   @patch
   static int parse(String source,
       {int? radix, @deprecated int onError(String source)?}) {
-    return Primitives.parseInt(source, radix, onError)!;
+    return Primitives.parseInt(source, radix, onError);
   }
 
   @patch
@@ -233,8 +233,8 @@
 class double {
   @patch
   static double parse(String source,
-      [@deprecated double onError(String source)]) {
-    return Primitives.parseDouble(source, onError)!;
+      [@deprecated double onError(String source)?]) {
+    return Primitives.parseDouble(source, onError);
   }
 
   @patch
@@ -308,7 +308,7 @@
 @patch
 class Error {
   @patch
-  static String _objectToString(Object? object) {
+  static String _objectToString(Object object) {
     return "Instance of '${dart.typeName(dart.getReifiedType(object))}'";
   }
 
@@ -318,7 +318,7 @@
   }
 
   @patch
-  StackTrace get stackTrace => dart.stackTraceForError(this);
+  StackTrace? get stackTrace => dart.stackTraceForError(this);
 }
 
 @patch
@@ -452,7 +452,7 @@
   int get weekday => Primitives.getWeekday(this);
 
   @patch
-  bool operator ==(dynamic other) =>
+  bool operator ==(Object other) =>
       other is DateTime &&
       _value == other.millisecondsSinceEpoch &&
       isUtc == other.isUtc;
@@ -505,16 +505,16 @@
 @patch
 class List<E> {
   @patch
-  factory List([@undefined int _length]) {
+  factory List([@undefined int? length]) {
     dynamic list;
-    if (JS<bool>('!', '# === void 0', _length)) {
+    if (JS<bool>('!', '# === void 0', length)) {
       list = JS('', '[]');
     } else {
-      int length = JS('!', '#', _length);
-      if (_length == null || length < 0) {
+      int _length = JS('!', '#', length);
+      if (length == null || _length < 0) {
         throw ArgumentError("Length must be a non-negative integer: $_length");
       }
-      list = JS('', 'new Array(#)', length);
+      list = JS('', 'new Array(#)', _length);
       JS('', '#.fill(null)', list);
       JSArray.markFixedList(list);
     }
@@ -522,7 +522,7 @@
   }
 
   @patch
-  factory List.empty({bool growable = false}) {
+  factory List.empty({bool growable = true}) {
     var list = JSArray<E>.of(JS('', 'new Array()'));
     if (!growable) JSArray.markFixedList(list);
     return list;
@@ -565,7 +565,7 @@
 @patch
 class Map<K, V> {
   @patch
-  factory Map.unmodifiable(Map other) {
+  factory Map.unmodifiable(Map<dynamic, dynamic> other) {
     return UnmodifiableMapView<K, V>(Map<K, V>.from(other));
   }
 
@@ -740,7 +740,7 @@
   }
 
   @patch
-  void writeAll(Iterable objects, [String separator = ""]) {
+  void writeAll(Iterable<dynamic> objects, [String separator = ""]) {
     _contents = _writeAll(_contents, objects, separator);
   }
 
@@ -796,18 +796,15 @@
   final Symbol _memberName;
   final List? _arguments;
   final Map<Symbol, dynamic>? _namedArguments;
-  final List? _existingArgumentNames;
   final Invocation? _invocation;
 
   @patch
   NoSuchMethodError(Object? receiver, Symbol memberName,
-      List? positionalArguments, Map<Symbol, dynamic>? namedArguments,
-      [List? existingArgumentNames = null])
+      List? positionalArguments, Map<Symbol, dynamic>? namedArguments)
       : _receiver = receiver,
         _memberName = memberName,
         _arguments = positionalArguments,
         _namedArguments = namedArguments,
-        _existingArgumentNames = existingArgumentNames,
         _invocation = null;
 
   @patch
@@ -816,7 +813,6 @@
         _memberName = invocation.memberName,
         _arguments = invocation.positionalArguments,
         _namedArguments = invocation.namedArguments,
-        _existingArgumentNames = null,
         _invocation = invocation;
 
   @patch
@@ -848,20 +844,10 @@
     var failureMessage = (invocation is dart.InvocationImpl)
         ? invocation.failureMessage
         : 'method not found';
-    List? existingArgumentNames = _existingArgumentNames;
-    if (existingArgumentNames == null) {
-      return "NoSuchMethodError: '$memberName'\n"
-          "$failureMessage\n"
-          "Receiver: ${receiverText}\n"
-          "Arguments: [$actualParameters]";
-    } else {
-      String formalParameters = existingArgumentNames.join(', ');
-      return "NoSuchMethodError: incorrect number of arguments passed to "
-          "method named '$memberName'\n"
-          "Receiver: ${receiverText}\n"
-          "Tried calling: $memberName($actualParameters)\n"
-          "Found: $memberName($formalParameters)";
-    }
+    return "NoSuchMethodError: '$memberName'\n"
+        "$failureMessage\n"
+        "Receiver: ${receiverText}\n"
+        "Arguments: [$actualParameters]";
   }
 }
 
@@ -957,6 +943,9 @@
 int _max(int a, int b) => a > b ? a : b;
 int _min(int a, int b) => a < b ? a : b;
 
+/// Empty list used as an initializer for local variables in the `_BigIntImpl`.
+final _dummyList = new Uint16List(0);
+
 // Copyright 2009 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
@@ -1014,14 +1003,14 @@
 
   // Result cache for last _divRem call.
   // Result cache for last _divRem call.
-  static Uint16List _lastDividendDigits;
-  static int _lastDividendUsed;
-  static Uint16List _lastDivisorDigits;
-  static int _lastDivisorUsed;
-  static Uint16List _lastQuoRemDigits;
-  static int _lastQuoRemUsed;
-  static int _lastRemUsed;
-  static int _lastRem_nsh;
+  static Uint16List? _lastDividendDigits;
+  static int? _lastDividendUsed;
+  static Uint16List? _lastDivisorDigits;
+  static int? _lastDivisorUsed;
+  static Uint16List? _lastQuoRemDigits;
+  static int? _lastQuoRemUsed;
+  static int? _lastRemUsed;
+  static int? _lastRem_nsh;
 
   /// Whether this bigint is negative.
   final bool _isNegative;
@@ -1081,7 +1070,7 @@
     // Read in the source 4 digits at a time.
     // The first part may have a few leading virtual '0's to make the remaining
     // parts all have exactly 4 digits.
-    int digitInPartCount = 4 - source.length.remainder(4);
+    var digitInPartCount = 4 - source.length.remainder(4);
     if (digitInPartCount == 4) digitInPartCount = 0;
     for (int i = 0; i < source.length; i++) {
       part = part * 10 + source.codeUnitAt(i) - _0;
@@ -1123,7 +1112,7 @@
   /// If [isNegative] is true, negates the result before returning it.
   ///
   /// The [source] (substring) must be a valid hex literal.
-  static _BigIntImpl _parseHex(String source, int startPos, bool isNegative) {
+  static _BigIntImpl? _parseHex(String source, int startPos, bool isNegative) {
     int hexDigitsPerChunk = _digitBits ~/ 4;
     int sourceLength = source.length - startPos;
     int chunkCount = (sourceLength / hexDigitsPerChunk).ceil();
@@ -1157,7 +1146,7 @@
   ///
   /// The [source] will be checked for invalid characters. If it is invalid,
   /// this function returns `null`.
-  static _BigIntImpl _parseRadix(String source, int radix, bool isNegative) {
+  static _BigIntImpl? _parseRadix(String source, int radix, bool isNegative) {
     var result = zero;
     var base = _BigIntImpl._fromInt(radix);
     for (int i = 0; i < source.length; i++) {
@@ -1209,11 +1198,11 @@
       return _parseDecimal(decimalMatch, isNegative);
     }
     if (radix == 16 && (decimalMatch != null || nonDecimalMatch != null)) {
-      return _parseHex(decimalMatch ?? nonDecimalMatch, 0, isNegative);
+      return _parseHex(decimalMatch ?? nonDecimalMatch!, 0, isNegative);
     }
 
     return _parseRadix(
-        decimalMatch ?? nonDecimalMatch ?? hexMatch, radix, isNegative);
+        decimalMatch ?? nonDecimalMatch ?? hexMatch!, radix, isNegative);
   }
 
   static RegExp _parseRE = RegExp(
@@ -1261,7 +1250,7 @@
     // then use the bit-manipulating `_fromDouble` for all other values.
     if (value.abs() < 0x100000000) return _BigIntImpl._fromInt(value.toInt());
     if (value is double) return _BigIntImpl._fromDouble(value);
-    return _BigIntImpl._fromInt(value);
+    return _BigIntImpl._fromInt(value as int);
   }
 
   factory _BigIntImpl._fromInt(int value) {
@@ -1563,8 +1552,7 @@
   ///
   /// Returns 0 if abs(this) == abs(other); a positive number if
   /// abs(this) > abs(other); and a negative number if abs(this) < abs(other).
-  int _absCompare(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  int _absCompare(_BigIntImpl other) {
     return _compareDigits(_digits, _used, other._digits, other._used);
   }
 
@@ -1574,8 +1562,7 @@
    * Returns a negative number if `this` is less than `other`, zero if they are
    * equal, and a positive number if `this` is greater than `other`.
    */
-  int compareTo(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  int compareTo(covariant _BigIntImpl other) {
     if (_isNegative == other._isNegative) {
       var result = _absCompare(other);
       // Use 0 - result to avoid negative zero in JavaScript.
@@ -1717,7 +1704,8 @@
     var digits = _digits;
     var otherDigits = other._digits;
     var resultDigits = Uint16List(resultUsed);
-    var l, m;
+    _BigIntImpl l;
+    int m;
     if (used < otherUsed) {
       l = other;
       m = used;
@@ -1743,7 +1731,8 @@
     var digits = _digits;
     var otherDigits = other._digits;
     var resultDigits = Uint16List(resultUsed);
-    var l, m;
+    _BigIntImpl l;
+    int m;
     if (used < otherUsed) {
       l = other;
       m = used;
@@ -1771,8 +1760,7 @@
    * Of both operands are negative, the result is negative, otherwise
    * the result is non-negative.
    */
-  _BigIntImpl operator &(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl operator &(covariant _BigIntImpl other) {
     if (_isZero || other._isZero) return zero;
     if (_isNegative == other._isNegative) {
       if (_isNegative) {
@@ -1787,7 +1775,7 @@
       return _absAndSetSign(other, false);
     }
     // _isNegative != other._isNegative
-    var p, n;
+    _BigIntImpl p, n;
     if (_isNegative) {
       p = other;
       n = this;
@@ -1811,8 +1799,7 @@
    * If both operands are non-negative, the result is non-negative,
    * otherwise the result us negative.
    */
-  _BigIntImpl operator |(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl operator |(covariant _BigIntImpl other) {
     if (_isZero) return other;
     if (other._isZero) return this;
     if (_isNegative == other._isNegative) {
@@ -1828,7 +1815,7 @@
       return _absOrSetSign(other, false);
     }
     // _neg != a._neg
-    var p, n;
+    _BigIntImpl p, n;
     if (_isNegative) {
       p = other;
       n = this;
@@ -1853,8 +1840,7 @@
    * If the operands have the same sign, the result is non-negative,
    * otherwise the result is negative.
    */
-  _BigIntImpl operator ^(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl operator ^(covariant _BigIntImpl other) {
     if (_isZero) return other;
     if (other._isZero) return this;
     if (_isNegative == other._isNegative) {
@@ -1867,7 +1853,7 @@
       return _absXorSetSign(other, false);
     }
     // _isNegative != a._isNegative
-    var p, n;
+    _BigIntImpl p, n;
     if (_isNegative) {
       p = other;
       n = this;
@@ -1902,8 +1888,7 @@
   }
 
   /// Addition operator.
-  _BigIntImpl operator +(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl operator +(covariant _BigIntImpl other) {
     if (_isZero) return other;
     if (other._isZero) return this;
     var isNegative = _isNegative;
@@ -1921,8 +1906,7 @@
   }
 
   /// Subtraction operator.
-  _BigIntImpl operator -(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl operator -(covariant _BigIntImpl other) {
     if (_isZero) return -other;
     if (other._isZero) return this;
     var isNegative = _isNegative;
@@ -1974,8 +1958,7 @@
   }
 
   /// Multiplication operator.
-  _BigIntImpl operator *(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl operator *(covariant _BigIntImpl other) {
     var used = _used;
     var otherUsed = other._used;
     if (used == 0 || otherUsed == 0) {
@@ -2023,8 +2006,7 @@
   }
 
   /// Returns `trunc(this / other)`, with `other != 0`.
-  _BigIntImpl _div(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl _div(_BigIntImpl other) {
     assert(other._used > 0);
     if (_used < other._used) {
       return zero;
@@ -2032,9 +2014,9 @@
     _divRem(other);
     // Return quotient, i.e.
     // _lastQuoRem_digits[_lastRem_used.._lastQuoRem_used-1] with proper sign.
-    var lastQuo_used = _lastQuoRemUsed - _lastRemUsed;
+    var lastQuo_used = _lastQuoRemUsed! - _lastRemUsed!;
     var quo_digits = _cloneDigits(
-        _lastQuoRemDigits, _lastRemUsed, _lastQuoRemUsed, lastQuo_used);
+        _lastQuoRemDigits!, _lastRemUsed!, _lastQuoRemUsed!, lastQuo_used);
     var quo = _BigIntImpl._(false, lastQuo_used, quo_digits);
     if ((_isNegative != other._isNegative) && (quo._used > 0)) {
       quo = -quo;
@@ -2043,8 +2025,7 @@
   }
 
   /// Returns `this - other * trunc(this / other)`, with `other != 0`.
-  _BigIntImpl _rem(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl _rem(_BigIntImpl other) {
     assert(other._used > 0);
     if (_used < other._used) {
       return this;
@@ -2053,10 +2034,10 @@
     // Return remainder, i.e.
     // denormalized _lastQuoRem_digits[0.._lastRem_used-1] with proper sign.
     var remDigits =
-        _cloneDigits(_lastQuoRemDigits, 0, _lastRemUsed, _lastRemUsed);
-    var rem = _BigIntImpl._(false, _lastRemUsed, remDigits);
-    if (_lastRem_nsh > 0) {
-      rem = rem >> _lastRem_nsh; // Denormalize remainder.
+        _cloneDigits(_lastQuoRemDigits!, 0, _lastRemUsed!, _lastRemUsed!);
+    var rem = _BigIntImpl._(false, _lastRemUsed!, remDigits);
+    if (_lastRem_nsh! > 0) {
+      rem = rem >> _lastRem_nsh!; // Denormalize remainder.
     }
     if (_isNegative && (rem._used > 0)) {
       rem = -rem;
@@ -2244,8 +2225,7 @@
    * seven.remainder(-three);   // => 1
    * ```
    */
-  _BigIntImpl operator ~/(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl operator ~/(covariant _BigIntImpl other) {
     if (other._used == 0) {
       throw const IntegerDivisionByZeroException();
     }
@@ -2259,8 +2239,7 @@
    * `this == (this ~/ other) * other + r`.
    * As a consequence the remainder `r` has the same sign as the divider `this`.
    */
-  _BigIntImpl remainder(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl remainder(covariant _BigIntImpl other) {
     if (other._used == 0) {
       throw const IntegerDivisionByZeroException();
     }
@@ -2271,16 +2250,16 @@
   double operator /(BigInt other) => this.toDouble() / other.toDouble();
 
   /** Relational less than operator. */
-  bool operator <(BigInt other) => compareTo(other) < 0;
+  bool operator <(covariant _BigIntImpl other) => compareTo(other) < 0;
 
   /** Relational less than or equal operator. */
-  bool operator <=(BigInt other) => compareTo(other) <= 0;
+  bool operator <=(covariant _BigIntImpl other) => compareTo(other) <= 0;
 
   /** Relational greater than operator. */
-  bool operator >(BigInt other) => compareTo(other) > 0;
+  bool operator >(covariant _BigIntImpl other) => compareTo(other) > 0;
 
   /** Relational greater than or equal operator. */
-  bool operator >=(BigInt other) => compareTo(other) >= 0;
+  bool operator >=(covariant _BigIntImpl other) => compareTo(other) >= 0;
 
   /**
    * Euclidean modulo operator.
@@ -2293,8 +2272,7 @@
    *
    * See [remainder] for the remainder of the truncating division.
    */
-  _BigIntImpl operator %(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl operator %(covariant _BigIntImpl other) {
     if (other._used == 0) {
       throw const IntegerDivisionByZeroException();
     }
@@ -2357,9 +2335,8 @@
    * The [exponent] must be non-negative and [modulus] must be
    * positive.
    */
-  _BigIntImpl modPow(BigInt bigExponent, BigInt bigModulus) {
-    _BigIntImpl exponent = bigExponent;
-    _BigIntImpl modulus = bigModulus;
+  _BigIntImpl modPow(
+      covariant _BigIntImpl exponent, covariant _BigIntImpl modulus) {
     if (exponent._isNegative) {
       throw ArgumentError("exponent must be positive: $exponent");
     }
@@ -2383,7 +2360,7 @@
       resultDigits[j] = gDigits[j];
     }
     var resultUsed = gUsed;
-    var result2Used;
+    int result2Used;
     for (int i = exponentBitlen - 2; i >= 0; i--) {
       result2Used = z.sqr(resultDigits, resultUsed, result2Digits);
       if (!(exponent & (one << i))._isZero) {
@@ -2458,19 +2435,19 @@
     // Variables a, b, c, and d require one more digit.
     final abcdUsed = maxUsed + 1;
     final abcdLen = abcdUsed + 2; // +2 to satisfy _absAdd.
-    var aDigits, bDigits, cDigits, dDigits;
-    bool aIsNegative, bIsNegative, cIsNegative, dIsNegative;
+    var aDigits = _dummyList;
+    var aIsNegative = false;
+    var cDigits = _dummyList;
+    var cIsNegative = false;
     if (ac) {
       aDigits = Uint16List(abcdLen);
-      aIsNegative = false;
       aDigits[0] = 1;
       cDigits = Uint16List(abcdLen);
-      cIsNegative = false;
     }
-    bDigits = Uint16List(abcdLen);
-    bIsNegative = false;
-    dDigits = Uint16List(abcdLen);
-    dIsNegative = false;
+    var bDigits = Uint16List(abcdLen);
+    var bIsNegative = false;
+    var dDigits = Uint16List(abcdLen);
+    var dIsNegative = false;
     dDigits[0] = 1;
 
     while (true) {
@@ -2663,8 +2640,7 @@
    * It is an error if no modular inverse exists.
    */
   // Returns 1/this % modulus, with modulus > 0.
-  _BigIntImpl modInverse(BigInt bigInt) {
-    _BigIntImpl modulus = bigInt;
+  _BigIntImpl modInverse(covariant _BigIntImpl modulus) {
     if (modulus <= zero) {
       throw ArgumentError("Modulus must be strictly positive: $modulus");
     }
@@ -2689,8 +2665,7 @@
    *
    * If both `this` and `other` is zero, the result is also zero.
    */
-  _BigIntImpl gcd(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl gcd(covariant _BigIntImpl other) {
     if (_isZero) return other.abs();
     if (other._isZero) return this.abs();
     return _binaryGcd(this, other, false);
@@ -3009,8 +2984,8 @@
                 _modulus._digits[_modulus._used - 1].bitLength);
 
   int convert(_BigIntImpl x, Uint16List resultDigits) {
-    var digits;
-    var used;
+    Uint16List digits;
+    int used;
     if (x._isNegative || x._absCompare(_modulus) >= 0) {
       var remainder = x._rem(_modulus);
       if (x._isNegative && remainder._used > 0) {
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/patch/internal_patch.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/internal_patch.dart
index 5e850bb..6ab95c4 100644
--- a/sdk_nnbd/lib/_internal/js_dev_runtime/patch/internal_patch.dart
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/patch/internal_patch.dart
@@ -2,8 +2,6 @@
 // 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:core' hide Symbol;
-import 'dart:core' as core show Symbol;
 import 'dart:_js_primitives' show printString;
 import 'dart:_js_helper' show patch;
 import 'dart:_interceptors' show JSArray;
@@ -17,7 +15,7 @@
 
   @patch
   int get hashCode {
-    int hash = JS('int|Null', '#._hashCode', this);
+    int? hash = JS('int|Null', '#._hashCode', this);
     if (hash != null) return hash;
     const arbitraryPrime = 664597;
     hash = 0x1fffffff & (arbitraryPrime * _name.hashCode);
@@ -38,13 +36,13 @@
 }
 
 @patch
-List<E> makeListFixedLength<E>(List<E> growableList) {
+List<T> makeListFixedLength<T>(List<T> growableList) {
   JSArray.markFixedList(growableList);
   return growableList;
 }
 
 @patch
-List<E> makeFixedListUnmodifiable<E>(List<E> fixedLengthList) {
+List<T> makeFixedListUnmodifiable<T>(List<T> fixedLengthList) {
   JSArray.markUnmodifiableList(fixedLengthList);
   return fixedLengthList;
 }
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart
index b4ee6a6..c9263ba 100644
--- a/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart
@@ -34,8 +34,7 @@
   // TODO(vsm): Per spec, we should throw an NSM here.  Technically, we ought
   // to thread through method info, but that uglifies the code and can't
   // actually be queried ... it only affects how the error is printed.
-  throw NoSuchMethodError(
-      null, Symbol('<Unexpected Null Value>'), null, null, null);
+  throw NoSuchMethodError(null, Symbol('<Unexpected Null Value>'), null, null);
 }
 
 castError(obj, expectedType, [@notNull bool isImplicit = false]) {
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/debugger.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/debugger.dart
index 8715cbd..f6ec3b3 100644
--- a/sdk_nnbd/lib/_internal/js_dev_runtime/private/debugger.dart
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/debugger.dart
@@ -2,8 +2,6 @@
 // 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.5
-
 library dart._debugger;
 
 import 'dart:_foreign_helper' show JS;
@@ -172,7 +170,7 @@
 /// [JsonMLFormatter] consumes [NameValuePair] objects and
 class NameValuePair {
   NameValuePair(
-      {this.name,
+      {this.name = '',
       this.value,
       this.config = JsonMLConfig.none,
       this.hideName = false});
@@ -188,7 +186,7 @@
   int get hashCode => name.hashCode;
 
   final String name;
-  final Object value;
+  final Object? value;
   final JsonMLConfig config;
   final bool hideName;
 
@@ -198,8 +196,8 @@
 class MapEntry {
   MapEntry({this.key, this.value});
 
-  final Object key;
-  final Object value;
+  final Object? key;
+  final Object? value;
 }
 
 class IterableSpan {
@@ -217,7 +215,7 @@
   /// 10000-length subset and 1 1-length subset.
   int get maxPowerOfSubsetSize =>
       (log(length - .5) / log(_maxSpanLength)).truncate();
-  int get subsetSize => pow(_maxSpanLength, maxPowerOfSubsetSize);
+  int get subsetSize => pow(_maxSpanLength, maxPowerOfSubsetSize).toInt();
 
   Map<int, dynamic> asMap() =>
       iterable.skip(start).take(length).toList().asMap();
@@ -285,7 +283,7 @@
 /// Devtools Formatter API.
 class JsonMLElement {
   dynamic _attributes;
-  List _jsonML;
+  late List _jsonML;
 
   JsonMLElement(tagName) {
     _attributes = JS('', '{}');
@@ -409,7 +407,7 @@
       // The value is indented when it is on a different line from the name
       // by setting right padding of the name to -13px and the padding of the
       // value to 13px.
-      JsonMLElement nameSpan;
+      JsonMLElement? nameSpan;
       var valueStyle = '';
       if (!child.hideName) {
         nameSpan = JsonMLElement('span')
@@ -445,38 +443,36 @@
 
 abstract class Formatter {
   bool accept(object, config);
-  String preview(object);
+  String? preview(object);
   bool hasChildren(object);
-  List<NameValuePair> children(object);
+  List<NameValuePair>? children(object);
 }
 
 class DartFormatter {
-  List<Formatter> _formatters;
+  final List<Formatter> _formatters;
 
-  DartFormatter() {
-    // The order of formatters matters as formatters earlier in the list take
-    // precedence.
-    _formatters = [
-      ObjectInternalsFormatter(),
-      ClassFormatter(),
-      TypeFormatter(),
-      NamedConstructorFormatter(),
-      MapFormatter(),
-      MapOverviewFormatter(),
-      IterableFormatter(),
-      IterableSpanFormatter(),
-      MapEntryFormatter(),
-      StackTraceFormatter(),
-      ErrorAndExceptionFormatter(),
-      FunctionFormatter(),
-      HeritageClauseFormatter(),
-      LibraryModuleFormatter(),
-      LibraryFormatter(),
-      ObjectFormatter(),
-    ];
-  }
+  DartFormatter()
+      : _formatters = [
+          // Formatters earlier in the list take precedence.
+          ObjectInternalsFormatter(),
+          ClassFormatter(),
+          TypeFormatter(),
+          NamedConstructorFormatter(),
+          MapFormatter(),
+          MapOverviewFormatter(),
+          IterableFormatter(),
+          IterableSpanFormatter(),
+          MapEntryFormatter(),
+          StackTraceFormatter(),
+          ErrorAndExceptionFormatter(),
+          FunctionFormatter(),
+          HeritageClauseFormatter(),
+          LibraryModuleFormatter(),
+          LibraryFormatter(),
+          ObjectFormatter(),
+        ];
 
-  String preview(object, config) {
+  String? preview(object, config) {
     try {
       if (object == null ||
           object is num ||
@@ -511,7 +507,7 @@
     return false;
   }
 
-  List<NameValuePair> children(object, config) {
+  List<NameValuePair>? children(object, config) {
     try {
       if (object != null) {
         for (var formatter in _formatters) {
@@ -557,7 +553,7 @@
 
   bool hasChildren(object) => true;
 
-  List<NameValuePair> children(object) {
+  children(object) {
     var type = dart.getType(object);
     var ret = LinkedHashSet<NameValuePair>();
     // We use a Set rather than a List to avoid duplicates.
@@ -590,7 +586,7 @@
 
 /// Formatter for module Dart Library objects.
 class LibraryModuleFormatter implements Formatter {
-  accept(object, config) => dart.getModuleName(object) != null;
+  bool accept(object, config) => dart.getModuleName(object) != null;
 
   bool hasChildren(object) => true;
 
@@ -621,7 +617,7 @@
 class LibraryFormatter implements Formatter {
   var genericParameters = HashMap<String, String>();
 
-  accept(object, config) => object is Library;
+  bool accept(object, config) => object is Library;
 
   bool hasChildren(object) => true;
 
@@ -656,7 +652,7 @@
 /// we can distinguish them based on whether they have been tagged with
 /// runtime type information.
 class FunctionFormatter implements Formatter {
-  accept(object, config) {
+  bool accept(object, config) {
     if (_typeof(object) != 'function') return false;
     return dart.getReifiedType(object) != null;
   }
@@ -689,7 +685,7 @@
 class MapOverviewFormatter implements Formatter {
   // Because this comes after MapFormatter in the list, internal
   // maps will be picked up by that formatter.
-  accept(object, config) => object is Map;
+  bool accept(object, config) => object is Map;
 
   bool hasChildren(object) => true;
 
@@ -717,7 +713,7 @@
 /// This is only used for internal maps, or when shown as [[entries]]
 /// from MapOverViewFormatter.
 class MapFormatter implements Formatter {
-  accept(object, config) =>
+  bool accept(object, config) =>
       object is InternalMap || config == JsonMLConfig.asMap;
 
   bool hasChildren(object) => true;
@@ -778,7 +774,7 @@
 }
 
 class NamedConstructorFormatter implements Formatter {
-  accept(object, config) => object is NamedConstructor;
+  bool accept(object, config) => object is NamedConstructor;
 
   // TODO(bmilligan): Display the signature of the named constructor as the
   // preview.
@@ -797,7 +793,7 @@
 /// Formatter for synthetic MapEntry objects used to display contents of a Map
 /// cleanly.
 class MapEntryFormatter implements Formatter {
-  accept(object, config) => object is MapEntry;
+  bool accept(object, config) => object is MapEntry;
 
   String preview(object) {
     MapEntry entry = object;
@@ -838,7 +834,7 @@
 /// Formatter for synthetic IterableSpan objects used to display contents of
 /// an Iterable cleanly.
 class IterableSpanFormatter implements Formatter {
-  accept(object, config) => object is IterableSpan;
+  bool accept(object, config) => object is IterableSpan;
 
   String preview(object) {
     return '[${object.start}...${object.end - 1}]';
@@ -853,7 +849,7 @@
 class ErrorAndExceptionFormatter extends ObjectFormatter {
   static final RegExp _pattern = RegExp(r'\d+\:\d+');
 
-  accept(object, config) => object is Error || object is Exception;
+  bool accept(object, config) => object is Error || object is Exception;
 
   bool hasChildren(object) => true;
 
@@ -866,8 +862,8 @@
             l.contains(_pattern) &&
             !l.contains('dart:sdk') &&
             !l.contains('dart_sdk'),
-        orElse: () => null);
-    return line != null ? '${object} at ${line}' : '${object}';
+        orElse: () => '');
+    return line != '' ? '${object} at ${line}' : '${object}';
   }
 
   List<NameValuePair> children(object) {
@@ -889,7 +885,7 @@
 }
 
 class StackTraceFormatter implements Formatter {
-  accept(object, config) => object is StackTrace;
+  bool accept(object, config) => object is StackTrace;
 
   String preview(object) => 'StackTrace';
 
@@ -907,7 +903,7 @@
 }
 
 class ClassFormatter implements Formatter {
-  accept(object, config) => config == JsonMLConfig.asClass;
+  bool accept(object, config) => config == JsonMLConfig.asClass;
 
   String preview(type) {
     var implements = dart.getImplements(type);
@@ -978,7 +974,7 @@
 }
 
 class TypeFormatter implements Formatter {
-  accept(object, config) => object is Type;
+  bool accept(object, config) => object is Type;
 
   String preview(object) => object.toString();
 
@@ -994,7 +990,7 @@
 ///
 /// Raw JS stack traces are used if $dartStackTraceUtility has not been
 /// specified.
-StackTraceMapper get stackTraceMapper {
+StackTraceMapper? get stackTraceMapper {
   var _util = JS('', r'#.$dartStackTraceUtility', dart.global_);
   return _util != null ? JS('!', '#.mapper', _util) : null;
 }
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/foreign_helper.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/foreign_helper.dart
index c9296cc..357047e 100644
--- a/sdk_nnbd/lib/_internal/js_dev_runtime/private/foreign_helper.dart
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/foreign_helper.dart
@@ -2,8 +2,6 @@
 // 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.5
-
 library dart._foreign_helper;
 
 /**
@@ -108,7 +106,7 @@
  */
 // Add additional optional arguments if needed. The method is treated internally
 // as a variable argument method.
-T JS<T extends Object>(String typeDescription, String codeTemplate,
+T JS<T extends Object?>(String typeDescription, String codeTemplate,
     [arg0,
     arg1,
     arg2,
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/isolate_helper.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/isolate_helper.dart
index 44824c7..6576653 100644
--- a/sdk_nnbd/lib/_internal/js_dev_runtime/private/isolate_helper.dart
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/isolate_helper.dart
@@ -2,8 +2,6 @@
 // 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.5
-
 library dart._isolate_helper;
 
 import 'dart:_runtime' as dart;
@@ -36,7 +34,7 @@
 
 class TimerImpl implements Timer {
   final bool _once;
-  int _handle;
+  int? _handle;
   int _tick = 0;
 
   TimerImpl(int milliseconds, void callback()) : _once = true {
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_helper.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_helper.dart
index e86378d..dcf1866 100644
--- a/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_helper.dart
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/js_helper.dart
@@ -203,7 +203,7 @@
   }
 
   static int timerFrequency;
-  static num Function() timerTicks;
+  static int Function() timerTicks;
 
   static bool get isD8 {
     return JS(
@@ -268,7 +268,7 @@
   }
 
   @notNull
-  static String stringFromCharCodes(JSArray<int> charCodes) {
+  static String stringFromCharCodes(List<int> charCodes) {
     for (@nullCheck var i in charCodes) {
       if (i < 0) throw argumentErrorValue(i);
       if (i > 0xffff) return stringFromCodePoints(charCodes);
@@ -362,7 +362,7 @@
     return -JS<int>('!', r'#.getTimezoneOffset()', lazyAsJsDate(receiver));
   }
 
-  static num valueFromDecomposedDate(
+  static int valueFromDecomposedDate(
       @nullCheck int years,
       @nullCheck int month,
       @nullCheck int day,
@@ -375,10 +375,10 @@
     var jsMonth = month - 1;
     num value;
     if (isUtc) {
-      value = JS('!', r'Date.UTC(#, #, #, #, #, #, #)', years, jsMonth, day,
-          hours, minutes, seconds, milliseconds);
+      value = JS<int>('!', r'Date.UTC(#, #, #, #, #, #, #)', years, jsMonth,
+          day, hours, minutes, seconds, milliseconds);
     } else {
-      value = JS('!', r'new Date(#, #, #, #, #, #, #).valueOf()', years,
+      value = JS<int>('!', r'new Date(#, #, #, #, #, #, #).valueOf()', years,
           jsMonth, day, hours, minutes, seconds, milliseconds);
     }
     if (value.isNaN ||
@@ -390,14 +390,14 @@
     return value;
   }
 
-  static num patchUpY2K(value, years, isUtc) {
-    var date = JS('', r'new Date(#)', value);
+  static int patchUpY2K(value, years, isUtc) {
+    var date = JS<int>('!', r'new Date(#)', value);
     if (isUtc) {
-      JS('', r'#.setUTCFullYear(#)', date, years);
+      JS<int>('!', r'#.setUTCFullYear(#)', date, years);
     } else {
-      JS('', r'#.setFullYear(#)', date, years);
+      JS<int>('!', r'#.setFullYear(#)', date, years);
     }
-    return JS('!', r'#.valueOf()', date);
+    return JS<int>('!', r'#.valueOf()', date);
   }
 
   // Lazily keep a JS Date stored in the JS object.
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/native_typed_data.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/native_typed_data.dart
index 2a7a621..e1ed809 100644
--- a/sdk_nnbd/lib/_internal/js_dev_runtime/private/native_typed_data.dart
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/native_typed_data.dart
@@ -33,69 +33,69 @@
 
   Type get runtimeType => ByteBuffer;
 
-  Uint8List asUint8List([int offsetInBytes = 0, int length]) {
+  Uint8List asUint8List([int offsetInBytes = 0, int? length]) {
     return NativeUint8List.view(this, offsetInBytes, length);
   }
 
-  Int8List asInt8List([int offsetInBytes = 0, int length]) {
+  Int8List asInt8List([int offsetInBytes = 0, int? length]) {
     return NativeInt8List.view(this, offsetInBytes, length);
   }
 
-  Uint8ClampedList asUint8ClampedList([int offsetInBytes = 0, int length]) {
+  Uint8ClampedList asUint8ClampedList([int offsetInBytes = 0, int? length]) {
     return NativeUint8ClampedList.view(this, offsetInBytes, length);
   }
 
-  Uint16List asUint16List([int offsetInBytes = 0, int length]) {
+  Uint16List asUint16List([int offsetInBytes = 0, int? length]) {
     return NativeUint16List.view(this, offsetInBytes, length);
   }
 
-  Int16List asInt16List([int offsetInBytes = 0, int length]) {
+  Int16List asInt16List([int offsetInBytes = 0, int? length]) {
     return NativeInt16List.view(this, offsetInBytes, length);
   }
 
-  Uint32List asUint32List([int offsetInBytes = 0, int length]) {
+  Uint32List asUint32List([int offsetInBytes = 0, int? length]) {
     return NativeUint32List.view(this, offsetInBytes, length);
   }
 
-  Int32List asInt32List([int offsetInBytes = 0, int length]) {
+  Int32List asInt32List([int offsetInBytes = 0, int? length]) {
     return NativeInt32List.view(this, offsetInBytes, length);
   }
 
-  Uint64List asUint64List([int offsetInBytes = 0, int length]) {
+  Uint64List asUint64List([int offsetInBytes = 0, int? length]) {
     throw UnsupportedError("Uint64List not supported by dart2js.");
   }
 
-  Int64List asInt64List([int offsetInBytes = 0, int length]) {
+  Int64List asInt64List([int offsetInBytes = 0, int? length]) {
     throw UnsupportedError("Int64List not supported by dart2js.");
   }
 
-  Int32x4List asInt32x4List([int offsetInBytes = 0, int length]) {
-    NativeInt32List storage =
+  Int32x4List asInt32x4List([int offsetInBytes = 0, int? length]) {
+    var storage =
         this.asInt32List(offsetInBytes, length != null ? length * 4 : null);
     return NativeInt32x4List._externalStorage(storage);
   }
 
-  Float32List asFloat32List([int offsetInBytes = 0, int length]) {
+  Float32List asFloat32List([int offsetInBytes = 0, int? length]) {
     return NativeFloat32List.view(this, offsetInBytes, length);
   }
 
-  Float64List asFloat64List([int offsetInBytes = 0, int length]) {
+  Float64List asFloat64List([int offsetInBytes = 0, int? length]) {
     return NativeFloat64List.view(this, offsetInBytes, length);
   }
 
-  Float32x4List asFloat32x4List([int offsetInBytes = 0, int length]) {
-    NativeFloat32List storage =
+  Float32x4List asFloat32x4List([int offsetInBytes = 0, int? length]) {
+    var storage =
         this.asFloat32List(offsetInBytes, length != null ? length * 4 : null);
     return NativeFloat32x4List._externalStorage(storage);
   }
 
-  Float64x2List asFloat64x2List([int offsetInBytes = 0, int length]) {
-    NativeFloat64List storage =
+  Float64x2List asFloat64x2List([int offsetInBytes = 0, int? length]) {
+    var storage =
         this.asFloat64List(offsetInBytes, length != null ? length * 2 : null);
     return NativeFloat64x2List._externalStorage(storage);
   }
 
-  ByteData asByteData([int offsetInBytes = 0, int length]) {
+  ByteData asByteData([int offsetInBytes = 0, int? length]) {
     return NativeByteData.view(this, offsetInBytes, length);
   }
 }
@@ -108,7 +108,7 @@
 class NativeFloat32x4List extends Object
     with ListMixin<Float32x4>, FixedLengthListMixin<Float32x4>
     implements Float32x4List {
-  final NativeFloat32List _storage;
+  final Float32List _storage;
 
   /**
    * Creates a [Float32x4List] of the specified length (in elements),
@@ -171,10 +171,10 @@
     _storage[(index * 4) + 3] = value.w;
   }
 
-  Float32x4List sublist(int start, [int end]) {
-    end = _checkValidRange(start, end, this.length);
+  Float32x4List sublist(int start, [int? end]) {
+    var stop = _checkValidRange(start, end, this.length);
     return NativeFloat32x4List._externalStorage(
-        _storage.sublist(start * 4, end * 4));
+        _storage.sublist(start * 4, stop * 4));
   }
 }
 
@@ -249,10 +249,10 @@
     _storage[(index * 4) + 3] = value.w;
   }
 
-  Int32x4List sublist(int start, [int end]) {
-    end = _checkValidRange(start, end, this.length);
+  Int32x4List sublist(int start, [int? end]) {
+    var stop = _checkValidRange(start, end, this.length);
     return NativeInt32x4List._externalStorage(
-        _storage.sublist(start * 4, end * 4));
+        _storage.sublist(start * 4, stop * 4));
   }
 }
 
@@ -264,7 +264,7 @@
 class NativeFloat64x2List extends Object
     with ListMixin<Float64x2>, FixedLengthListMixin<Float64x2>
     implements Float64x2List {
-  final NativeFloat64List _storage;
+  final Float64List _storage;
 
   /**
    * Creates a [Float64x2List] of the specified length (in elements),
@@ -321,10 +321,10 @@
     _storage[(index * 2) + 1] = value.y;
   }
 
-  Float64x2List sublist(int start, [int end]) {
-    end = _checkValidRange(start, end, this.length);
+  Float64x2List sublist(int start, [int? end]) {
+    var stop = _checkValidRange(start, end, this.length);
     return NativeFloat64x2List._externalStorage(
-        _storage.sublist(start * 2, end * 2));
+        _storage.sublist(start * 2, stop * 2));
   }
 }
 
@@ -393,7 +393,7 @@
   if (offsetInBytes is! int) {
     throw ArgumentError('Invalid view offsetInBytes $offsetInBytes');
   }
-  if (length != null && length is! int) {
+  if (length is! int?) {
     throw ArgumentError('Invalid view length $length');
   }
 }
@@ -430,7 +430,7 @@
    * the length of [buffer].
    */
   factory NativeByteData.view(
-      ByteBuffer buffer, int offsetInBytes, int length) {
+      ByteBuffer buffer, int offsetInBytes, int? length) {
     _checkViewArguments(buffer, offsetInBytes, length);
     return length == null
         ? _create2(buffer, offsetInBytes)
@@ -454,7 +454,7 @@
 
   @JSName('getFloat32')
   @Returns('double')
-  double _getFloat32(int byteOffset, [bool littleEndian]) native;
+  double _getFloat32(int byteOffset, [bool? littleEndian]) native;
 
   /**
    * Returns the floating point number represented by the eight bytes at
@@ -469,7 +469,7 @@
 
   @JSName('getFloat64')
   @Returns('double')
-  double _getFloat64(int byteOffset, [bool littleEndian]) native;
+  double _getFloat64(int byteOffset, [bool? littleEndian]) native;
 
   /**
    * Returns the (possibly negative) integer represented by the two bytes at
@@ -486,7 +486,7 @@
 
   @JSName('getInt16')
   @Returns('int')
-  int _getInt16(int byteOffset, [bool littleEndian]) native;
+  int _getInt16(int byteOffset, [bool? littleEndian]) native;
 
   /**
    * Returns the (possibly negative) integer represented by the four bytes at
@@ -503,7 +503,7 @@
 
   @JSName('getInt32')
   @Returns('int')
-  int _getInt32(int byteOffset, [bool littleEndian]) native;
+  int _getInt32(int byteOffset, [bool? littleEndian]) native;
 
   /**
    * Returns the (possibly negative) integer represented by the eight bytes at
@@ -543,7 +543,7 @@
 
   @JSName('getUint16')
   @Returns('int')
-  int _getUint16(int byteOffset, [bool littleEndian]) native;
+  int _getUint16(int byteOffset, [bool? littleEndian]) native;
 
   /**
    * Returns the positive integer represented by the four bytes starting
@@ -559,7 +559,7 @@
 
   @JSName('getUint32')
   @Returns('int')
-  int _getUint32(int byteOffset, [bool littleEndian]) native;
+  int _getUint32(int byteOffset, [bool? littleEndian]) native;
 
   /**
    * Returns the positive integer represented by the eight bytes starting
@@ -605,7 +605,7 @@
       _setFloat32(byteOffset, value, Endian.little == endian);
 
   @JSName('setFloat32')
-  void _setFloat32(int byteOffset, num value, [bool littleEndian]) native;
+  void _setFloat32(int byteOffset, num value, [bool? littleEndian]) native;
 
   /**
    * Sets the eight bytes starting at the specified [byteOffset] in this
@@ -619,7 +619,7 @@
       _setFloat64(byteOffset, value, Endian.little == endian);
 
   @JSName('setFloat64')
-  void _setFloat64(int byteOffset, num value, [bool littleEndian]) native;
+  void _setFloat64(int byteOffset, num value, [bool? littleEndian]) native;
 
   /**
    * Sets the two bytes starting at the specified [byteOffset] in this
@@ -634,7 +634,7 @@
       _setInt16(byteOffset, value, Endian.little == endian);
 
   @JSName('setInt16')
-  void _setInt16(int byteOffset, int value, [bool littleEndian]) native;
+  void _setInt16(int byteOffset, int value, [bool? littleEndian]) native;
 
   /**
    * Sets the four bytes starting at the specified [byteOffset] in this
@@ -649,7 +649,7 @@
       _setInt32(byteOffset, value, Endian.little == endian);
 
   @JSName('setInt32')
-  void _setInt32(int byteOffset, int value, [bool littleEndian]) native;
+  void _setInt32(int byteOffset, int value, [bool? littleEndian]) native;
 
   /**
    * Sets the eight bytes starting at the specified [byteOffset] in this
@@ -688,7 +688,7 @@
       _setUint16(byteOffset, value, Endian.little == endian);
 
   @JSName('setUint16')
-  void _setUint16(int byteOffset, int value, [bool littleEndian]) native;
+  void _setUint16(int byteOffset, int value, [bool? littleEndian]) native;
 
   /**
    * Sets the four bytes starting at the specified [byteOffset] in this object
@@ -703,7 +703,7 @@
       _setUint32(byteOffset, value, Endian.little == endian);
 
   @JSName('setUint32')
-  void _setUint32(int byteOffset, int value, [bool littleEndian]) native;
+  void _setUint32(int byteOffset, int value, [bool? littleEndian]) native;
 
   /**
    * Sets the eight bytes starting at the specified [byteOffset] in this object
@@ -822,7 +822,7 @@
       _create1(_ensureNativeList(elements));
 
   factory NativeFloat32List.view(
-      ByteBuffer buffer, int offsetInBytes, int length) {
+      ByteBuffer buffer, int offsetInBytes, int? length) {
     _checkViewArguments(buffer, offsetInBytes, length);
     return length == null
         ? _create2(buffer, offsetInBytes)
@@ -831,10 +831,10 @@
 
   Type get runtimeType => Float32List;
 
-  Float32List sublist(int start, [int end]) {
-    end = _checkValidRange(start, end, this.length);
+  Float32List sublist(int start, [int? end]) {
+    var stop = _checkValidRange(start, end, this.length);
     var source =
-        JS<NativeFloat32List>('!', '#.subarray(#, #)', this, start, end);
+        JS<NativeFloat32List>('!', '#.subarray(#, #)', this, start, stop);
     return _create1(source);
   }
 
@@ -857,7 +857,7 @@
       _create1(_ensureNativeList(elements));
 
   factory NativeFloat64List.view(
-      ByteBuffer buffer, int offsetInBytes, int length) {
+      ByteBuffer buffer, int offsetInBytes, int? length) {
     _checkViewArguments(buffer, offsetInBytes, length);
     return length == null
         ? _create2(buffer, offsetInBytes)
@@ -866,9 +866,9 @@
 
   Type get runtimeType => Float64List;
 
-  Float64List sublist(int start, [int end]) {
-    end = _checkValidRange(start, end, this.length);
-    var source = JS('NativeFloat64List', '#.subarray(#, #)', this, start, end);
+  Float64List sublist(int start, [int? end]) {
+    var stop = _checkValidRange(start, end, this.length);
+    var source = JS('NativeFloat64List', '#.subarray(#, #)', this, start, stop);
     return _create1(source);
   }
 
@@ -890,7 +890,7 @@
       _create1(_ensureNativeList(elements));
 
   factory NativeInt16List.view(
-      NativeByteBuffer buffer, int offsetInBytes, int length) {
+      NativeByteBuffer buffer, int offsetInBytes, int? length) {
     _checkViewArguments(buffer, offsetInBytes, length);
     return length == null
         ? _create2(buffer, offsetInBytes)
@@ -904,9 +904,9 @@
     return JS<int>('!', '#[#]', this, index);
   }
 
-  Int16List sublist(int start, [int end]) {
-    end = _checkValidRange(start, end, this.length);
-    var source = JS('NativeInt16List', '#.subarray(#, #)', this, start, end);
+  Int16List sublist(int start, [int? end]) {
+    var stop = _checkValidRange(start, end, this.length);
+    var source = JS('NativeInt16List', '#.subarray(#, #)', this, start, stop);
     return _create1(source);
   }
 
@@ -928,7 +928,7 @@
       _create1(_ensureNativeList(elements));
 
   factory NativeInt32List.view(
-      ByteBuffer buffer, int offsetInBytes, int length) {
+      ByteBuffer buffer, int offsetInBytes, int? length) {
     _checkViewArguments(buffer, offsetInBytes, length);
     return length == null
         ? _create2(buffer, offsetInBytes)
@@ -942,9 +942,10 @@
     return JS<int>('!', '#[#]', this, index);
   }
 
-  Int32List sublist(int start, [int end]) {
-    end = _checkValidRange(start, end, this.length);
-    var source = JS<NativeInt32List>('!', '#.subarray(#, #)', this, start, end);
+  Int32List sublist(int start, [int? end]) {
+    var stop = _checkValidRange(start, end, this.length);
+    var source =
+        JS<NativeInt32List>('!', '#.subarray(#, #)', this, start, stop);
     return _create1(source);
   }
 
@@ -966,7 +967,7 @@
       _create1(_ensureNativeList(elements));
 
   factory NativeInt8List.view(
-      ByteBuffer buffer, int offsetInBytes, int length) {
+      ByteBuffer buffer, int offsetInBytes, int? length) {
     _checkViewArguments(buffer, offsetInBytes, length);
     return length == null
         ? _create2(buffer, offsetInBytes)
@@ -980,9 +981,9 @@
     return JS<int>('!', '#[#]', this, index);
   }
 
-  Int8List sublist(int start, [int end]) {
-    end = _checkValidRange(start, end, this.length);
-    var source = JS<NativeInt8List>('!', '#.subarray(#, #)', this, start, end);
+  Int8List sublist(int start, [int? end]) {
+    var stop = _checkValidRange(start, end, this.length);
+    var source = JS<NativeInt8List>('!', '#.subarray(#, #)', this, start, stop);
     return _create1(source);
   }
 
@@ -992,7 +993,7 @@
   static NativeInt8List _create2(arg1, arg2) =>
       JS<NativeInt8List>('!', 'new Int8Array(#, #)', arg1, arg2);
 
-  static Int8List _create3(arg1, arg2, arg3) =>
+  static NativeInt8List _create3(arg1, arg2, arg3) =>
       JS<NativeInt8List>('!', 'new Int8Array(#, #, #)', arg1, arg2, arg3);
 }
 
@@ -1004,7 +1005,7 @@
       _create1(_ensureNativeList(list));
 
   factory NativeUint16List.view(
-      ByteBuffer buffer, int offsetInBytes, int length) {
+      ByteBuffer buffer, int offsetInBytes, int? length) {
     _checkViewArguments(buffer, offsetInBytes, length);
     return length == null
         ? _create2(buffer, offsetInBytes)
@@ -1018,10 +1019,10 @@
     return JS<int>('!', '#[#]', this, index);
   }
 
-  Uint16List sublist(int start, [int end]) {
-    end = _checkValidRange(start, end, this.length);
+  Uint16List sublist(int start, [int? end]) {
+    var stop = _checkValidRange(start, end, this.length);
     var source =
-        JS<NativeUint16List>('!', '#.subarray(#, #)', this, start, end);
+        JS<NativeUint16List>('!', '#.subarray(#, #)', this, start, stop);
     return _create1(source);
   }
 
@@ -1043,7 +1044,7 @@
       _create1(_ensureNativeList(elements));
 
   factory NativeUint32List.view(
-      ByteBuffer buffer, int offsetInBytes, int length) {
+      ByteBuffer buffer, int offsetInBytes, int? length) {
     _checkViewArguments(buffer, offsetInBytes, length);
     return length == null
         ? _create2(buffer, offsetInBytes)
@@ -1057,10 +1058,10 @@
     return JS<int>('!', '#[#]', this, index);
   }
 
-  Uint32List sublist(int start, [int end]) {
-    end = _checkValidRange(start, end, this.length);
+  Uint32List sublist(int start, [int? end]) {
+    var stop = _checkValidRange(start, end, this.length);
     var source =
-        JS<NativeUint32List>('!', '#.subarray(#, #)', this, start, end);
+        JS<NativeUint32List>('!', '#.subarray(#, #)', this, start, stop);
     return _create1(source);
   }
 
@@ -1083,7 +1084,7 @@
       _create1(_ensureNativeList(elements));
 
   factory NativeUint8ClampedList.view(
-      ByteBuffer buffer, int offsetInBytes, int length) {
+      ByteBuffer buffer, int offsetInBytes, int? length) {
     _checkViewArguments(buffer, offsetInBytes, length);
     return length == null
         ? _create2(buffer, offsetInBytes)
@@ -1099,10 +1100,10 @@
     return JS<int>('!', '#[#]', this, index);
   }
 
-  Uint8ClampedList sublist(int start, [int end]) {
-    end = _checkValidRange(start, end, this.length);
+  Uint8ClampedList sublist(int start, [int? end]) {
+    var stop = _checkValidRange(start, end, this.length);
     var source =
-        JS<NativeUint8ClampedList>('!', '#.subarray(#, #)', this, start, end);
+        JS<NativeUint8ClampedList>('!', '#.subarray(#, #)', this, start, stop);
     return _create1(source);
   }
 
@@ -1133,7 +1134,7 @@
       _create1(_ensureNativeList(elements));
 
   factory NativeUint8List.view(
-      ByteBuffer buffer, int offsetInBytes, int length) {
+      ByteBuffer buffer, int offsetInBytes, int? length) {
     _checkViewArguments(buffer, offsetInBytes, length);
     return length == null
         ? _create2(buffer, offsetInBytes)
@@ -1149,9 +1150,10 @@
     return JS<int>('!', '#[#]', this, index);
   }
 
-  Uint8List sublist(int start, [int end]) {
-    end = _checkValidRange(start, end, this.length);
-    var source = JS<NativeUint8List>('!', '#.subarray(#, #)', this, start, end);
+  Uint8List sublist(int start, [int? end]) {
+    var stop = _checkValidRange(start, end, this.length);
+    var source =
+        JS<NativeUint8List>('!', '#.subarray(#, #)', this, start, stop);
     return _create1(source);
   }
 
@@ -1541,7 +1543,7 @@
     floatList[1] = f.y;
     floatList[2] = f.z;
     floatList[3] = f.w;
-    NativeInt32List view = floatList.buffer.asInt32List();
+    Int32List view = floatList.buffer.asInt32List();
     return NativeInt32x4._truncated(view[0], view[1], view[2], view[3]);
   }
 
@@ -1759,7 +1761,7 @@
   final double y;
 
   static NativeFloat64List _list = NativeFloat64List(2);
-  static NativeUint32List _uint32View = _list.buffer.asUint32List();
+  static Uint32List _uint32View = _list.buffer.asUint32List();
 
   NativeFloat64x2(this.x, this.y) {
     if (x is! num) throw ArgumentError(x);
@@ -1890,7 +1892,7 @@
 ///
 /// Returns the actual value of `end`, which is `length` if `end` is `null`, and
 /// the original value of `end` otherwise.
-int _checkValidRange(int start, int end, int length) {
+int _checkValidRange(int start, int? end, int length) {
   if (_isInvalidArrayIndex(start) || // Ensures start is non-negative int.
       ((end == null)
           ? start > length
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/profile.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/profile.dart
index 8f3410b..d46f7f7 100644
--- a/sdk_nnbd/lib/_internal/js_dev_runtime/private/profile.dart
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/profile.dart
@@ -2,8 +2,6 @@
 // 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.5
-
 /// This file supports profiling dynamic calls.
 part of dart._debugger;
 
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/core_patch.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/core_patch.dart
index e31c549..ce924cd 100644
--- a/sdk_nnbd/lib/_internal/js_runtime/lib/core_patch.dart
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/core_patch.dart
@@ -857,6 +857,9 @@
 int _max(int a, int b) => a > b ? a : b;
 int _min(int a, int b) => a < b ? a : b;
 
+/// Empty list used as an initializer for local variables in the `_BigIntImpl`.
+final _dummyList = new Uint16List(0);
+
 // Copyright 2009 The Go Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
@@ -1455,8 +1458,7 @@
   ///
   /// Returns 0 if abs(this) == abs(other); a positive number if
   /// abs(this) > abs(other); and a negative number if abs(this) < abs(other).
-  int _absCompare(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  int _absCompare(_BigIntImpl other) {
     return _compareDigits(_digits, _used, other._digits, other._used);
   }
 
@@ -1464,8 +1466,7 @@
   ///
   /// Returns a negative number if `this` is less than `other`, zero if they are
   /// equal, and a positive number if `this` is greater than `other`.
-  int compareTo(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  int compareTo(covariant _BigIntImpl other) {
     if (_isNegative == other._isNegative) {
       var result = _absCompare(other);
       // Use 0 - result to avoid negative zero in JavaScript.
@@ -1607,7 +1608,8 @@
     var digits = _digits;
     var otherDigits = other._digits;
     var resultDigits = new Uint16List(resultUsed);
-    var l, m;
+    _BigIntImpl l;
+    int m;
     if (used < otherUsed) {
       l = other;
       m = used;
@@ -1633,7 +1635,8 @@
     var digits = _digits;
     var otherDigits = other._digits;
     var resultDigits = new Uint16List(resultUsed);
-    var l, m;
+    _BigIntImpl l;
+    int m;
     if (used < otherUsed) {
       l = other;
       m = used;
@@ -1659,8 +1662,7 @@
   ///
   /// Of both operands are negative, the result is negative, otherwise
   /// the result is non-negative.
-  _BigIntImpl operator &(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl operator &(covariant _BigIntImpl other) {
     if (_isZero || other._isZero) return zero;
     if (_isNegative == other._isNegative) {
       if (_isNegative) {
@@ -1675,7 +1677,7 @@
       return _absAndSetSign(other, false);
     }
     // _isNegative != other._isNegative
-    var p, n;
+    _BigIntImpl p, n;
     if (_isNegative) {
       p = other;
       n = this;
@@ -1697,8 +1699,7 @@
   ///
   /// If both operands are non-negative, the result is non-negative,
   /// otherwise the result us negative.
-  _BigIntImpl operator |(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl operator |(covariant _BigIntImpl other) {
     if (_isZero) return other;
     if (other._isZero) return this;
     if (_isNegative == other._isNegative) {
@@ -1714,7 +1715,7 @@
       return _absOrSetSign(other, false);
     }
     // _neg != a._neg
-    var p, n;
+    _BigIntImpl p, n;
     if (_isNegative) {
       p = other;
       n = this;
@@ -1737,8 +1738,7 @@
   ///
   /// If the operands have the same sign, the result is non-negative,
   /// otherwise the result is negative.
-  _BigIntImpl operator ^(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl operator ^(covariant _BigIntImpl other) {
     if (_isZero) return other;
     if (other._isZero) return this;
     if (_isNegative == other._isNegative) {
@@ -1751,7 +1751,7 @@
       return _absXorSetSign(other, false);
     }
     // _isNegative != a._isNegative
-    var p, n;
+    _BigIntImpl p, n;
     if (_isNegative) {
       p = other;
       n = this;
@@ -1784,8 +1784,7 @@
   }
 
   /// Addition operator.
-  _BigIntImpl operator +(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl operator +(covariant _BigIntImpl other) {
     if (_isZero) return other;
     if (other._isZero) return this;
     var isNegative = _isNegative;
@@ -1803,8 +1802,7 @@
   }
 
   /// Subtraction operator.
-  _BigIntImpl operator -(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl operator -(covariant _BigIntImpl other) {
     if (_isZero) return -other;
     if (other._isZero) return this;
     var isNegative = _isNegative;
@@ -1856,8 +1854,7 @@
   }
 
   /// Multiplication operator.
-  _BigIntImpl operator *(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl operator *(covariant _BigIntImpl other) {
     var used = _used;
     var otherUsed = other._used;
     if (used == 0 || otherUsed == 0) {
@@ -1905,8 +1902,7 @@
   }
 
   /// Returns `trunc(this / other)`, with `other != 0`.
-  _BigIntImpl _div(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl _div(_BigIntImpl other) {
     assert(other._used > 0);
     if (_used < other._used) {
       return zero;
@@ -1925,8 +1921,7 @@
   }
 
   /// Returns `this - other * trunc(this / other)`, with `other != 0`.
-  _BigIntImpl _rem(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl _rem(_BigIntImpl other) {
     assert(other._used > 0);
     if (_used < other._used) {
       return this;
@@ -2120,8 +2115,7 @@
   /// (-seven).remainder(three); // => -1
   /// seven.remainder(-three);   // => 1
   /// ```
-  _BigIntImpl operator ~/(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl operator ~/(covariant _BigIntImpl other) {
     if (other._used == 0) {
       throw const IntegerDivisionByZeroException();
     }
@@ -2134,8 +2128,7 @@
   /// `this == (this ~/ other) * other + r`.
   /// As a consequence the remainder `r` has the same sign as the divider
   /// `this`.
-  _BigIntImpl remainder(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl remainder(covariant _BigIntImpl other) {
     if (other._used == 0) {
       throw const IntegerDivisionByZeroException();
     }
@@ -2146,16 +2139,16 @@
   double operator /(BigInt other) => this.toDouble() / other.toDouble();
 
   /// Relational less than operator.
-  bool operator <(BigInt other) => compareTo(other) < 0;
+  bool operator <(covariant _BigIntImpl other) => compareTo(other) < 0;
 
   /// Relational less than or equal operator.
-  bool operator <=(BigInt other) => compareTo(other) <= 0;
+  bool operator <=(covariant _BigIntImpl other) => compareTo(other) <= 0;
 
   /// Relational greater than operator.
-  bool operator >(BigInt other) => compareTo(other) > 0;
+  bool operator >(covariant _BigIntImpl other) => compareTo(other) > 0;
 
   /// Relational greater than or equal operator.
-  bool operator >=(BigInt other) => compareTo(other) >= 0;
+  bool operator >=(covariant _BigIntImpl other) => compareTo(other) >= 0;
 
   /// Euclidean modulo operator.
   ///
@@ -2166,8 +2159,7 @@
   /// The sign of the returned value `r` is always positive.
   ///
   /// See [remainder] for the remainder of the truncating division.
-  _BigIntImpl operator %(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl operator %(covariant _BigIntImpl other) {
     if (other._used == 0) {
       throw const IntegerDivisionByZeroException();
     }
@@ -2226,9 +2218,8 @@
   ///
   /// The [exponent] must be non-negative and [modulus] must be
   /// positive.
-  _BigIntImpl modPow(BigInt bigExponent, BigInt bigModulus) {
-    _BigIntImpl exponent = bigExponent;
-    _BigIntImpl modulus = bigModulus;
+  _BigIntImpl modPow(
+      covariant _BigIntImpl exponent, covariant _BigIntImpl modulus) {
     if (exponent._isNegative) {
       throw new ArgumentError("exponent must be positive: $exponent");
     }
@@ -2252,7 +2243,7 @@
       resultDigits[j] = gDigits[j];
     }
     var resultUsed = gUsed;
-    var result2Used;
+    int result2Used;
     for (int i = exponentBitlen - 2; i >= 0; i--) {
       result2Used = z.sqr(resultDigits, resultUsed, result2Digits);
       if (!(exponent & (one << i))._isZero) {
@@ -2327,19 +2318,19 @@
     // Variables a, b, c, and d require one more digit.
     final abcdUsed = maxUsed + 1;
     final abcdLen = abcdUsed + 2; // +2 to satisfy _absAdd.
-    var aDigits, bDigits, cDigits, dDigits;
-    bool aIsNegative, bIsNegative, cIsNegative, dIsNegative;
+    var aDigits = _dummyList;
+    var aIsNegative = false;
+    var cDigits = _dummyList;
+    var cIsNegative = false;
     if (ac) {
       aDigits = new Uint16List(abcdLen);
-      aIsNegative = false;
       aDigits[0] = 1;
       cDigits = new Uint16List(abcdLen);
-      cIsNegative = false;
     }
-    bDigits = new Uint16List(abcdLen);
-    bIsNegative = false;
-    dDigits = new Uint16List(abcdLen);
-    dIsNegative = false;
+    var bDigits = new Uint16List(abcdLen);
+    var bIsNegative = false;
+    var dDigits = new Uint16List(abcdLen);
+    var dIsNegative = false;
     dDigits[0] = 1;
 
     while (true) {
@@ -2530,8 +2521,7 @@
   ///
   /// It is an error if no modular inverse exists.
   // Returns 1/this % modulus, with modulus > 0.
-  _BigIntImpl modInverse(BigInt bigInt) {
-    _BigIntImpl modulus = bigInt;
+  _BigIntImpl modInverse(covariant _BigIntImpl modulus) {
     if (modulus <= zero) {
       throw new ArgumentError("Modulus must be strictly positive: $modulus");
     }
@@ -2554,8 +2544,7 @@
   /// For any integer `x`, `x.gcd(x)` is `x.abs()`.
   ///
   /// If both `this` and `other` is zero, the result is also zero.
-  _BigIntImpl gcd(BigInt bigInt) {
-    _BigIntImpl other = bigInt;
+  _BigIntImpl gcd(covariant _BigIntImpl other) {
     if (_isZero) return other.abs();
     if (other._isZero) return this.abs();
     return _binaryGcd(this, other, false);
@@ -2865,8 +2854,8 @@
                 _modulus._digits[_modulus._used - 1].bitLength);
 
   int convert(_BigIntImpl x, Uint16List resultDigits) {
-    var digits;
-    var used;
+    Uint16List digits;
+    int used;
     if (x._isNegative || x._absCompare(_modulus) >= 0) {
       var remainder = x._rem(_modulus);
       if (x._isNegative && remainder._used > 0) {
diff --git a/sdk_nnbd/lib/async/async.dart b/sdk_nnbd/lib/async/async.dart
index 75d1c60..616375c 100644
--- a/sdk_nnbd/lib/async/async.dart
+++ b/sdk_nnbd/lib/async/async.dart
@@ -87,7 +87,7 @@
  * [asynchronous-programming]: https://www.dartlang.org/docs/dart-up-and-running/ch03.html#dartasync---asynchronous-programming
  * [futures-tutorial]: https://www.dartlang.org/docs/tutorials/futures/
  * [futures-error-handling]: https://www.dartlang.org/articles/futures-and-error-handling/
- * [test-readme]: https://pub.dartlang.org/packages/test
+ * [test-readme]: https://pub.dev/packages/test
  *
  * {@category Core}
  */
diff --git a/sdk_nnbd/lib/async/schedule_microtask.dart b/sdk_nnbd/lib/async/schedule_microtask.dart
index 95fca9e..940989c 100644
--- a/sdk_nnbd/lib/async/schedule_microtask.dart
+++ b/sdk_nnbd/lib/async/schedule_microtask.dart
@@ -132,7 +132,7 @@
  * Learn how Dart handles the event queue and microtask queue, so you can write
  * better asynchronous code with fewer surprises.
  */
-void scheduleMicrotask(void callback()) {
+void scheduleMicrotask(void Function() callback) {
   _Zone currentZone = Zone._current;
   if (identical(_rootZone, currentZone)) {
     // No need to bind the callback. We know that the root's scheduleMicrotask
@@ -152,5 +152,5 @@
 
 class _AsyncRun {
   /** Schedule the given callback before any other event in the event-loop. */
-  external static void _scheduleImmediate(void callback());
+  external static void _scheduleImmediate(void Function() callback);
 }
diff --git a/sdk_nnbd/lib/async/stream_impl.dart b/sdk_nnbd/lib/async/stream_impl.dart
index c5f331c..5011a82 100644
--- a/sdk_nnbd/lib/async/stream_impl.dart
+++ b/sdk_nnbd/lib/async/stream_impl.dart
@@ -426,7 +426,7 @@
    * during the call, and it checks for state changes after the call
    * that should cause further callbacks.
    */
-  void _guardCallback(void callback()) {
+  void _guardCallback(void Function() callback) {
     assert(!_inCallback);
     bool wasInputPaused = _isInputPaused;
     _state |= _STATE_IN_CALLBACK;
diff --git a/sdk_nnbd/lib/async/timer.dart b/sdk_nnbd/lib/async/timer.dart
index 97560a9..e0ef447 100644
--- a/sdk_nnbd/lib/async/timer.dart
+++ b/sdk_nnbd/lib/async/timer.dart
@@ -42,7 +42,7 @@
    * The [callback] function is invoked after the given [duration].
    *
    */
-  factory Timer(Duration duration, void callback()) {
+  factory Timer(Duration duration, void Function() callback) {
     if (Zone.current == Zone.root) {
       // No need to bind the callback. We know that the root's timer will
       // be invoked in the root zone.
@@ -85,7 +85,7 @@
    *
    * This function is equivalent to `new Timer(Duration.zero, callback)`.
    */
-  static void run(void callback()) {
+  static void run(void Function() callback) {
     new Timer(Duration.zero, callback);
   }
 
@@ -123,7 +123,8 @@
    */
   bool get isActive;
 
-  external static Timer _createTimer(Duration duration, void callback());
+  external static Timer _createTimer(
+      Duration duration, void Function() callback);
   external static Timer _createPeriodicTimer(
       Duration duration, void callback(Timer timer));
 }
diff --git a/sdk_nnbd/lib/async/zone.dart b/sdk_nnbd/lib/async/zone.dart
index 4e956a2..31644f2 100644
--- a/sdk_nnbd/lib/async/zone.dart
+++ b/sdk_nnbd/lib/async/zone.dart
@@ -546,7 +546,7 @@
    *     return () => this.runGuarded(registered);
    *
    */
-  void Function() bindCallbackGuarded(void callback());
+  void Function() bindCallbackGuarded(void Function() callback);
 
   /**
    * Registers the provided [callback] and returns a function that will
@@ -615,12 +615,12 @@
    * Custom zones may intercept this operation (for example to wrap the given
    * [callback]).
    */
-  void scheduleMicrotask(void callback());
+  void scheduleMicrotask(void Function() callback);
 
   /**
    * Creates a Timer where the callback is executed in this zone.
    */
-  Timer createTimer(Duration duration, void callback());
+  Timer createTimer(Duration duration, void Function() callback);
 
   /**
    * Creates a periodic Timer where the callback is executed in this zone.
@@ -1202,7 +1202,7 @@
 }
 
 Timer _rootCreateTimer(Zone self, ZoneDelegate parent, Zone zone,
-    Duration duration, void callback()) {
+    Duration duration, void Function() callback) {
   if (!identical(_rootZone, zone)) {
     callback = zone.bindCallback(callback);
   }
diff --git a/sdk_nnbd/lib/convert/json.dart b/sdk_nnbd/lib/convert/json.dart
index 1fafde7..7e08ccb 100644
--- a/sdk_nnbd/lib/convert/json.dart
+++ b/sdk_nnbd/lib/convert/json.dart
@@ -288,8 +288,6 @@
     if (other is Utf8Encoder) {
       // The instance check guarantees that `T` is (a subtype of) List<int>,
       // but the static type system doesn't know that, and so we cast.
-      // Cast through dynamic to keep the cast implicit for builds using
-      // unchecked implicit casts.
       return JsonUtf8Encoder(indent, _toEncodable) as Converter<Object?, T>;
     }
     return super.fuse<T>(other);
diff --git a/sdk_nnbd/lib/convert/string_conversion.dart b/sdk_nnbd/lib/convert/string_conversion.dart
index ea33dc5..1d5f038 100644
--- a/sdk_nnbd/lib/convert/string_conversion.dart
+++ b/sdk_nnbd/lib/convert/string_conversion.dart
@@ -79,11 +79,11 @@
     _sink.writeCharCode(charCode);
   }
 
-  void write(Object o) {
+  void write(Object? o) {
     _sink.write(o);
   }
 
-  void writeln([Object o = ""]) {
+  void writeln([Object? o = ""]) {
     _sink.writeln(o);
   }
 
diff --git a/sdk_nnbd/lib/core/date_time.dart b/sdk_nnbd/lib/core/date_time.dart
index 4f5f299..6788d1d 100644
--- a/sdk_nnbd/lib/core/date_time.dart
+++ b/sdk_nnbd/lib/core/date_time.dart
@@ -117,7 +117,7 @@
  *
  * The DateTime class does not provide internationalization.
  * To internationalize your code, use
- * the [intl](https://pub.dartlang.org/packages/intl) package.
+ * the [intl](https://pub.dev/packages/intl) package.
  *
  */
 class DateTime implements Comparable<DateTime> {
@@ -238,7 +238,8 @@
    *   The time part is a two digit hour,
    *   then optionally a two digit minutes value,
    *   then optionally a two digit seconds value, and
-   *   then optionally a '.' or ',' followed by a one-to-six digit second fraction.
+   *   then optionally a '.' or ',' followed by at least a one digit
+   *   second fraction.
    *   The minutes and seconds may be separated from the previous parts by a
    *   ':'.
    *   Examples: "12", "12:30:24.124", "12:30:24,124", "123010.50".
@@ -261,8 +262,8 @@
    * Examples of accepted strings:
    *
    * * `"2012-02-27 13:27:00"`
-   * * `"2012-02-27 13:27:00.123456z"`
-   * * `"2012-02-27 13:27:00,123456z"`
+   * * `"2012-02-27 13:27:00.123456789z"`
+   * * `"2012-02-27 13:27:00,123456789z"`
    * * `"20120227 13:27:00"`
    * * `"20120227T132700"`
    * * `"20120227"`
@@ -283,14 +284,13 @@
         return int.parse(matched);
       }
 
-      // Parses fractional second digits of '.(\d{1,6})' into the combined
-      // microseconds.
+      // Parses fractional second digits of '.(\d+)' into the combined
+      // microseconds. We only use the first 6 digits because of DateTime
+      // precision of 999 milliseconds and 999 microseconds.
       int parseMilliAndMicroseconds(String? matched) {
         if (matched == null) return 0;
         int length = matched.length;
         assert(length >= 1);
-        assert(length <= 6);
-
         int result = 0;
         for (int i = 0; i < 6; i++) {
           result *= 10;
@@ -557,7 +557,7 @@
    * The returned string is constructed for the time zone of this instance.
    * The `toString()` method provides a simply formatted string.
    * It does not support internationalized strings.
-   * Use the [intl](https://pub.dartlang.org/packages/intl) package
+   * Use the [intl](https://pub.dev/packages/intl) package
    * at the pub shared packages repo.
    *
    * The resulting string can be parsed back using [parse].
@@ -857,7 +857,7 @@
    * time_opt ::= <empty> | (' ' | 'T') hour minutes_opt
    * minutes_opt ::= <empty> | colon_opt digit{2} seconds_opt
    * seconds_opt ::= <empty> | colon_opt digit{2} millis_opt
-   * micros_opt ::= <empty> | ('.' | ',') digit{1,6}
+   * micros_opt ::= <empty> | ('.' | ',') digit+
    * timezone_opt ::= <empty> | space_opt timezone
    * space_opt :: ' ' | <empty>
    * timezone ::= 'z' | 'Z' | sign digit{2} timezonemins_opt
@@ -865,6 +865,6 @@
    */
   static final RegExp _parseFormat = RegExp(
       r'^([+-]?\d{4,6})-?(\d\d)-?(\d\d)' // Day part.
-      r'(?:[ T](\d\d)(?::?(\d\d)(?::?(\d\d)(?:[.,](\d{1,6}))?)?)?' // Time part.
+      r'(?:[ T](\d\d)(?::?(\d\d)(?::?(\d\d)(?:[.,](\d+))?)?)?' // Time part.
       r'( ?[zZ]| ?([-+])(\d\d)(?::?(\d\d))?)?)?$'); // Timezone part.
 }
diff --git a/sdk_nnbd/lib/core/num.dart b/sdk_nnbd/lib/core/num.dart
index 7b45da6..f63dc68 100644
--- a/sdk_nnbd/lib/core/num.dart
+++ b/sdk_nnbd/lib/core/num.dart
@@ -42,7 +42,7 @@
    * Use [compareTo] for a comparison that distinguishes zero and minus zero,
    * and that considers NaN values as equal.
    */
-  bool operator ==(Object? other);
+  bool operator ==(Object other);
 
   /**
    * Returns a hash code for a numerical value.
diff --git a/sdk_nnbd/lib/core/print.dart b/sdk_nnbd/lib/core/print.dart
index c45336c..d88ea7f 100644
--- a/sdk_nnbd/lib/core/print.dart
+++ b/sdk_nnbd/lib/core/print.dart
@@ -7,9 +7,10 @@
 /// Prints a string representation of the object to the console.
 void print(Object? object) {
   String line = object.toString();
-  if (printToZone == null) {
+  var toZone = printToZone;
+  if (toZone == null) {
     printToConsole(line);
   } else {
-    printToZone(line);
+    toZone(line);
   }
 }
diff --git a/sdk_nnbd/lib/internal/internal.dart b/sdk_nnbd/lib/internal/internal.dart
index 11ee996..1a92f98 100644
--- a/sdk_nnbd/lib/internal/internal.dart
+++ b/sdk_nnbd/lib/internal/internal.dart
@@ -16,7 +16,7 @@
         Zone;
 import 'dart:convert' show Converter;
 import 'dart:core' hide Symbol;
-import 'dart:core' as core;
+import 'dart:core' as core show Symbol;
 import 'dart:math' show Random;
 
 part 'async_cast.dart';
diff --git a/sdk_nnbd/lib/internal/iterable.dart b/sdk_nnbd/lib/internal/iterable.dart
index 3865626..394dcaa 100644
--- a/sdk_nnbd/lib/internal/iterable.dart
+++ b/sdk_nnbd/lib/internal/iterable.dart
@@ -768,7 +768,7 @@
 }
 
 class FollowedByIterable<E> extends Iterable<E> {
-  final EfficientLengthIterable<E> _first;
+  final Iterable<E> _first;
   final Iterable<E> _second;
   FollowedByIterable(this._first, this._second);
 
@@ -854,13 +854,13 @@
 }
 
 class WhereTypeIterable<T> extends Iterable<T> {
-  final Iterable<Object> _source;
+  final Iterable<Object?> _source;
   WhereTypeIterable(this._source);
   Iterator<T> get iterator => new WhereTypeIterator<T>(_source.iterator);
 }
 
 class WhereTypeIterator<T> implements Iterator<T> {
-  final Iterator<Object> _source;
+  final Iterator<Object?> _source;
   WhereTypeIterator(this._source);
   bool moveNext() {
     while (_source.moveNext()) {
diff --git a/sdk_nnbd/lib/io/io.dart b/sdk_nnbd/lib/io/io.dart
index 64a1f78..2207d9b 100644
--- a/sdk_nnbd/lib/io/io.dart
+++ b/sdk_nnbd/lib/io/io.dart
@@ -67,7 +67,7 @@
  * The [HttpServer] class provides the basic functionality for
  * implementing an HTTP server.
  * For some higher-level building-blocks, we recommend that you try
- * the [shelf](https://pub.dartlang.org/packages/shelf)
+ * the [shelf](https://pub.dev/packages/shelf)
  * pub package, which contains
  * a set of high-level classes that, together with the [HttpServer] class
  * in this library, make it easier to implement HTTP servers.
diff --git a/sdk_nnbd/lib/libraries.json b/sdk_nnbd/lib/libraries.json
index 95aa4205..49d5373 100644
--- a/sdk_nnbd/lib/libraries.json
+++ b/sdk_nnbd/lib/libraries.json
@@ -4,151 +4,151 @@
   "vm": {
     "libraries": {
       "_builtin": {
-        "uri": "_internal/vm/bin/builtin.dart"
+        "uri": "../../sdk/lib/_internal/vm/bin/builtin.dart"
       },
       "cli": {
         "patches": [
-          "_internal/vm/bin/cli_patch.dart"
+          "../../sdk/lib/_internal/vm/bin/cli_patch.dart"
         ],
-        "uri": "cli/cli.dart"
+        "uri": "../../sdk/lib/cli/cli.dart"
       },
       "core": {
         "patches": [
-          "_internal/vm/lib/core_patch.dart",
-          "_internal/vm/lib/array.dart",
-          "_internal/vm/lib/array_patch.dart",
-          "_internal/vm/lib/bigint_patch.dart",
-          "_internal/vm/lib/bool_patch.dart",
-          "_internal/vm/lib/date_patch.dart",
-          "_internal/vm/lib/double.dart",
-          "_internal/vm/lib/double_patch.dart",
-          "_internal/vm/lib/errors_patch.dart",
-          "_internal/vm/lib/expando_patch.dart",
-          "_internal/vm/lib/function.dart",
-          "_internal/vm/lib/function_patch.dart",
-          "_internal/vm/lib/growable_array.dart",
-          "_internal/vm/lib/identical_patch.dart",
-          "_internal/vm/lib/immutable_map.dart",
-          "_internal/vm/lib/integers.dart",
-          "_internal/vm/lib/integers_patch.dart",
-          "_internal/vm/lib/invocation_mirror_patch.dart",
-          "_internal/vm/lib/lib_prefix.dart",
-          "_internal/vm/lib/map_patch.dart",
-          "_internal/vm/lib/null_patch.dart",
-          "_internal/vm/lib/object_patch.dart",
-          "_internal/vm/lib/regexp_patch.dart",
-          "_internal/vm/lib/stacktrace.dart",
-          "_internal/vm/lib/stopwatch_patch.dart",
-          "_internal/vm/lib/string_buffer_patch.dart",
-          "_internal/vm/lib/string_patch.dart",
-          "_internal/vm/lib/type_patch.dart",
-          "_internal/vm/lib/uri_patch.dart",
-          "_internal/vm/lib/weak_property.dart"
+          "../../sdk/lib/_internal/vm/lib/core_patch.dart",
+          "../../sdk/lib/_internal/vm/lib/array.dart",
+          "../../sdk/lib/_internal/vm/lib/array_patch.dart",
+          "../../sdk/lib/_internal/vm/lib/bigint_patch.dart",
+          "../../sdk/lib/_internal/vm/lib/bool_patch.dart",
+          "../../sdk/lib/_internal/vm/lib/date_patch.dart",
+          "../../sdk/lib/_internal/vm/lib/double.dart",
+          "../../sdk/lib/_internal/vm/lib/double_patch.dart",
+          "../../sdk/lib/_internal/vm/lib/errors_patch.dart",
+          "../../sdk/lib/_internal/vm/lib/expando_patch.dart",
+          "../../sdk/lib/_internal/vm/lib/function.dart",
+          "../../sdk/lib/_internal/vm/lib/function_patch.dart",
+          "../../sdk/lib/_internal/vm/lib/growable_array.dart",
+          "../../sdk/lib/_internal/vm/lib/identical_patch.dart",
+          "../../sdk/lib/_internal/vm/lib/immutable_map.dart",
+          "../../sdk/lib/_internal/vm/lib/integers.dart",
+          "../../sdk/lib/_internal/vm/lib/integers_patch.dart",
+          "../../sdk/lib/_internal/vm/lib/invocation_mirror_patch.dart",
+          "../../sdk/lib/_internal/vm/lib/lib_prefix.dart",
+          "../../sdk/lib/_internal/vm/lib/map_patch.dart",
+          "../../sdk/lib/_internal/vm/lib/null_patch.dart",
+          "../../sdk/lib/_internal/vm/lib/object_patch.dart",
+          "../../sdk/lib/_internal/vm/lib/regexp_patch.dart",
+          "../../sdk/lib/_internal/vm/lib/stacktrace.dart",
+          "../../sdk/lib/_internal/vm/lib/stopwatch_patch.dart",
+          "../../sdk/lib/_internal/vm/lib/string_buffer_patch.dart",
+          "../../sdk/lib/_internal/vm/lib/string_patch.dart",
+          "../../sdk/lib/_internal/vm/lib/type_patch.dart",
+          "../../sdk/lib/_internal/vm/lib/uri_patch.dart",
+          "../../sdk/lib/_internal/vm/lib/weak_property.dart"
         ],
-        "uri": "core/core.dart"
+        "uri": "../../sdk/lib/core/core.dart"
       },
       "async": {
         "patches": [
-          "_internal/vm/lib/async_patch.dart",
-          "_internal/vm/lib/deferred_load_patch.dart",
-          "_internal/vm/lib/schedule_microtask_patch.dart",
-          "_internal/vm/lib/timer_patch.dart"
+          "../../sdk/lib/_internal/vm/lib/async_patch.dart",
+          "../../sdk/lib/_internal/vm/lib/deferred_load_patch.dart",
+          "../../sdk/lib/_internal/vm/lib/schedule_microtask_patch.dart",
+          "../../sdk/lib/_internal/vm/lib/timer_patch.dart"
         ],
-        "uri": "async/async.dart"
+        "uri": "../../sdk/lib/async/async.dart"
       },
       "collection": {
         "patches": [
-          "_internal/vm/lib/collection_patch.dart",
-          "_internal/vm/lib/compact_hash.dart"
+          "../../sdk/lib/_internal/vm/lib/collection_patch.dart",
+          "../../sdk/lib/_internal/vm/lib/compact_hash.dart"
         ],
-        "uri": "collection/collection.dart"
+        "uri": "../../sdk/lib/collection/collection.dart"
       },
       "ffi": {
         "patches": [
-          "_internal/vm/lib/ffi_patch.dart",
-          "_internal/vm/lib/ffi_dynamic_library_patch.dart",
-          "_internal/vm/lib/ffi_native_type_patch.dart"
+          "../../sdk/lib/_internal/vm/lib/ffi_patch.dart",
+          "../../sdk/lib/_internal/vm/lib/ffi_dynamic_library_patch.dart",
+          "../../sdk/lib/_internal/vm/lib/ffi_native_type_patch.dart"
         ],
-        "uri": "ffi/ffi.dart"
+        "uri": "../../sdk/lib/ffi/ffi.dart"
       },
       "typed_data": {
-        "patches": "_internal/vm/lib/typed_data_patch.dart",
-        "uri": "typed_data/typed_data.dart"
+        "patches": "../../sdk/lib/_internal/vm/lib/typed_data_patch.dart",
+        "uri": "../../sdk/lib/typed_data/typed_data.dart"
       },
       "nativewrappers": {
-        "uri": "html/dartium/nativewrappers.dart"
+        "uri": "../../sdk/lib/html/dartium/nativewrappers.dart"
       },
       "mirrors": {
         "patches": [
-          "_internal/vm/lib/mirrors_patch.dart",
-          "_internal/vm/lib/mirrors_impl.dart",
-          "_internal/vm/lib/mirror_reference.dart"
+          "../../sdk/lib/_internal/vm/lib/mirrors_patch.dart",
+          "../../sdk/lib/_internal/vm/lib/mirrors_impl.dart",
+          "../../sdk/lib/_internal/vm/lib/mirror_reference.dart"
         ],
-        "uri": "mirrors/mirrors.dart"
+        "uri": "../../sdk/lib/mirrors/mirrors.dart"
       },
       "developer": {
         "patches": [
-          "_internal/vm/lib/developer.dart",
-          "_internal/vm/lib/profiler.dart",
-          "_internal/vm/lib/timeline.dart"
+          "../../sdk/lib/_internal/vm/lib/developer.dart",
+          "../../sdk/lib/_internal/vm/lib/profiler.dart",
+          "../../sdk/lib/_internal/vm/lib/timeline.dart"
         ],
-        "uri": "developer/developer.dart"
+        "uri": "../../sdk/lib/developer/developer.dart"
       },
       "isolate": {
         "patches": [
-          "_internal/vm/lib/isolate_patch.dart",
-          "_internal/vm/lib/timer_impl.dart"
+          "../../sdk/lib/_internal/vm/lib/isolate_patch.dart",
+          "../../sdk/lib/_internal/vm/lib/timer_impl.dart"
         ],
-        "uri": "isolate/isolate.dart"
+        "uri": "../../sdk/lib/isolate/isolate.dart"
       },
       "_vmservice": {
-        "uri": "vmservice/vmservice.dart"
+        "uri": "../../sdk/lib/vmservice/vmservice.dart"
       },
       "wasm": {
         "patches": [
-          "_internal/vm/lib/wasm_patch.dart"
+          "../../sdk/lib/_internal/vm/lib/wasm_patch.dart"
         ],
-        "uri": "wasm/wasm.dart"
+        "uri": "../../sdk/lib/wasm/wasm.dart"
       },
       "io": {
         "patches": [
-          "_internal/vm/bin/common_patch.dart",
-          "_internal/vm/bin/directory_patch.dart",
-          "_internal/vm/bin/eventhandler_patch.dart",
-          "_internal/vm/bin/file_patch.dart",
-          "_internal/vm/bin/file_system_entity_patch.dart",
-          "_internal/vm/bin/filter_patch.dart",
-          "_internal/vm/bin/io_service_patch.dart",
-          "_internal/vm/bin/namespace_patch.dart",
-          "_internal/vm/bin/platform_patch.dart",
-          "_internal/vm/bin/process_patch.dart",
-          "_internal/vm/bin/socket_patch.dart",
-          "_internal/vm/bin/stdio_patch.dart",
-          "_internal/vm/bin/secure_socket_patch.dart",
-          "_internal/vm/bin/sync_socket_patch.dart"
+          "../../sdk/lib/_internal/vm/bin/common_patch.dart",
+          "../../sdk/lib/_internal/vm/bin/directory_patch.dart",
+          "../../sdk/lib/_internal/vm/bin/eventhandler_patch.dart",
+          "../../sdk/lib/_internal/vm/bin/file_patch.dart",
+          "../../sdk/lib/_internal/vm/bin/file_system_entity_patch.dart",
+          "../../sdk/lib/_internal/vm/bin/filter_patch.dart",
+          "../../sdk/lib/_internal/vm/bin/io_service_patch.dart",
+          "../../sdk/lib/_internal/vm/bin/namespace_patch.dart",
+          "../../sdk/lib/_internal/vm/bin/platform_patch.dart",
+          "../../sdk/lib/_internal/vm/bin/process_patch.dart",
+          "../../sdk/lib/_internal/vm/bin/socket_patch.dart",
+          "../../sdk/lib/_internal/vm/bin/stdio_patch.dart",
+          "../../sdk/lib/_internal/vm/bin/secure_socket_patch.dart",
+          "../../sdk/lib/_internal/vm/bin/sync_socket_patch.dart"
         ],
-        "uri": "io/io.dart"
+        "uri": "../../sdk/lib/io/io.dart"
       },
       "_internal": {
         "patches": [
-          "_internal/vm/lib/internal_patch.dart",
-          "_internal/vm/lib/class_id_fasta.dart",
-          "_internal/vm/lib/print_patch.dart",
-          "_internal/vm/lib/symbol_patch.dart",
-          "internal/patch.dart"
+          "../../sdk/lib/_internal/vm/lib/internal_patch.dart",
+          "../../sdk/lib/_internal/vm/lib/class_id_fasta.dart",
+          "../../sdk/lib/_internal/vm/lib/print_patch.dart",
+          "../../sdk/lib/_internal/vm/lib/symbol_patch.dart",
+          "../../sdk/lib/internal/patch.dart"
         ],
-        "uri": "internal/internal.dart"
+        "uri": "../../sdk/lib/internal/internal.dart"
       },
       "convert": {
-        "patches": "_internal/vm/lib/convert_patch.dart",
-        "uri": "convert/convert.dart"
+        "patches": "../../sdk/lib/_internal/vm/lib/convert_patch.dart",
+        "uri": "../../sdk/lib/convert/convert.dart"
       },
       "math": {
-        "patches": "_internal/vm/lib/math_patch.dart",
-        "uri": "math/math.dart"
+        "patches": "../../sdk/lib/_internal/vm/lib/math_patch.dart",
+        "uri": "../../sdk/lib/math/math.dart"
       },
       "_http": {
-        "uri": "_http/http.dart"
+        "uri": "../../sdk/lib/_http/http.dart"
       },
       "vmservice_io": {
         "uri": "../../runtime/bin/vmservice/vmservice_io.dart"
@@ -161,323 +161,323 @@
   "dart2js": {
     "libraries": {
       "async": {
-        "patches": "_internal/js_runtime/lib/async_patch.dart",
-        "uri": "async/async.dart"
+        "patches": "../../sdk/lib/_internal/js_runtime/lib/async_patch.dart",
+        "uri": "../../sdk/lib/async/async.dart"
       },
       "_interceptors": {
-        "uri": "_internal/js_runtime/lib/interceptors.dart"
+        "uri": "../../sdk/lib/_internal/js_runtime/lib/interceptors.dart"
       },
       "mirrors": {
-        "patches": "_internal/js_runtime/lib/mirrors_patch_cfe.dart",
+        "patches": "../../sdk/lib/_internal/js_runtime/lib/mirrors_patch_cfe.dart",
         "supported": false,
-        "uri": "mirrors/mirrors.dart"
+        "uri": "../../sdk/lib/mirrors/mirrors.dart"
       },
       "_js_embedded_names": {
-        "uri": "_internal/js_runtime/lib/shared/embedded_names.dart"
+        "uri": "../../sdk/lib/_internal/js_runtime/lib/shared/embedded_names.dart"
       },
       "io": {
-        "patches": "_internal/js_runtime/lib/io_patch.dart",
+        "patches": "../../sdk/lib/_internal/js_runtime/lib/io_patch.dart",
         "supported": false,
-        "uri": "io/io.dart"
+        "uri": "../../sdk/lib/io/io.dart"
       },
       "_internal": {
-        "patches": "_internal/js_runtime/lib/internal_patch.dart",
-        "uri": "internal/internal.dart"
+        "patches": "../../sdk/lib/_internal/js_runtime/lib/internal_patch.dart",
+        "uri": "../../sdk/lib/internal/internal.dart"
       },
       "_metadata": {
-        "uri": "html/html_common/metadata.dart"
+        "uri": "../../sdk/lib/html/html_common/metadata.dart"
       },
       "_async_await_error_codes": {
-        "uri": "_internal/js_runtime/lib/shared/async_await_error_codes.dart"
+        "uri": "../../sdk/lib/_internal/js_runtime/lib/shared/async_await_error_codes.dart"
       },
       "_http": {
-        "uri": "_http/http.dart"
+        "uri": "../../sdk/lib/_http/http.dart"
       },
       "_js_primitives": {
-        "uri": "_internal/js_runtime/lib/js_primitives.dart"
+        "uri": "../../sdk/lib/_internal/js_runtime/lib/js_primitives.dart"
       },
       "_js_helper": {
-        "uri": "_internal/js_runtime/lib/js_helper.dart"
+        "uri": "../../sdk/lib/_internal/js_runtime/lib/js_helper.dart"
       },
       "js": {
-        "uri": "js/dart2js/js_dart2js.dart"
+        "uri": "../../sdk/lib/js/dart2js/js_dart2js.dart"
       },
       "html_common": {
-        "uri": "html/html_common/html_common_dart2js.dart"
+        "uri": "../../sdk/lib/html/html_common/html_common_dart2js.dart"
       },
       "_recipe_syntax": {
-        "uri": "_internal/js_runtime/lib/shared/recipe_syntax.dart"
+        "uri": "../../sdk/lib/_internal/js_runtime/lib/shared/recipe_syntax.dart"
       },
       "_native_typed_data": {
-        "uri": "_internal/js_runtime/lib/native_typed_data.dart"
+        "uri": "../../sdk/lib/_internal/js_runtime/lib/native_typed_data.dart"
       },
       "_js_names": {
-        "uri": "_internal/js_runtime/lib/js_names.dart"
+        "uri": "../../sdk/lib/_internal/js_runtime/lib/js_names.dart"
       },
       "core": {
-        "patches": "_internal/js_runtime/lib/core_patch.dart",
-        "uri": "core/core.dart"
+        "patches": "../../sdk/lib/_internal/js_runtime/lib/core_patch.dart",
+        "uri": "../../sdk/lib/core/core.dart"
       },
       "collection": {
-        "patches": "_internal/js_runtime/lib/collection_patch.dart",
-        "uri": "collection/collection.dart"
+        "patches": "../../sdk/lib/_internal/js_runtime/lib/collection_patch.dart",
+        "uri": "../../sdk/lib/collection/collection.dart"
       },
       "js_util": {
-        "uri": "js_util/dart2js/js_util_dart2js.dart"
+        "uri": "../../sdk/lib/js_util/dart2js/js_util_dart2js.dart"
       },
       "typed_data": {
-        "patches": "_internal/js_runtime/lib/typed_data_patch.dart",
-        "uri": "typed_data/typed_data.dart"
+        "patches": "../../sdk/lib/_internal/js_runtime/lib/typed_data_patch.dart",
+        "uri": "../../sdk/lib/typed_data/typed_data.dart"
       },
       "web_audio": {
-        "uri": "web_audio/dart2js/web_audio_dart2js.dart"
+        "uri": "../../sdk/lib/web_audio/dart2js/web_audio_dart2js.dart"
       },
       "html": {
-        "uri": "html/dart2js/html_dart2js.dart"
+        "uri": "../../sdk/lib/html/dart2js/html_dart2js.dart"
       },
       "isolate": {
-        "patches": "_internal/js_runtime/lib/isolate_patch.dart",
+        "patches": "../../sdk/lib/_internal/js_runtime/lib/isolate_patch.dart",
         "supported": false,
-        "uri": "isolate/isolate.dart"
+        "uri": "../../sdk/lib/isolate/isolate.dart"
       },
       "developer": {
-        "patches": "_internal/js_runtime/lib/developer_patch.dart",
-        "uri": "developer/developer.dart"
+        "patches": "../../sdk/lib/_internal/js_runtime/lib/developer_patch.dart",
+        "uri": "../../sdk/lib/developer/developer.dart"
       },
       "web_gl": {
-        "uri": "web_gl/dart2js/web_gl_dart2js.dart"
+        "uri": "../../sdk/lib/web_gl/dart2js/web_gl_dart2js.dart"
       },
       "indexed_db": {
-        "uri": "indexed_db/dart2js/indexed_db_dart2js.dart"
+        "uri": "../../sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart"
       },
       "_js": {
-        "patches": "js/_js_client.dart",
-        "uri": "js/_js.dart"
+        "patches": "../../sdk/lib/js/_js_client.dart",
+        "uri": "../../sdk/lib/js/_js.dart"
       },
       "convert": {
-        "patches": "_internal/js_runtime/lib/convert_patch.dart",
-        "uri": "convert/convert.dart"
+        "patches": "../../sdk/lib/_internal/js_runtime/lib/convert_patch.dart",
+        "uri": "../../sdk/lib/convert/convert.dart"
       },
       "math": {
-        "patches": "_internal/js_runtime/lib/math_patch.dart",
-        "uri": "math/math.dart"
+        "patches": "../../sdk/lib/_internal/js_runtime/lib/math_patch.dart",
+        "uri": "../../sdk/lib/math/math.dart"
       },
       "_foreign_helper": {
-        "uri": "_internal/js_runtime/lib/foreign_helper.dart"
+        "uri": "../../sdk/lib/_internal/js_runtime/lib/foreign_helper.dart"
       },
       "web_sql": {
-        "uri": "web_sql/dart2js/web_sql_dart2js.dart"
+        "uri": "../../sdk/lib/web_sql/dart2js/web_sql_dart2js.dart"
       },
       "_rti": {
-        "uri": "_internal/js_runtime/lib/rti.dart"
+        "uri": "../../sdk/lib/_internal/js_runtime/lib/rti.dart"
       },
       "svg": {
-        "uri": "svg/dart2js/svg_dart2js.dart"
+        "uri": "../../sdk/lib/svg/dart2js/svg_dart2js.dart"
       }
     }
   },
   "dartdevc": {
     "libraries": {
       "async": {
-        "patches": "_internal/js_dev_runtime/patch/async_patch.dart",
-        "uri": "async/async.dart"
+        "patches": "../../sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart",
+        "uri": "../../sdk/lib/async/async.dart"
       },
       "_runtime": {
         "uri": "_internal/js_dev_runtime/private/ddc_runtime/runtime.dart"
       },
       "_interceptors": {
-        "uri": "_internal/js_dev_runtime/private/interceptors.dart"
+        "uri": "../../sdk/lib/_internal/js_dev_runtime/private/interceptors.dart"
       },
       "mirrors": {
-        "patches": "_internal/js_dev_runtime/patch/mirrors_patch.dart",
+        "patches": "../../sdk/lib/_internal/js_dev_runtime/patch/mirrors_patch.dart",
         "supported": false,
-        "uri": "mirrors/mirrors.dart"
+        "uri": "../../sdk/lib/mirrors/mirrors.dart"
       },
       "_debugger": {
-        "uri": "_internal/js_dev_runtime/private/debugger.dart"
+        "uri": "../../sdk/lib/_internal/js_dev_runtime/private/debugger.dart"
       },
       "io": {
-        "patches": "_internal/js_dev_runtime/patch/io_patch.dart",
+        "patches": "../../sdk/lib/_internal/js_dev_runtime/patch/io_patch.dart",
         "supported": false,
-        "uri": "io/io.dart"
+        "uri": "../../sdk/lib/io/io.dart"
       },
       "_internal": {
-        "patches": "_internal/js_dev_runtime/patch/internal_patch.dart",
-        "uri": "internal/internal.dart"
+        "patches": "../../sdk/lib/_internal/js_dev_runtime/patch/internal_patch.dart",
+        "uri": "../../sdk/lib/internal/internal.dart"
       },
       "_metadata": {
-        "uri": "html/html_common/metadata.dart"
+        "uri": "../../sdk/lib/html/html_common/metadata.dart"
       },
       "_http": {
-        "uri": "_http/http.dart"
+        "uri": "../../sdk/lib/_http/http.dart"
       },
       "_js_primitives": {
-        "uri": "_internal/js_dev_runtime/private/js_primitives.dart"
+        "uri": "../../sdk/lib/_internal/js_dev_runtime/private/js_primitives.dart"
       },
       "_js_helper": {
-        "uri": "_internal/js_dev_runtime/private/js_helper.dart"
+        "uri": "../../sdk/lib/_internal/js_dev_runtime/private/js_helper.dart"
       },
       "js": {
-        "uri": "_internal/js_dev_runtime/lib/js/dart2js/js_dart2js.dart"
+        "uri": "../../sdk/lib/_internal/js_dev_runtime/lib/js/dart2js/js_dart2js.dart"
       },
       "_js_mirrors": {
-        "uri": "_internal/js_dev_runtime/private/js_mirrors.dart"
+        "uri": "../../sdk/lib/_internal/js_dev_runtime/private/js_mirrors.dart"
       },
       "html_common": {
-        "uri": "html/html_common/html_common_dart2js.dart"
+        "uri": "../../sdk/lib/html/html_common/html_common_dart2js.dart"
       },
       "_native_typed_data": {
-        "uri": "_internal/js_dev_runtime/private/native_typed_data.dart"
+        "uri": "../../sdk/lib/_internal/js_dev_runtime/private/native_typed_data.dart"
       },
       "core": {
-        "patches": "_internal/js_dev_runtime/patch/core_patch.dart",
-        "uri": "core/core.dart"
+        "patches": "../../sdk/lib/_internal/js_dev_runtime/patch/core_patch.dart",
+        "uri": "../../sdk/lib/core/core.dart"
       },
       "js_util": {
-        "uri": "_internal/js_dev_runtime/lib/js_util/dart2js/js_util_dart2js.dart"
+        "uri": "../../sdk/lib/_internal/js_dev_runtime/lib/js_util/dart2js/js_util_dart2js.dart"
       },
       "collection": {
-        "patches": "_internal/js_dev_runtime/patch/collection_patch.dart",
-        "uri": "collection/collection.dart"
+        "patches": "../../sdk/lib/_internal/js_dev_runtime/patch/collection_patch.dart",
+        "uri": "../../sdk/lib/collection/collection.dart"
       },
       "typed_data": {
-        "patches": "_internal/js_dev_runtime/patch/typed_data_patch.dart",
-        "uri": "typed_data/typed_data.dart"
+        "patches": "../../sdk/lib/_internal/js_dev_runtime/patch/typed_data_patch.dart",
+        "uri": "../../sdk/lib/typed_data/typed_data.dart"
       },
       "web_audio": {
-        "uri": "web_audio/dart2js/web_audio_dart2js.dart"
+        "uri": "../../sdk/lib/web_audio/dart2js/web_audio_dart2js.dart"
       },
       "html": {
-        "uri": "html/dart2js/html_dart2js.dart"
+        "uri": "../../sdk/lib/html/dart2js/html_dart2js.dart"
       },
       "developer": {
-        "patches": "_internal/js_dev_runtime/patch/developer_patch.dart",
-        "uri": "developer/developer.dart"
+        "patches": "../../sdk/lib/_internal/js_dev_runtime/patch/developer_patch.dart",
+        "uri": "../../sdk/lib/developer/developer.dart"
       },
       "isolate": {
-        "patches": "_internal/js_dev_runtime/patch/isolate_patch.dart",
+        "patches": "../../sdk/lib/_internal/js_dev_runtime/patch/isolate_patch.dart",
         "supported": false,
-        "uri": "isolate/isolate.dart"
+        "uri": "../../sdk/lib/isolate/isolate.dart"
       },
       "web_gl": {
-        "uri": "web_gl/dart2js/web_gl_dart2js.dart"
+        "uri": "../../sdk/lib/web_gl/dart2js/web_gl_dart2js.dart"
       },
       "indexed_db": {
-        "uri": "indexed_db/dart2js/indexed_db_dart2js.dart"
+        "uri": "../../sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart"
       },
       "convert": {
-        "patches": "_internal/js_dev_runtime/patch/convert_patch.dart",
-        "uri": "convert/convert.dart"
+        "patches": "../../sdk/lib/_internal/js_dev_runtime/patch/convert_patch.dart",
+        "uri": "../../sdk/lib/convert/convert.dart"
       },
       "_isolate_helper": {
-        "uri": "_internal/js_dev_runtime/private/isolate_helper.dart"
+        "uri": "../../sdk/lib/_internal/js_dev_runtime/private/isolate_helper.dart"
       },
       "math": {
-        "patches": "_internal/js_dev_runtime/patch/math_patch.dart",
-        "uri": "math/math.dart"
+        "patches": "../../sdk/lib/_internal/js_dev_runtime/patch/math_patch.dart",
+        "uri": "../../sdk/lib/math/math.dart"
       },
       "_foreign_helper": {
-        "uri": "_internal/js_dev_runtime/private/foreign_helper.dart"
+        "uri": "../../sdk/lib/_internal/js_dev_runtime/private/foreign_helper.dart"
       },
       "web_sql": {
-        "uri": "web_sql/dart2js/web_sql_dart2js.dart"
+        "uri": "../../sdk/lib/web_sql/dart2js/web_sql_dart2js.dart"
       },
       "svg": {
-        "uri": "svg/dart2js/svg_dart2js.dart"
+        "uri": "../../sdk/lib/svg/dart2js/svg_dart2js.dart"
       }
     }
   },
   "dart2js_server": {
     "libraries": {
       "async": {
-        "patches": "_internal/js_runtime/lib/async_patch.dart",
-        "uri": "async/async.dart"
+        "patches": "../../sdk/lib/_internal/js_runtime/lib/async_patch.dart",
+        "uri": "../../sdk/lib/async/async.dart"
       },
       "mirrors": {
-        "patches": "_internal/js_runtime/lib/mirrors_patch_cfe.dart",
+        "patches": "../../sdk/lib/_internal/js_runtime/lib/mirrors_patch_cfe.dart",
         "supported": false,
-        "uri": "mirrors/mirrors.dart"
+        "uri": "../../sdk/lib/mirrors/mirrors.dart"
       },
       "_interceptors": {
-        "uri": "_internal/js_runtime/lib/interceptors.dart"
+        "uri": "../../sdk/lib/_internal/js_runtime/lib/interceptors.dart"
       },
       "_js_embedded_names": {
-        "uri": "_internal/js_runtime/lib/shared/embedded_names.dart"
+        "uri": "../../sdk/lib/_internal/js_runtime/lib/shared/embedded_names.dart"
       },
       "io": {
-        "patches": "_internal/js_runtime/lib/io_patch.dart",
+        "patches": "../../sdk/lib/_internal/js_runtime/lib/io_patch.dart",
         "supported": false,
-        "uri": "io/io.dart"
+        "uri": "../../sdk/lib/io/io.dart"
       },
       "_internal": {
-        "patches": "_internal/js_runtime/lib/internal_patch.dart",
-        "uri": "internal/internal.dart"
+        "patches": "../../sdk/lib/_internal/js_runtime/lib/internal_patch.dart",
+        "uri": "../../sdk/lib/internal/internal.dart"
       },
       "_async_await_error_codes": {
-        "uri": "_internal/js_runtime/lib/shared/async_await_error_codes.dart"
+        "uri": "../../sdk/lib/_internal/js_runtime/lib/shared/async_await_error_codes.dart"
       },
       "_http": {
-        "uri": "_http/http.dart"
+        "uri": "../../sdk/lib/_http/http.dart"
       },
       "_js_helper": {
-        "uri": "_internal/js_runtime/lib/js_helper.dart"
+        "uri": "../../sdk/lib/_internal/js_runtime/lib/js_helper.dart"
       },
       "_js_primitives": {
-        "uri": "_internal/js_runtime/lib/js_primitives.dart"
+        "uri": "../../sdk/lib/_internal/js_runtime/lib/js_primitives.dart"
       },
       "js": {
-        "uri": "js/dart2js/js_dart2js.dart"
+        "uri": "../../sdk/lib/js/dart2js/js_dart2js.dart"
       },
       "_recipe_syntax": {
-        "uri": "_internal/js_runtime/lib/shared/recipe_syntax.dart"
+        "uri": "../../sdk/lib/_internal/js_runtime/lib/shared/recipe_syntax.dart"
       },
       "_native_typed_data": {
-        "uri": "_internal/js_runtime/lib/native_typed_data.dart"
+        "uri": "../../sdk/lib/_internal/js_runtime/lib/native_typed_data.dart"
       },
       "core": {
-        "patches": "_internal/js_runtime/lib/core_patch.dart",
-        "uri": "core/core.dart"
+        "patches": "../../sdk/lib/_internal/js_runtime/lib/core_patch.dart",
+        "uri": "../../sdk/lib/core/core.dart"
       },
       "_js_names": {
-        "uri": "_internal/js_runtime/lib/js_names.dart"
+        "uri": "../../sdk/lib/_internal/js_runtime/lib/js_names.dart"
       },
       "js_util": {
-        "uri": "js_util/dart2js/js_util_dart2js.dart"
+        "uri": "../../sdk/lib/js_util/dart2js/js_util_dart2js.dart"
       },
       "collection": {
-        "patches": "_internal/js_runtime/lib/collection_patch.dart",
-        "uri": "collection/collection.dart"
+        "patches": "../../sdk/lib/_internal/js_runtime/lib/collection_patch.dart",
+        "uri": "../../sdk/lib/collection/collection.dart"
       },
       "typed_data": {
-        "patches": "_internal/js_runtime/lib/typed_data_patch.dart",
-        "uri": "typed_data/typed_data.dart"
+        "patches": "../../sdk/lib/_internal/js_runtime/lib/typed_data_patch.dart",
+        "uri": "../../sdk/lib/typed_data/typed_data.dart"
       },
       "isolate": {
-        "patches": "_internal/js_runtime/lib/isolate_patch.dart",
+        "patches": "../../sdk/lib/_internal/js_runtime/lib/isolate_patch.dart",
         "supported": false,
-        "uri": "isolate/isolate.dart"
+        "uri": "../../sdk/lib/isolate/isolate.dart"
       },
       "developer": {
-        "patches": "_internal/js_runtime/lib/developer_patch.dart",
-        "uri": "developer/developer.dart"
+        "patches": "../../sdk/lib/_internal/js_runtime/lib/developer_patch.dart",
+        "uri": "../../sdk/lib/developer/developer.dart"
       },
       "_js": {
-        "patches": "js/_js_server.dart",
-        "uri": "js/_js.dart"
+        "patches": "../../sdk/lib/js/_js_server.dart",
+        "uri": "../../sdk/lib/js/_js.dart"
       },
       "convert": {
-        "patches": "_internal/js_runtime/lib/convert_patch.dart",
-        "uri": "convert/convert.dart"
+        "patches": "../../sdk/lib/_internal/js_runtime/lib/convert_patch.dart",
+        "uri": "../../sdk/lib/convert/convert.dart"
       },
       "math": {
-        "patches": "_internal/js_runtime/lib/math_patch.dart",
-        "uri": "math/math.dart"
+        "patches": "../../sdk/lib/_internal/js_runtime/lib/math_patch.dart",
+        "uri": "../../sdk/lib/math/math.dart"
       },
       "_foreign_helper": {
-        "uri": "_internal/js_runtime/lib/foreign_helper.dart"
+        "uri": "../../sdk/lib/_internal/js_runtime/lib/foreign_helper.dart"
       },
       "_rti": {
-        "uri": "_internal/js_runtime/lib/rti.dart"
+        "uri": "../../sdk/lib/_internal/js_runtime/lib/rti.dart"
       }
     }
   }
diff --git a/sdk_nnbd/lib/libraries.yaml b/sdk_nnbd/lib/libraries.yaml
index 31a800e..ce07502 100644
--- a/sdk_nnbd/lib/libraries.yaml
+++ b/sdk_nnbd/lib/libraries.yaml
@@ -17,140 +17,140 @@
 vm:
   libraries:
     _builtin:
-      uri: "_internal/vm/bin/builtin.dart"
+      uri: "../../sdk/lib/_internal/vm/bin/builtin.dart"
 
     _internal:
-      uri: "internal/internal.dart"
+      uri: "../../sdk/lib/internal/internal.dart"
       patches:
-        - "_internal/vm/lib/internal_patch.dart"
-        - "_internal/vm/lib/class_id_fasta.dart"
-        - "_internal/vm/lib/print_patch.dart"
-        - "_internal/vm/lib/symbol_patch.dart"
-        - "internal/patch.dart"
+        - "../../sdk/lib/_internal/vm/lib/internal_patch.dart"
+        - "../../sdk/lib/_internal/vm/lib/class_id_fasta.dart"
+        - "../../sdk/lib/_internal/vm/lib/print_patch.dart"
+        - "../../sdk/lib/_internal/vm/lib/symbol_patch.dart"
+        - "../../sdk/lib/internal/patch.dart"
 
     async:
-      uri: "async/async.dart"
+      uri: "../../sdk/lib/async/async.dart"
       patches:
-        - "_internal/vm/lib/async_patch.dart"
-        - "_internal/vm/lib/deferred_load_patch.dart"
-        - "_internal/vm/lib/schedule_microtask_patch.dart"
-        - "_internal/vm/lib/timer_patch.dart"
+        - "../../sdk/lib/_internal/vm/lib/async_patch.dart"
+        - "../../sdk/lib/_internal/vm/lib/deferred_load_patch.dart"
+        - "../../sdk/lib/_internal/vm/lib/schedule_microtask_patch.dart"
+        - "../../sdk/lib/_internal/vm/lib/timer_patch.dart"
 
     collection:
-      uri: "collection/collection.dart"
+      uri: "../../sdk/lib/collection/collection.dart"
       patches:
-        - "_internal/vm/lib/collection_patch.dart"
-        - "_internal/vm/lib/compact_hash.dart"
+        - "../../sdk/lib/_internal/vm/lib/collection_patch.dart"
+        - "../../sdk/lib/_internal/vm/lib/compact_hash.dart"
 
     convert:
-      uri: "convert/convert.dart"
-      patches: "_internal/vm/lib/convert_patch.dart"
+      uri: "../../sdk/lib/convert/convert.dart"
+      patches: "../../sdk/lib/_internal/vm/lib/convert_patch.dart"
 
     core:
-      uri: "core/core.dart"
+      uri: "../../sdk/lib/core/core.dart"
       patches:
-        - "_internal/vm/lib/core_patch.dart"
-        - "_internal/vm/lib/array.dart"
-        - "_internal/vm/lib/array_patch.dart"
-        - "_internal/vm/lib/bigint_patch.dart"
-        - "_internal/vm/lib/bool_patch.dart"
-        - "_internal/vm/lib/date_patch.dart"
-        - "_internal/vm/lib/double.dart"
-        - "_internal/vm/lib/double_patch.dart"
-        - "_internal/vm/lib/errors_patch.dart"
-        - "_internal/vm/lib/expando_patch.dart"
-        - "_internal/vm/lib/function.dart"
-        - "_internal/vm/lib/function_patch.dart"
-        - "_internal/vm/lib/growable_array.dart"
-        - "_internal/vm/lib/identical_patch.dart"
-        - "_internal/vm/lib/immutable_map.dart"
-        - "_internal/vm/lib/integers.dart"
-        - "_internal/vm/lib/integers_patch.dart"
-        - "_internal/vm/lib/invocation_mirror_patch.dart"
-        - "_internal/vm/lib/lib_prefix.dart"
-        - "_internal/vm/lib/map_patch.dart"
-        - "_internal/vm/lib/null_patch.dart"
-        - "_internal/vm/lib/object_patch.dart"
-        - "_internal/vm/lib/regexp_patch.dart"
-        - "_internal/vm/lib/stacktrace.dart"
-        - "_internal/vm/lib/stopwatch_patch.dart"
-        - "_internal/vm/lib/string_buffer_patch.dart"
-        - "_internal/vm/lib/string_patch.dart"
-        - "_internal/vm/lib/type_patch.dart"
-        - "_internal/vm/lib/uri_patch.dart"
-        - "_internal/vm/lib/weak_property.dart"
+        - "../../sdk/lib/_internal/vm/lib/core_patch.dart"
+        - "../../sdk/lib/_internal/vm/lib/array.dart"
+        - "../../sdk/lib/_internal/vm/lib/array_patch.dart"
+        - "../../sdk/lib/_internal/vm/lib/bigint_patch.dart"
+        - "../../sdk/lib/_internal/vm/lib/bool_patch.dart"
+        - "../../sdk/lib/_internal/vm/lib/date_patch.dart"
+        - "../../sdk/lib/_internal/vm/lib/double.dart"
+        - "../../sdk/lib/_internal/vm/lib/double_patch.dart"
+        - "../../sdk/lib/_internal/vm/lib/errors_patch.dart"
+        - "../../sdk/lib/_internal/vm/lib/expando_patch.dart"
+        - "../../sdk/lib/_internal/vm/lib/function.dart"
+        - "../../sdk/lib/_internal/vm/lib/function_patch.dart"
+        - "../../sdk/lib/_internal/vm/lib/growable_array.dart"
+        - "../../sdk/lib/_internal/vm/lib/identical_patch.dart"
+        - "../../sdk/lib/_internal/vm/lib/immutable_map.dart"
+        - "../../sdk/lib/_internal/vm/lib/integers.dart"
+        - "../../sdk/lib/_internal/vm/lib/integers_patch.dart"
+        - "../../sdk/lib/_internal/vm/lib/invocation_mirror_patch.dart"
+        - "../../sdk/lib/_internal/vm/lib/lib_prefix.dart"
+        - "../../sdk/lib/_internal/vm/lib/map_patch.dart"
+        - "../../sdk/lib/_internal/vm/lib/null_patch.dart"
+        - "../../sdk/lib/_internal/vm/lib/object_patch.dart"
+        - "../../sdk/lib/_internal/vm/lib/regexp_patch.dart"
+        - "../../sdk/lib/_internal/vm/lib/stacktrace.dart"
+        - "../../sdk/lib/_internal/vm/lib/stopwatch_patch.dart"
+        - "../../sdk/lib/_internal/vm/lib/string_buffer_patch.dart"
+        - "../../sdk/lib/_internal/vm/lib/string_patch.dart"
+        - "../../sdk/lib/_internal/vm/lib/type_patch.dart"
+        - "../../sdk/lib/_internal/vm/lib/uri_patch.dart"
+        - "../../sdk/lib/_internal/vm/lib/weak_property.dart"
 
     developer:
-      uri: "developer/developer.dart"
+      uri: "../../sdk/lib/developer/developer.dart"
       patches:
-        - "_internal/vm/lib/developer.dart"
-        - "_internal/vm/lib/profiler.dart"
-        - "_internal/vm/lib/timeline.dart"
+        - "../../sdk/lib/_internal/vm/lib/developer.dart"
+        - "../../sdk/lib/_internal/vm/lib/profiler.dart"
+        - "../../sdk/lib/_internal/vm/lib/timeline.dart"
 
     ffi:
-      uri: "ffi/ffi.dart"
+      uri: "../../sdk/lib/ffi/ffi.dart"
       patches:
-        - "_internal/vm/lib/ffi_patch.dart"
-        - "_internal/vm/lib/ffi_dynamic_library_patch.dart"
-        - "_internal/vm/lib/ffi_native_type_patch.dart"
+        - "../../sdk/lib/_internal/vm/lib/ffi_patch.dart"
+        - "../../sdk/lib/_internal/vm/lib/ffi_dynamic_library_patch.dart"
+        - "../../sdk/lib/_internal/vm/lib/ffi_native_type_patch.dart"
 
     wasm:
-      uri: "wasm/wasm.dart"
+      uri: "../../sdk/lib/wasm/wasm.dart"
       patches:
-        - "_internal/vm/lib/wasm_patch.dart"
+        - "../../sdk/lib/_internal/vm/lib/wasm_patch.dart"
 
     _http:
-      uri: "_http/http.dart"
+      uri: "../../sdk/lib/_http/http.dart"
 
     io:
-      uri: "io/io.dart"
+      uri: "../../sdk/lib/io/io.dart"
       patches:
-        - "_internal/vm/bin/common_patch.dart"
-        - "_internal/vm/bin/directory_patch.dart"
-        - "_internal/vm/bin/eventhandler_patch.dart"
-        - "_internal/vm/bin/file_patch.dart"
-        - "_internal/vm/bin/file_system_entity_patch.dart"
-        - "_internal/vm/bin/filter_patch.dart"
-        - "_internal/vm/bin/io_service_patch.dart"
-        - "_internal/vm/bin/namespace_patch.dart"
-        - "_internal/vm/bin/platform_patch.dart"
-        - "_internal/vm/bin/process_patch.dart"
-        - "_internal/vm/bin/socket_patch.dart"
-        - "_internal/vm/bin/stdio_patch.dart"
-        - "_internal/vm/bin/secure_socket_patch.dart"
-        - "_internal/vm/bin/sync_socket_patch.dart"
+        - "../../sdk/lib/_internal/vm/bin/common_patch.dart"
+        - "../../sdk/lib/_internal/vm/bin/directory_patch.dart"
+        - "../../sdk/lib/_internal/vm/bin/eventhandler_patch.dart"
+        - "../../sdk/lib/_internal/vm/bin/file_patch.dart"
+        - "../../sdk/lib/_internal/vm/bin/file_system_entity_patch.dart"
+        - "../../sdk/lib/_internal/vm/bin/filter_patch.dart"
+        - "../../sdk/lib/_internal/vm/bin/io_service_patch.dart"
+        - "../../sdk/lib/_internal/vm/bin/namespace_patch.dart"
+        - "../../sdk/lib/_internal/vm/bin/platform_patch.dart"
+        - "../../sdk/lib/_internal/vm/bin/process_patch.dart"
+        - "../../sdk/lib/_internal/vm/bin/socket_patch.dart"
+        - "../../sdk/lib/_internal/vm/bin/stdio_patch.dart"
+        - "../../sdk/lib/_internal/vm/bin/secure_socket_patch.dart"
+        - "../../sdk/lib/_internal/vm/bin/sync_socket_patch.dart"
 
     isolate:
-      uri: "isolate/isolate.dart"
+      uri: "../../sdk/lib/isolate/isolate.dart"
       patches:
-        - "_internal/vm/lib/isolate_patch.dart"
-        - "_internal/vm/lib/timer_impl.dart"
+        - "../../sdk/lib/_internal/vm/lib/isolate_patch.dart"
+        - "../../sdk/lib/_internal/vm/lib/timer_impl.dart"
 
     math:
-      uri: "math/math.dart"
-      patches: "_internal/vm/lib/math_patch.dart"
+      uri: "../../sdk/lib/math/math.dart"
+      patches: "../../sdk/lib/_internal/vm/lib/math_patch.dart"
 
     mirrors:
-      uri: "mirrors/mirrors.dart"
+      uri: "../../sdk/lib/mirrors/mirrors.dart"
       patches:
-        - "_internal/vm/lib/mirrors_patch.dart"
-        - "_internal/vm/lib/mirrors_impl.dart"
-        - "_internal/vm/lib/mirror_reference.dart"
+        - "../../sdk/lib/_internal/vm/lib/mirrors_patch.dart"
+        - "../../sdk/lib/_internal/vm/lib/mirrors_impl.dart"
+        - "../../sdk/lib/_internal/vm/lib/mirror_reference.dart"
 
     nativewrappers:
-      uri: "html/dartium/nativewrappers.dart"
+      uri: "../../sdk/lib/html/dartium/nativewrappers.dart"
 
     cli:
-      uri: "cli/cli.dart"
+      uri: "../../sdk/lib/cli/cli.dart"
       patches:
-        - "_internal/vm/bin/cli_patch.dart"
+        - "../../sdk/lib/_internal/vm/bin/cli_patch.dart"
 
     typed_data:
-      uri: "typed_data/typed_data.dart"
-      patches: "_internal/vm/lib/typed_data_patch.dart"
+      uri: "../../sdk/lib/typed_data/typed_data.dart"
+      patches: "../../sdk/lib/_internal/vm/lib/typed_data_patch.dart"
 
     _vmservice:
-      uri: "vmservice/vmservice.dart"
+      uri: "../../sdk/lib/vmservice/vmservice.dart"
 
     vmservice_io:
       uri: "../../runtime/bin/vmservice/vmservice_io.dart"
@@ -158,210 +158,210 @@
 dart2js:
   libraries:
     async:
-      uri: "async/async.dart"
-      patches: "_internal/js_runtime/lib/async_patch.dart"
+      uri: "../../sdk/lib/async/async.dart"
+      patches: "../../sdk/lib/_internal/js_runtime/lib/async_patch.dart"
 
     collection:
-      uri: "collection/collection.dart"
-      patches: "_internal/js_runtime/lib/collection_patch.dart"
+      uri: "../../sdk/lib/collection/collection.dart"
+      patches: "../../sdk/lib/_internal/js_runtime/lib/collection_patch.dart"
 
     convert:
-      uri: "convert/convert.dart"
-      patches: "_internal/js_runtime/lib/convert_patch.dart"
+      uri: "../../sdk/lib/convert/convert.dart"
+      patches: "../../sdk/lib/_internal/js_runtime/lib/convert_patch.dart"
 
     core:
-      uri: "core/core.dart"
-      patches: "_internal/js_runtime/lib/core_patch.dart"
+      uri: "../../sdk/lib/core/core.dart"
+      patches: "../../sdk/lib/_internal/js_runtime/lib/core_patch.dart"
 
     developer:
-      uri: "developer/developer.dart"
-      patches: "_internal/js_runtime/lib/developer_patch.dart"
+      uri: "../../sdk/lib/developer/developer.dart"
+      patches: "../../sdk/lib/_internal/js_runtime/lib/developer_patch.dart"
 
     html:
-      uri: "html/dart2js/html_dart2js.dart"
+      uri: "../../sdk/lib/html/dart2js/html_dart2js.dart"
 
     html_common:
-      uri: "html/html_common/html_common_dart2js.dart"
+      uri: "../../sdk/lib/html/html_common/html_common_dart2js.dart"
 
     indexed_db:
-      uri: "indexed_db/dart2js/indexed_db_dart2js.dart"
+      uri: "../../sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart"
 
     _http:
-      uri: "_http/http.dart"
+      uri: "../../sdk/lib/_http/http.dart"
 
     io:
-      uri: "io/io.dart"
-      patches: "_internal/js_runtime/lib/io_patch.dart"
+      uri: "../../sdk/lib/io/io.dart"
+      patches: "../../sdk/lib/_internal/js_runtime/lib/io_patch.dart"
       supported: false
 
     isolate:
-      uri: "isolate/isolate.dart"
-      patches: "_internal/js_runtime/lib/isolate_patch.dart"
+      uri: "../../sdk/lib/isolate/isolate.dart"
+      patches: "../../sdk/lib/_internal/js_runtime/lib/isolate_patch.dart"
       supported: false
 
     js:
-      uri: "js/dart2js/js_dart2js.dart"
+      uri: "../../sdk/lib/js/dart2js/js_dart2js.dart"
 
     _js:
-      uri: "js/_js.dart"
-      patches: "js/_js_client.dart"
+      uri: "../../sdk/lib/js/_js.dart"
+      patches: "../../sdk/lib/js/_js_client.dart"
 
     js_util:
-      uri: "js_util/dart2js/js_util_dart2js.dart"
+      uri: "../../sdk/lib/js_util/dart2js/js_util_dart2js.dart"
 
     math:
-      uri: "math/math.dart"
-      patches: "_internal/js_runtime/lib/math_patch.dart"
+      uri: "../../sdk/lib/math/math.dart"
+      patches: "../../sdk/lib/_internal/js_runtime/lib/math_patch.dart"
 
     mirrors:
-      uri: "mirrors/mirrors.dart"
-      patches: "_internal/js_runtime/lib/mirrors_patch_cfe.dart"
+      uri: "../../sdk/lib/mirrors/mirrors.dart"
+      patches: "../../sdk/lib/_internal/js_runtime/lib/mirrors_patch_cfe.dart"
       supported: false
 
     typed_data:
-      uri: "typed_data/typed_data.dart"
-      patches: "_internal/js_runtime/lib/typed_data_patch.dart"
+      uri: "../../sdk/lib/typed_data/typed_data.dart"
+      patches: "../../sdk/lib/_internal/js_runtime/lib/typed_data_patch.dart"
 
     _native_typed_data:
-      uri: "_internal/js_runtime/lib/native_typed_data.dart"
+      uri: "../../sdk/lib/_internal/js_runtime/lib/native_typed_data.dart"
 
     svg:
-      uri: "svg/dart2js/svg_dart2js.dart"
+      uri: "../../sdk/lib/svg/dart2js/svg_dart2js.dart"
 
     web_audio:
-      uri: "web_audio/dart2js/web_audio_dart2js.dart"
+      uri: "../../sdk/lib/web_audio/dart2js/web_audio_dart2js.dart"
 
     web_gl:
-      uri: "web_gl/dart2js/web_gl_dart2js.dart"
+      uri: "../../sdk/lib/web_gl/dart2js/web_gl_dart2js.dart"
 
     web_sql:
-      uri: "web_sql/dart2js/web_sql_dart2js.dart"
+      uri: "../../sdk/lib/web_sql/dart2js/web_sql_dart2js.dart"
 
     _internal:
-      uri: "internal/internal.dart"
-      patches: "_internal/js_runtime/lib/internal_patch.dart"
+      uri: "../../sdk/lib/internal/internal.dart"
+      patches: "../../sdk/lib/_internal/js_runtime/lib/internal_patch.dart"
 
     _js_helper:
-      uri: "_internal/js_runtime/lib/js_helper.dart"
+      uri: "../../sdk/lib/_internal/js_runtime/lib/js_helper.dart"
 
     _rti:
-      uri: "_internal/js_runtime/lib/rti.dart"
+      uri: "../../sdk/lib/_internal/js_runtime/lib/rti.dart"
 
     _interceptors:
-      uri: "_internal/js_runtime/lib/interceptors.dart"
+      uri: "../../sdk/lib/_internal/js_runtime/lib/interceptors.dart"
 
     _foreign_helper:
-      uri: "_internal/js_runtime/lib/foreign_helper.dart"
+      uri: "../../sdk/lib/_internal/js_runtime/lib/foreign_helper.dart"
 
     _js_names:
-      uri: "_internal/js_runtime/lib/js_names.dart"
+      uri: "../../sdk/lib/_internal/js_runtime/lib/js_names.dart"
 
     _js_primitives:
-      uri: "_internal/js_runtime/lib/js_primitives.dart"
+      uri: "../../sdk/lib/_internal/js_runtime/lib/js_primitives.dart"
 
     _js_embedded_names:
-      uri: "_internal/js_runtime/lib/shared/embedded_names.dart"
+      uri: "../../sdk/lib/_internal/js_runtime/lib/shared/embedded_names.dart"
 
     _async_await_error_codes:
-      uri: "_internal/js_runtime/lib/shared/async_await_error_codes.dart"
+      uri: "../../sdk/lib/_internal/js_runtime/lib/shared/async_await_error_codes.dart"
 
     _recipe_syntax:
-      uri: "_internal/js_runtime/lib/shared/recipe_syntax.dart"
+      uri: "../../sdk/lib/_internal/js_runtime/lib/shared/recipe_syntax.dart"
 
     _metadata:
-      uri: "html/html_common/metadata.dart"
+      uri: "../../sdk/lib/html/html_common/metadata.dart"
 
 dart2js_server:
   libraries:
     async:
-      uri: "async/async.dart"
-      patches: "_internal/js_runtime/lib/async_patch.dart"
+      uri: "../../sdk/lib/async/async.dart"
+      patches: "../../sdk/lib/_internal/js_runtime/lib/async_patch.dart"
 
     collection:
-      uri: "collection/collection.dart"
-      patches: "_internal/js_runtime/lib/collection_patch.dart"
+      uri: "../../sdk/lib/collection/collection.dart"
+      patches: "../../sdk/lib/_internal/js_runtime/lib/collection_patch.dart"
 
     convert:
-      uri: "convert/convert.dart"
-      patches: "_internal/js_runtime/lib/convert_patch.dart"
+      uri: "../../sdk/lib/convert/convert.dart"
+      patches: "../../sdk/lib/_internal/js_runtime/lib/convert_patch.dart"
 
     core:
-      uri: "core/core.dart"
-      patches: "_internal/js_runtime/lib/core_patch.dart"
+      uri: "../../sdk/lib/core/core.dart"
+      patches: "../../sdk/lib/_internal/js_runtime/lib/core_patch.dart"
 
     developer:
-      uri: "developer/developer.dart"
-      patches: "_internal/js_runtime/lib/developer_patch.dart"
+      uri: "../../sdk/lib/developer/developer.dart"
+      patches: "../../sdk/lib/_internal/js_runtime/lib/developer_patch.dart"
 
     _http:
-      uri: "_http/http.dart"
+      uri: "../../sdk/lib/_http/http.dart"
 
     io:
-      uri: "io/io.dart"
-      patches: "_internal/js_runtime/lib/io_patch.dart"
+      uri: "../../sdk/lib/io/io.dart"
+      patches: "../../sdk/lib/_internal/js_runtime/lib/io_patch.dart"
       supported: false
 
     isolate:
-      uri: "isolate/isolate.dart"
-      patches: "_internal/js_runtime/lib/isolate_patch.dart"
+      uri: "../../sdk/lib/isolate/isolate.dart"
+      patches: "../../sdk/lib/_internal/js_runtime/lib/isolate_patch.dart"
       supported: false
 
     js:
-      uri: "js/dart2js/js_dart2js.dart"
+      uri: "../../sdk/lib/js/dart2js/js_dart2js.dart"
 
     _js:
-      uri: "js/_js.dart"
-      patches: "js/_js_server.dart"
+      uri: "../../sdk/lib/js/_js.dart"
+      patches: "../../sdk/lib/js/_js_server.dart"
 
     js_util:
-      uri: "js_util/dart2js/js_util_dart2js.dart"
+      uri: "../../sdk/lib/js_util/dart2js/js_util_dart2js.dart"
 
     math:
-      uri: "math/math.dart"
-      patches: "_internal/js_runtime/lib/math_patch.dart"
+      uri: "../../sdk/lib/math/math.dart"
+      patches: "../../sdk/lib/_internal/js_runtime/lib/math_patch.dart"
 
     mirrors:
-      uri: "mirrors/mirrors.dart"
-      patches: "_internal/js_runtime/lib/mirrors_patch_cfe.dart"
+      uri: "../../sdk/lib/mirrors/mirrors.dart"
+      patches: "../../sdk/lib/_internal/js_runtime/lib/mirrors_patch_cfe.dart"
       supported: false
 
     typed_data:
-      uri: "typed_data/typed_data.dart"
-      patches: "_internal/js_runtime/lib/typed_data_patch.dart"
+      uri: "../../sdk/lib/typed_data/typed_data.dart"
+      patches: "../../sdk/lib/_internal/js_runtime/lib/typed_data_patch.dart"
 
     _native_typed_data:
-      uri: "_internal/js_runtime/lib/native_typed_data.dart"
+      uri: "../../sdk/lib/_internal/js_runtime/lib/native_typed_data.dart"
 
     _internal:
-      uri: "internal/internal.dart"
-      patches: "_internal/js_runtime/lib/internal_patch.dart"
+      uri: "../../sdk/lib/internal/internal.dart"
+      patches: "../../sdk/lib/_internal/js_runtime/lib/internal_patch.dart"
 
     _js_helper:
-      uri: "_internal/js_runtime/lib/js_helper.dart"
+      uri: "../../sdk/lib/_internal/js_runtime/lib/js_helper.dart"
 
     _rti:
-      uri: "_internal/js_runtime/lib/rti.dart"
+      uri: "../../sdk/lib/_internal/js_runtime/lib/rti.dart"
 
     _interceptors:
-      uri: "_internal/js_runtime/lib/interceptors.dart"
+      uri: "../../sdk/lib/_internal/js_runtime/lib/interceptors.dart"
 
     _foreign_helper:
-      uri: "_internal/js_runtime/lib/foreign_helper.dart"
+      uri: "../../sdk/lib/_internal/js_runtime/lib/foreign_helper.dart"
 
     _js_names:
-      uri: "_internal/js_runtime/lib/js_names.dart"
+      uri: "../../sdk/lib/_internal/js_runtime/lib/js_names.dart"
 
     _js_primitives:
-      uri: "_internal/js_runtime/lib/js_primitives.dart"
+      uri: "../../sdk/lib/_internal/js_runtime/lib/js_primitives.dart"
 
     _js_embedded_names:
-      uri: "_internal/js_runtime/lib/shared/embedded_names.dart"
+      uri: "../../sdk/lib/_internal/js_runtime/lib/shared/embedded_names.dart"
 
     _async_await_error_codes:
-      uri: "_internal/js_runtime/lib/shared/async_await_error_codes.dart"
+      uri: "../../sdk/lib/_internal/js_runtime/lib/shared/async_await_error_codes.dart"
 
     _recipe_syntax:
-      uri: "_internal/js_runtime/lib/shared/recipe_syntax.dart"
+      uri: "../../sdk/lib/_internal/js_runtime/lib/shared/recipe_syntax.dart"
 
 dartdevc:
     libraries:
@@ -369,105 +369,105 @@
         uri: "_internal/js_dev_runtime/private/ddc_runtime/runtime.dart"
 
       _debugger:
-        uri: "_internal/js_dev_runtime/private/debugger.dart"
+        uri: "../../sdk/lib/_internal/js_dev_runtime/private/debugger.dart"
 
       _foreign_helper:
-        uri: "_internal/js_dev_runtime/private/foreign_helper.dart"
+        uri: "../../sdk/lib/_internal/js_dev_runtime/private/foreign_helper.dart"
 
       _http:
-        uri: "_http/http.dart"
+        uri: "../../sdk/lib/_http/http.dart"
 
       _interceptors:
-        uri: "_internal/js_dev_runtime/private/interceptors.dart"
+        uri: "../../sdk/lib/_internal/js_dev_runtime/private/interceptors.dart"
 
       _internal:
-        uri: "internal/internal.dart"
-        patches: "_internal/js_dev_runtime/patch/internal_patch.dart"
+        uri: "../../sdk/lib/internal/internal.dart"
+        patches: "../../sdk/lib/_internal/js_dev_runtime/patch/internal_patch.dart"
 
       _isolate_helper:
-        uri: "_internal/js_dev_runtime/private/isolate_helper.dart"
+        uri: "../../sdk/lib/_internal/js_dev_runtime/private/isolate_helper.dart"
 
       _js_helper:
-        uri: "_internal/js_dev_runtime/private/js_helper.dart"
+        uri: "../../sdk/lib/_internal/js_dev_runtime/private/js_helper.dart"
 
       _js_mirrors:
-        uri: "_internal/js_dev_runtime/private/js_mirrors.dart"
+        uri: "../../sdk/lib/_internal/js_dev_runtime/private/js_mirrors.dart"
 
       _js_primitives:
-        uri: "_internal/js_dev_runtime/private/js_primitives.dart"
+        uri: "../../sdk/lib/_internal/js_dev_runtime/private/js_primitives.dart"
 
       _metadata:
-        uri: "html/html_common/metadata.dart"
+        uri: "../../sdk/lib/html/html_common/metadata.dart"
 
       _native_typed_data:
-        uri: "_internal/js_dev_runtime/private/native_typed_data.dart"
+        uri: "../../sdk/lib/_internal/js_dev_runtime/private/native_typed_data.dart"
 
       async:
-        uri: "async/async.dart"
-        patches: "_internal/js_dev_runtime/patch/async_patch.dart"
+        uri: "../../sdk/lib/async/async.dart"
+        patches: "../../sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart"
 
       collection:
-        uri: "collection/collection.dart"
-        patches: "_internal/js_dev_runtime/patch/collection_patch.dart"
+        uri: "../../sdk/lib/collection/collection.dart"
+        patches: "../../sdk/lib/_internal/js_dev_runtime/patch/collection_patch.dart"
 
       convert:
-        uri: "convert/convert.dart"
-        patches: "_internal/js_dev_runtime/patch/convert_patch.dart"
+        uri: "../../sdk/lib/convert/convert.dart"
+        patches: "../../sdk/lib/_internal/js_dev_runtime/patch/convert_patch.dart"
 
       core:
-        uri: "core/core.dart"
-        patches: "_internal/js_dev_runtime/patch/core_patch.dart"
+        uri: "../../sdk/lib/core/core.dart"
+        patches: "../../sdk/lib/_internal/js_dev_runtime/patch/core_patch.dart"
 
       developer:
-        uri: "developer/developer.dart"
-        patches: "_internal/js_dev_runtime/patch/developer_patch.dart"
+        uri: "../../sdk/lib/developer/developer.dart"
+        patches: "../../sdk/lib/_internal/js_dev_runtime/patch/developer_patch.dart"
 
       io:
-        uri: "io/io.dart"
-        patches: "_internal/js_dev_runtime/patch/io_patch.dart"
+        uri: "../../sdk/lib/io/io.dart"
+        patches: "../../sdk/lib/_internal/js_dev_runtime/patch/io_patch.dart"
         supported: false
 
       isolate:
-        uri: "isolate/isolate.dart"
-        patches: "_internal/js_dev_runtime/patch/isolate_patch.dart"
+        uri: "../../sdk/lib/isolate/isolate.dart"
+        patches: "../../sdk/lib/_internal/js_dev_runtime/patch/isolate_patch.dart"
         supported: false
 
       mirrors:
-        uri: "mirrors/mirrors.dart"
-        patches: "_internal/js_dev_runtime/patch/mirrors_patch.dart"
+        uri: "../../sdk/lib/mirrors/mirrors.dart"
+        patches: "../../sdk/lib/_internal/js_dev_runtime/patch/mirrors_patch.dart"
         supported: false
 
       math:
-        uri: "math/math.dart"
-        patches: "_internal/js_dev_runtime/patch/math_patch.dart"
+        uri: "../../sdk/lib/math/math.dart"
+        patches: "../../sdk/lib/_internal/js_dev_runtime/patch/math_patch.dart"
 
       typed_data:
-        uri: "typed_data/typed_data.dart"
-        patches: "_internal/js_dev_runtime/patch/typed_data_patch.dart"
+        uri: "../../sdk/lib/typed_data/typed_data.dart"
+        patches: "../../sdk/lib/_internal/js_dev_runtime/patch/typed_data_patch.dart"
 
       html:
-        uri: "html/dart2js/html_dart2js.dart"
+        uri: "../../sdk/lib/html/dart2js/html_dart2js.dart"
 
       html_common:
-        uri: "html/html_common/html_common_dart2js.dart"
+        uri: "../../sdk/lib/html/html_common/html_common_dart2js.dart"
 
       indexed_db:
-        uri: "indexed_db/dart2js/indexed_db_dart2js.dart"
+        uri: "../../sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart"
 
       js:
-        uri: "_internal/js_dev_runtime/lib/js/dart2js/js_dart2js.dart"
+        uri: "../../sdk/lib/_internal/js_dev_runtime/lib/js/dart2js/js_dart2js.dart"
 
       js_util:
-        uri: "_internal/js_dev_runtime/lib/js_util/dart2js/js_util_dart2js.dart"
+        uri: "../../sdk/lib/_internal/js_dev_runtime/lib/js_util/dart2js/js_util_dart2js.dart"
 
       svg:
-        uri: "svg/dart2js/svg_dart2js.dart"
+        uri: "../../sdk/lib/svg/dart2js/svg_dart2js.dart"
 
       web_audio:
-        uri: "web_audio/dart2js/web_audio_dart2js.dart"
+        uri: "../../sdk/lib/web_audio/dart2js/web_audio_dart2js.dart"
 
       web_gl:
-        uri: "web_gl/dart2js/web_gl_dart2js.dart"
+        uri: "../../sdk/lib/web_gl/dart2js/web_gl_dart2js.dart"
 
       web_sql:
-        uri: "web_sql/dart2js/web_sql_dart2js.dart"
+        uri: "../../sdk/lib/web_sql/dart2js/web_sql_dart2js.dart"
diff --git a/tests/co19/update.sh b/tests/co19/update.sh
new file mode 100755
index 0000000..b4b5ff0
--- /dev/null
+++ b/tests/co19/update.sh
@@ -0,0 +1,71 @@
+#!/usr/bin/env bash
+# Uploads a new version of the co19 CIPD package.
+# This script requires access to the dart-build-access group, which EngProd has.
+
+set -e
+set -x
+
+if [ ! -e tests/co19 ]; then
+  echo "$0: error: Run this script at the root of the Dart SDK" >&2
+  exit 1
+fi
+
+# Find the latest co19 commit.
+rm -rf tests/co19/src.git
+git clone https://dart.googlesource.com/co19 tests/co19/src.git
+CO19=tests/co19/src.git
+OLD=$(gclient getdep --var=co19_rev)
+NEW=$(cd $CO19 && git fetch origin && git rev-parse origin/master)
+
+git fetch origin
+git branch cl-co19-roll-co19-to-$NEW origin/master
+git checkout cl-co19-roll-co19-to-$NEW
+
+# Build a cipd package of the commit.
+BUILD_ID=$(bb add \
+              -commit https://dart.googlesource.com/co19/+/$NEW \
+              -json \
+              dart/ci/co19-roller \
+             | jq '.id' \
+             | tr -d '"')
+bb collect -interval 10s $BUILD_ID
+
+# Update DEPS:
+gclient setdep --var=co19_rev=$NEW
+
+# Make a nice commit. Don't include the '#' character to avoid referencing Dart
+# SDK issues.
+git commit DEPS -m \
+  "$(printf "[co19] Roll co19 to $NEW\n\n" &&
+     cd $CO19 &&
+     git log --date='format:%Y-%m-%d' --pretty='format:%ad %ae %s' \
+       $OLD..$NEW | tr -d '#')"
+
+rm -rf tests/co19/src.git
+
+GIT_EDITOR=true git cl upload
+ISSUE=$(git config --get branch.cl-co19-roll-co19-to-$NEW.gerritissue)
+
+BUILDERS=$(jq '.builder_configurations|
+                map(select(.steps|
+                           any(.arguments|
+                               select(.!=null)|
+                               any(.=="co19"))))|
+                map(.builders)|
+                flatten|
+                sort' \
+                tools/bots/test_matrix.json \
+             | tr -d '[",]')
+
+git cl try -B dart/try $(for BUILDER in $BUILDERS; do echo -b $BUILDER-try; done)
+
+git cl web
+
+set +x
+cat << EOF
+
+Wait for the builders to finish. If any failed, pre-approve them:
+
+  tools/sdks/dart-sdk/bin/dart tools/approve_results.dart \
+    -p https://dart-review.googlesource.com/c/sdk/+/$ISSUE
+EOF
diff --git a/tests/co19_2/co19_2-co19.status b/tests/co19_2/co19_2-co19.status
new file mode 100644
index 0000000..0d2914b
--- /dev/null
+++ b/tests/co19_2/co19_2-co19.status
@@ -0,0 +1,265 @@
+# Copyright (c) 2019, 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.
+
+[ $compiler != fasta ]
+Language/Classes/Abstract_Instance_Members/inherited_t13: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Abstract_Instance_Members/inherited_t14: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Abstract_Instance_Members/inherited_t15: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Abstract_Instance_Members/invocation_t05: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Abstract_Instance_Members/invocation_t06: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Abstract_Instance_Members/override_default_value_t10: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Abstract_Instance_Members/override_less_positional_parameters_t03: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Abstract_Instance_Members/override_more_required_parameters_t05: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Abstract_Instance_Members/override_no_named_parameters_t07: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Abstract_Instance_Members/override_not_a_subtype_t05: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Abstract_Instance_Members/same_name_static_method_in_superclass_t07: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Constructors/Constant_Constructors/name_t01: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Constructors/Constant_Constructors/not_a_constant_in_superclass_t03: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Constructors/Constant_Constructors/superinitializer_t05: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Constructors/Constant_Constructors/superinitializer_t06: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Constructors/Factories/name_t06: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Constructors/Factories/name_t07: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Constructors/Factories/redirecting_constructor_call_t03: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Constructors/Factories/redirecting_constructor_t04: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Constructors/Factories/redirecting_to_itself_t05: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Constructors/Factories/redirecting_to_itself_t06: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Constructors/Factories/redirecting_to_itself_t07: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Constructors/Factories/return_type_t08: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Constructors/Factories/return_wrong_type_t08: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Constructors/Factories/return_wrong_type_t09: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Constructors/Factories/return_wrong_type_t10: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Constructors/Generative_Constructors/execution_of_a_superinitializer_t02: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Constructors/Generative_Constructors/formal_parameter_t09: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Constructors/Generative_Constructors/formal_parameter_t10: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Constructors/Generative_Constructors/formal_parameter_t11: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Constructors/Generative_Constructors/implicit_superinitializer_t03: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Constructors/Generative_Constructors/implicit_superinitializer_t04: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Constructors/Generative_Constructors/initializers_t17: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Constructors/Generative_Constructors/name_t01: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Constructors/Generative_Constructors/superinitializer_t04: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Constructors/implicit_constructor_t04: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Constructors/implicit_constructor_t05: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Constructors/name_t08: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Constructors/wrong_name_t02: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Constructors/wrong_name_t03: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Getters/instance_getter_t13: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Getters/instance_getter_t14: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Getters/override_t05: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Getters/same_name_method_t13: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Getters/same_name_method_t14: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Getters/type_object_t03: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Instance_Methods/override_different_default_values_t03: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Instance_Methods/override_fewer_parameters_t03: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Instance_Methods/override_more_parameters_t03: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Instance_Methods/override_named_parameters_t07: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Instance_Methods/override_named_parameters_t08: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Instance_Methods/override_named_parameters_t09: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Instance_Methods/override_named_parameters_t10: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Instance_Methods/override_named_parameters_t11: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Instance_Methods/override_subtype_t07: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Instance_Methods/override_subtype_t08: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Instance_Methods/override_subtype_t09: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Instance_Methods/override_subtype_t10: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Instance_Methods/override_subtype_t11: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Instance_Methods/override_subtype_t12: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Instance_Methods/same_name_getter_t03: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Instance_Methods/same_name_setter_t03: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Instance_Methods/same_name_static_member_in_superclass_t10: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Instance_Methods/same_name_static_member_in_superclass_t11: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Instance_Variables/definition_t05: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Instance_Variables/type_aliases_t01: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Instance_Variables/type_aliases_t02: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Instance_Variables/type_aliases_t03: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Setters/syntax_t06: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Static_Methods/declaration_t04: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Static_Variables/inheritance_t02: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Static_Variables/type_alias_t01: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Superclasses/Inheritance_and_Overriding/abstract_method_t02: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Superclasses/Inheritance_and_Overriding/inheritance_t08: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Superclasses/Inheritance_and_Overriding/inheritance_t09: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Superclasses/Inheritance_and_Overriding/inheritance_t10: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Superclasses/Inheritance_and_Overriding/overriding_t06: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Superclasses/Inheritance_and_Overriding/overriding_t07: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Superclasses/Inheritance_and_Overriding/overriding_t08: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Superclasses/extends_clause_t02: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Superclasses/superclass_of_itself_t03: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Superclasses/superclass_of_itself_t04: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Superclasses/transition_t02: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Superinterfaces/dynamic_type_t03: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Superinterfaces/implicit_interface_t03: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Superinterfaces/itself_t02: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Superinterfaces/more_than_once_t02: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Superinterfaces/no_member_t06: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Superinterfaces/no_member_t07: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Superinterfaces/superclass_as_superinterface_t02: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Superinterfaces/superclass_as_superinterface_t03: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Superinterfaces/superclass_as_superinterface_t04: Skip # github.com/dart-lang/language/issues/115
+Language/Classes/Superinterfaces/syntax_t03: Skip # github.com/dart-lang/language/issues/115
+Language/Enums/restrictions_t09: Skip # github.com/dart-lang/language/issues/115
+Language/Enums/restrictions_t10: Skip # github.com/dart-lang/language/issues/115
+Language/Enums/restrictions_t11: Skip # github.com/dart-lang/language/issues/115
+Language/Enums/restrictions_t12: Skip # github.com/dart-lang/language/issues/115
+Language/Enums/syntax_t10: Skip # github.com/dart-lang/language/issues/115
+Language/Expressions/Instance_Creation/New/type_t08: Skip # github.com/dart-lang/language/issues/115
+Language/Expressions/Instance_Creation/New/type_t09: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/Superbounded_types/typedef3_A01_t01: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/Superbounded_types/typedef3_A01_t02: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/Superbounded_types/typedef3_A01_t03: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/Superbounded_types/typedef3_A01_t04: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/Superbounded_types/typedef3_A01_t05: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/Superbounded_types/typedef3_A01_t06: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/parameter_A01_t03: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/parameter_A01_t04: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/parameter_A02_t03: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/parameter_A03_t03: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/parameter_A04_t03: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/parameter_A09_t03: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/syntax_t20: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/syntax_t21: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/syntax_t22: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/syntax_t23: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/syntax_t24: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/syntax_t25: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/syntax_t27: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/syntax_t28: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/syntax_t29: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/syntax_t30: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/typedef_A01_t01: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/typedef_A01_t02: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/typedef_A01_t03: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/typedef_A01_t04: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/typedef_A01_t05: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/typedef_A01_t06: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/typedef_A01_t07: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/typedef_A01_t08: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/typedef_A01_t10: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/typedef_A04_t01: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/typedef_A04_t02: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/typedef_A06_t01: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/typedef_A06_t02: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/typedef_A06_t03: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/typedef_A06_t04: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/typedef_A06_t05: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/typedef_A06_t06: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/typedef_A06_t07: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/typedef_A06_t08: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/typedef_A06_t09: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/typedef_A06_t10: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/typedef_A06_t11: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/typedef_A06_t12: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/typedef_A06_t13: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/typedef_A06_t14: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/typedef_A07_t01: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/typedef_A08_t01: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/typedef_A09_t05: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/typedef_A09_t06: Skip # github.com/dart-lang/language/issues/115
+Language/Generics/typedef_A10_t01: Skip # github.com/dart-lang/language/issues/115
+Language/Interfaces/Superinterfaces/Inheritance_and_Overriding/inheritance_t09: Skip # github.com/dart-lang/language/issues/115
+Language/Interfaces/Superinterfaces/Inheritance_and_Overriding/inheritance_t10: Skip # github.com/dart-lang/language/issues/115
+Language/Interfaces/Superinterfaces/Inheritance_and_Overriding/inheritance_t11: Skip # github.com/dart-lang/language/issues/115
+Language/Interfaces/Superinterfaces/Inheritance_and_Overriding/inheritance_t12: Skip # github.com/dart-lang/language/issues/115
+Language/Interfaces/Superinterfaces/Inheritance_and_Overriding/inheritance_t13: Skip # github.com/dart-lang/language/issues/115
+Language/Interfaces/Superinterfaces/Inheritance_and_Overriding/inheritance_t14: Skip # github.com/dart-lang/language/issues/115
+Language/Interfaces/Superinterfaces/Inheritance_and_Overriding/not_overriden_members_t03: Skip # github.com/dart-lang/language/issues/115
+Language/Interfaces/Superinterfaces/Inheritance_and_Overriding/not_overriden_members_t04: Skip # github.com/dart-lang/language/issues/115
+Language/Interfaces/Superinterfaces/Inheritance_and_Overriding/same_name_getters_t03: Skip # github.com/dart-lang/language/issues/115
+Language/Interfaces/Superinterfaces/Inheritance_and_Overriding/same_name_getters_t04: Skip # github.com/dart-lang/language/issues/115
+Language/Interfaces/Superinterfaces/Inheritance_and_Overriding/same_name_getters_type_t10: Skip # github.com/dart-lang/language/issues/115
+Language/Interfaces/Superinterfaces/Inheritance_and_Overriding/same_name_getters_type_t11: Skip # github.com/dart-lang/language/issues/115
+Language/Interfaces/Superinterfaces/Inheritance_and_Overriding/same_name_getters_type_t12: Skip # github.com/dart-lang/language/issues/115
+Language/Interfaces/Superinterfaces/Inheritance_and_Overriding/same_name_members_t03: Skip # github.com/dart-lang/language/issues/115
+Language/Interfaces/Superinterfaces/Inheritance_and_Overriding/same_name_method_and_getter_t03: Skip # github.com/dart-lang/language/issues/115
+Language/Interfaces/Superinterfaces/definition_t06: Skip # github.com/dart-lang/language/issues/115
+Language/Interfaces/Superinterfaces/superinterface_of_itself_t04: Skip # github.com/dart-lang/language/issues/115
+Language/Mixins/Mixin_Application/abstract_t09: Skip # github.com/dart-lang/language/issues/115
+Language/Mixins/Mixin_Application/abstract_t10: Skip # github.com/dart-lang/language/issues/115
+Language/Mixins/Mixin_Application/abstract_t11: Skip # github.com/dart-lang/language/issues/115
+Language/Mixins/Mixin_Application/abstract_t12: Skip # github.com/dart-lang/language/issues/115
+Language/Mixins/Mixin_Application/abstract_t13: Skip # github.com/dart-lang/language/issues/115
+Language/Mixins/Mixin_Application/deferred_t03: Skip # github.com/dart-lang/language/issues/115
+Language/Mixins/Mixin_Application/implicit_constructor_t03: Skip # github.com/dart-lang/language/issues/115
+Language/Mixins/Mixin_Application/implicit_constructor_t04: Skip # github.com/dart-lang/language/issues/115
+Language/Mixins/Mixin_Application/initializers_t04: Skip # github.com/dart-lang/language/issues/115
+Language/Mixins/Mixin_Application/initializers_t05: Skip # github.com/dart-lang/language/issues/115
+Language/Mixins/Mixin_Application/initializers_t06: Skip # github.com/dart-lang/language/issues/115
+Language/Mixins/Mixin_Application/interfaces_t06: Skip # github.com/dart-lang/language/issues/115
+Language/Mixins/Mixin_Application/interfaces_t07: Skip # github.com/dart-lang/language/issues/115
+Language/Mixins/Mixin_Application/superclass_t03: Skip # github.com/dart-lang/language/issues/115
+Language/Mixins/Mixin_Application/superclass_t04: Skip # github.com/dart-lang/language/issues/115
+Language/Mixins/Mixin_Application/superinterfaces_t10: Skip # github.com/dart-lang/language/issues/115
+Language/Mixins/Mixin_Application/superinterfaces_t11: Skip # github.com/dart-lang/language/issues/115
+Language/Mixins/Mixin_Application/superinterfaces_t12: Skip # github.com/dart-lang/language/issues/115
+Language/Mixins/Mixin_Application/superinterfaces_t13: Skip # github.com/dart-lang/language/issues/115
+Language/Mixins/Mixin_Application/superinterfaces_t14: Skip # github.com/dart-lang/language/issues/115
+Language/Mixins/Mixin_Application/syntax_t26: Skip # github.com/dart-lang/language/issues/115
+Language/Mixins/Mixin_Application/warning_t04: Skip # github.com/dart-lang/language/issues/115
+Language/Mixins/Mixin_Application/wrong_mixin_type_t09: Skip # github.com/dart-lang/language/issues/115
+Language/Mixins/Mixin_Composition/order_t02: Skip # github.com/dart-lang/language/issues/115
+Language/Mixins/declaring_constructor_t11: Skip # github.com/dart-lang/language/issues/115
+Language/Types/Type_Aliases/built-in_types_t01: Skip # github.com/dart-lang/language/issues/115
+Language/Types/Type_Aliases/built-in_types_t02: Skip # github.com/dart-lang/language/issues/115
+Language/Types/Type_Aliases/built-in_types_t03: Skip # github.com/dart-lang/language/issues/115
+Language/Types/Type_Aliases/built-in_types_t04: Skip # github.com/dart-lang/language/issues/115
+Language/Types/Type_Aliases/built-in_types_t05: Skip # github.com/dart-lang/language/issues/115
+Language/Types/Type_Aliases/built-in_types_t06: Skip # github.com/dart-lang/language/issues/115
+Language/Types/Type_Aliases/built-in_types_t07: Skip # github.com/dart-lang/language/issues/115
+Language/Types/Type_Aliases/built-in_types_t08: Skip # github.com/dart-lang/language/issues/115
+Language/Types/Type_Aliases/built-in_types_t09: Skip # github.com/dart-lang/language/issues/115
+Language/Types/Type_Aliases/built-in_types_t10: Skip # github.com/dart-lang/language/issues/115
+Language/Types/Type_Aliases/built-in_types_t11: Skip # github.com/dart-lang/language/issues/115
+Language/Types/Type_Aliases/built-in_types_t12: Skip # github.com/dart-lang/language/issues/115
+Language/Types/Type_Aliases/scope_t01: Skip # github.com/dart-lang/language/issues/115
+Language/Types/Type_Aliases/scope_t02: Skip # github.com/dart-lang/language/issues/115
+Language/Types/Type_Aliases/scope_t03: Skip # github.com/dart-lang/language/issues/115
+Language/Types/Type_Aliases/scope_t04: Skip # github.com/dart-lang/language/issues/115
+Language/Types/Type_Aliases/self_reference_t19: Skip # github.com/dart-lang/language/issues/115
+Language/Types/Type_Aliases/self_reference_t20: Skip # github.com/dart-lang/language/issues/115
+Language/Types/Type_Aliases/self_reference_t21: Skip # github.com/dart-lang/language/issues/115
+Language/Types/Type_Aliases/self_reference_t22: Skip # github.com/dart-lang/language/issues/115
+Language/Types/Type_Aliases/self_reference_t23: Skip # github.com/dart-lang/language/issues/115
+Language/Types/Type_Aliases/self_reference_t24: Skip # github.com/dart-lang/language/issues/115
+Language/Types/Type_Aliases/self_reference_t25: Skip # github.com/dart-lang/language/issues/115
+Language/Types/Type_Aliases/syntax_t01: Skip # github.com/dart-lang/language/issues/115
+Language/Types/Type_Aliases/syntax_t02: Skip # github.com/dart-lang/language/issues/115
+Language/Types/Type_Aliases/syntax_t03: Skip # github.com/dart-lang/language/issues/115
+Language/Types/Type_Aliases/syntax_t04: Skip # github.com/dart-lang/language/issues/115
+Language/Types/Type_Aliases/syntax_t05: Skip # github.com/dart-lang/language/issues/115
+Language/Types/Type_Aliases/syntax_t06: Skip # github.com/dart-lang/language/issues/115
+Language/Types/Type_Aliases/syntax_t20: Skip # github.com/dart-lang/language/issues/115
+Language/Types/Type_Aliases/syntax_t21: Skip # github.com/dart-lang/language/issues/115
+LanguageFeatures/Instantiate-to-bound/nonfunction_typedef/dynamic/*: Skip # github.com/dart-lang/language/issues/115
+LanguageFeatures/Instantiate-to-bound/nonfunction_typedef/static/*: Skip # github.com/dart-lang/language/issues/115
+LanguageFeatures/Simple-bounds/dynamic/typedef1_FutureOr_l1_t01: Skip # github.com/dart-lang/language/issues/115
+LanguageFeatures/Simple-bounds/dynamic/typedef1_FutureOr_l1_t02: Skip # github.com/dart-lang/language/issues/115
+LanguageFeatures/Simple-bounds/dynamic/typedef1_l1_t01: Skip # github.com/dart-lang/language/issues/115
+LanguageFeatures/Simple-bounds/dynamic/typedef1_l1_t02: Skip # github.com/dart-lang/language/issues/115
+LanguageFeatures/Simple-bounds/dynamic/typedef1_l1_t03: Skip # github.com/dart-lang/language/issues/115
+LanguageFeatures/Simple-bounds/dynamic/typedef1_l1_t04: Skip # github.com/dart-lang/language/issues/115
+LanguageFeatures/Simple-bounds/dynamic/typedef1_l2_t01: Skip # github.com/dart-lang/language/issues/115
+LanguageFeatures/Simple-bounds/dynamic/typedef1_l2_t02: Skip # github.com/dart-lang/language/issues/115
+LanguageFeatures/Simple-bounds/dynamic/typedef1_typedef_l1_t01: Skip # github.com/dart-lang/language/issues/115
+LanguageFeatures/Simple-bounds/dynamic/typedef1_typedef_l1_t02: Skip # github.com/dart-lang/language/issues/115
+LanguageFeatures/Simple-bounds/dynamic/typedef1_typedef_l1_t03: Skip # github.com/dart-lang/language/issues/115
+LanguageFeatures/Simple-bounds/dynamic/typedef1_typedef_l1_t04: Skip # github.com/dart-lang/language/issues/115
+LanguageFeatures/Simple-bounds/dynamic/typedef1_typedef_l1_t05: Skip # github.com/dart-lang/language/issues/115
+LanguageFeatures/Simple-bounds/dynamic/typedef1_typedef_l1_t07: Skip # github.com/dart-lang/language/issues/115
+LanguageFeatures/Simple-bounds/dynamic/typedef1_typedef_l1_t08: Skip # github.com/dart-lang/language/issues/115
+LanguageFeatures/Simple-bounds/static/typedef1_FutureOr_l1_t01: Skip # github.com/dart-lang/language/issues/115
+LanguageFeatures/Simple-bounds/static/typedef1_FutureOr_l1_t02: Skip # github.com/dart-lang/language/issues/115
+LanguageFeatures/Simple-bounds/static/typedef1_l1_t01: Skip # github.com/dart-lang/language/issues/115
+LanguageFeatures/Simple-bounds/static/typedef1_l1_t02: Skip # github.com/dart-lang/language/issues/115
+LanguageFeatures/Simple-bounds/static/typedef1_l1_t03: Skip # github.com/dart-lang/language/issues/115
+LanguageFeatures/Simple-bounds/static/typedef1_l1_t04: Skip # github.com/dart-lang/language/issues/115
+LanguageFeatures/Simple-bounds/static/typedef1_l2_t01: Skip # github.com/dart-lang/language/issues/115
+LanguageFeatures/Simple-bounds/static/typedef1_l2_t02: Skip # github.com/dart-lang/language/issues/115
+LanguageFeatures/Simple-bounds/static/typedef1_typedef_l1_t01: Skip # github.com/dart-lang/language/issues/115
+LanguageFeatures/Simple-bounds/static/typedef1_typedef_l1_t02: Skip # github.com/dart-lang/language/issues/115
+LanguageFeatures/Simple-bounds/static/typedef1_typedef_l1_t03: Skip # github.com/dart-lang/language/issues/115
+LanguageFeatures/Simple-bounds/static/typedef1_typedef_l1_t04: Skip # github.com/dart-lang/language/issues/115
+LanguageFeatures/Simple-bounds/static/typedef1_typedef_l1_t05: Skip # github.com/dart-lang/language/issues/115
+LanguageFeatures/Simple-bounds/static/typedef1_typedef_l1_t06: Skip # github.com/dart-lang/language/issues/115
+LanguageFeatures/Simple-bounds/static/typedef1_typedef_l1_t07: Skip # github.com/dart-lang/language/issues/115
+LanguageFeatures/Simple-bounds/static/typedef1_typedef_l1_t08: Skip # github.com/dart-lang/language/issues/115
+LanguageFeatures/regression/32903_t02: Skip # github.com/dart-lang/language/issues/115
+LanguageFeatures/regression/34560_t02: Skip # github.com/dart-lang/language/issues/115
diff --git a/tests/co19_2/update.sh b/tests/co19_2/update.sh
index 3fb0933..db2c88f 100755
--- a/tests/co19_2/update.sh
+++ b/tests/co19_2/update.sh
@@ -1,5 +1,5 @@
 #!/usr/bin/env bash
-# Uploads a new version of the co19 CIPD packages.
+# Uploads a new version of the co19_2 CIPD package.
 # This script requires access to the dart-build-access group, which EngProd has.
 
 set -e
@@ -25,6 +25,7 @@
 BUILD_ID=$(bb add \
               -commit https://dart.googlesource.com/co19/+/$NEW \
               -json \
+              -p variant=legacy \
               dart/ci/co19-roller \
              | jq '.id' \
              | tr -d '"')
@@ -36,7 +37,7 @@
 # Make a nice commit. Don't include the '#' character to avoid referencing Dart
 # SDK issues.
 git commit DEPS -m \
-  "$(printf "[co19] Roll co19 to $NEW\n\n" &&
+  "$(printf "[co19] Roll co19_2 to $NEW\n\n" &&
      cd $CO19 &&
      git log --date='format:%Y-%m-%d' --pretty='format:%ad %ae %s' \
        $OLD..$NEW | tr -d '#')"
diff --git a/tests/compiler/dart2js/analyses/analysis_helper.dart b/tests/compiler/dart2js/analyses/analysis_helper.dart
index cea60ab..211c911 100644
--- a/tests/compiler/dart2js/analyses/analysis_helper.dart
+++ b/tests/compiler/dart2js/analyses/analysis_helper.dart
@@ -75,6 +75,9 @@
 
   ir.ConstantEvaluator _constantEvaluator;
 
+  @override
+  ir.StaticTypeContext staticTypeContext;
+
   StaticTypeVisitorBase(
       ir.Component component, ir.ClassHierarchy classHierarchy)
       : super(
@@ -103,10 +106,12 @@
       // Skip synthetic .dill members.
       return;
     }
+    staticTypeContext = new ir.StaticTypeContext(node, typeEnvironment);
     variableScopeModel =
         new ScopeModel.from(node, _constantEvaluator).variableScopeModel;
     super.visitProcedure(node);
     variableScopeModel = null;
+    staticTypeContext = null;
   }
 
   @override
@@ -115,10 +120,12 @@
       // Skip synthetic .dill members.
       return;
     }
+    staticTypeContext = new ir.StaticTypeContext(node, typeEnvironment);
     variableScopeModel =
         new ScopeModel.from(node, _constantEvaluator).variableScopeModel;
     super.visitField(node);
     variableScopeModel = null;
+    staticTypeContext = null;
   }
 
   @override
@@ -127,10 +134,12 @@
       // Skip synthetic .dill members.
       return;
     }
+    staticTypeContext = new ir.StaticTypeContext(node, typeEnvironment);
     variableScopeModel =
         new ScopeModel.from(node, _constantEvaluator).variableScopeModel;
     super.visitConstructor(node);
     variableScopeModel = null;
+    staticTypeContext = null;
   }
 }
 
@@ -292,9 +301,7 @@
       enclosingClass = enclosingClass.parent;
     }
     try {
-      typeEnvironment.thisType =
-          enclosingClass is ir.Class ? enclosingClass.thisType : null;
-      return node.getStaticType(typeEnvironment);
+      return node.getStaticType(staticTypeContext);
     } catch (e) {
       // The static type computation crashes on type errors. Use `dynamic`
       // as static type.
diff --git a/tests/compiler/dart2js/analyses/api_allowed.json b/tests/compiler/dart2js/analyses/api_allowed.json
index 9a02f59..b988fc0 100644
--- a/tests/compiler/dart2js/analyses/api_allowed.json
+++ b/tests/compiler/dart2js/analyses/api_allowed.json
@@ -178,20 +178,6 @@
     "Dynamic invocation of 'where'.": 1,
     "Dynamic access of 'single'.": 1
   },
-  "org-dartlang-sdk:///sdk/lib/_internal/js_runtime/lib/core_patch.dart": {
-    "Dynamic access of 'dart.core::_digits'.": 2,
-    "Dynamic invocation of '<'.": 2,
-    "Dynamic invocation of '[]'.": 17,
-    "Dynamic invocation of '+'.": 2,
-    "Dynamic invocation of 'dart.core::_absSubSetSign'.": 3,
-    "Dynamic invocation of 'dart.core::_absAndNotSetSign'.": 2,
-    "Dynamic invocation of 'dart.core::_absAddSetSign'.": 2,
-    "Dynamic invocation of 'dart.core::_absXorSetSign'.": 1,
-    "Dynamic invocation of '[]='.": 2,
-    "Dynamic invocation of '&'.": 6,
-    "Dynamic invocation of '-'.": 1,
-    "Dynamic invocation of '>='.": 1
-  },
   "org-dartlang-sdk:///sdk/lib/core/errors.dart": {
     "Dynamic access of 'length'.": 2
   },
@@ -239,4 +225,4 @@
     "Dynamic access of 'port'.": 1,
     "Dynamic invocation of 'dart._http::_toJSON'.": 1
   }
-}
\ No newline at end of file
+}
diff --git a/tests/compiler/dart2js/analyses/dart2js_allowed.json b/tests/compiler/dart2js/analyses/dart2js_allowed.json
index ff6c98a..f62235b 100644
--- a/tests/compiler/dart2js/analyses/dart2js_allowed.json
+++ b/tests/compiler/dart2js/analyses/dart2js_allowed.json
@@ -183,21 +183,12 @@
   "third_party/pkg/dart2js_info/lib/binary_serialization.dart": {
     "Dynamic invocation of 'cast'.": 1
   },
-  "pkg/compiler/lib/src/inferrer/inferrer_engine.dart": {
-    "Dynamic access of 'isVoid'.": 1,
-    "Dynamic access of 'isDynamic'.": 1,
-    "Dynamic access of 'isInterfaceType'.": 1,
-    "Dynamic access of 'element'.": 1
-  },
   "pkg/compiler/lib/src/js_backend/checked_mode_helpers.dart": {
     "Dynamic access of 'name'.": 1
   },
   "pkg/compiler/lib/src/universe/side_effects.dart": {
     "Dynamic access of 'universe.side_effects::_flags'.": 1
   },
-  "pkg/compiler/lib/src/native/enqueue.dart": {
-    "Dynamic access of 'isDynamic'.": 1
-  },
   "pkg/compiler/lib/src/ssa/builder_kernel.dart": {
     "Dynamic update to 'instantiatedTypes'.": 1,
     "Dynamic update to 'sideEffects'.": 1,
@@ -206,8 +197,6 @@
     "Dynamic invocation of 'addSuccessor'.": 1
   },
   "pkg/compiler/lib/src/ssa/types.dart": {
-    "Dynamic access of 'isVoid'.": 1,
-    "Dynamic access of 'isDynamic'.": 1,
     "Dynamic access of 'treatAsDynamic'.": 1,
     "Dynamic access of 'element'.": 1
   },
diff --git a/tests/compiler/dart2js/analyses/static_type_visitor_test.dart b/tests/compiler/dart2js/analyses/static_type_visitor_test.dart
index d546a06..44c73c0 100644
--- a/tests/compiler/dart2js/analyses/static_type_visitor_test.dart
+++ b/tests/compiler/dart2js/analyses/static_type_visitor_test.dart
@@ -40,14 +40,14 @@
       // as static type.
       return const ir.DynamicType();
     }
-    ir.TreeNode enclosingClass = node;
-    while (enclosingClass != null && enclosingClass is! ir.Class) {
-      enclosingClass = enclosingClass.parent;
+    ir.TreeNode enclosingMember = node;
+    while (enclosingMember != null && enclosingMember is! ir.Member) {
+      enclosingMember = enclosingMember.parent;
     }
     try {
-      typeEnvironment.thisType =
-          enclosingClass is ir.Class ? enclosingClass.thisType : null;
-      return node.getStaticType(typeEnvironment);
+      staticTypeContext =
+          new ir.StaticTypeContext(enclosingMember, typeEnvironment);
+      return node.getStaticType(staticTypeContext);
     } catch (e) {
       // The static type computation crashes on type errors. Use `dynamic`
       // as static type.
diff --git a/tests/compiler/dart2js/equivalence/check_helpers.dart b/tests/compiler/dart2js/equivalence/check_helpers.dart
index ee1aa14..1b7ae3a 100644
--- a/tests/compiler/dart2js/equivalence/check_helpers.dart
+++ b/tests/compiler/dart2js/equivalence/check_helpers.dart
@@ -441,6 +441,23 @@
   }
 
   @override
+  visitLegacyType(LegacyType type, _) {
+    visit(type.baseType);
+    sb.write('*');
+  }
+
+  @override
+  visitNullableType(NullableType type, _) {
+    visit(type.baseType);
+    sb.write('?');
+  }
+
+  @override
+  visitNeverType(NeverType type, _) {
+    sb.write('Never');
+  }
+
+  @override
   visitDynamicType(DynamicType type, _) {
     sb.write('dynamic');
   }
@@ -458,7 +475,7 @@
   @override
   visitTypedefType(TypedefType type, _) {
     sb.write(type.element.name);
-    if (type.typeArguments.any((type) => !type.isDynamic)) {
+    if (type.typeArguments.any((type) => type is! DynamicType)) {
       sb.write('<');
       visitTypes(type.typeArguments);
       sb.write('>');
@@ -468,7 +485,7 @@
   @override
   visitInterfaceType(InterfaceType type, _) {
     sb.write(type.element.name);
-    if (type.typeArguments.any((type) => !type.isDynamic)) {
+    if (type.typeArguments.any((type) => type is! DynamicType)) {
       sb.write('<');
       visitTypes(type.typeArguments);
       sb.write('>');
diff --git a/tests/compiler/dart2js/helpers/shared_helper.dart b/tests/compiler/dart2js/helpers/shared_helper.dart
index d03dddc..ec3cc15 100644
--- a/tests/compiler/dart2js/helpers/shared_helper.dart
+++ b/tests/compiler/dart2js/helpers/shared_helper.dart
@@ -24,6 +24,23 @@
   }
 
   @override
+  void visitLegacyType(LegacyType type, StringBuffer sb) {
+    visit(type.baseType, sb);
+    sb.write('*');
+  }
+
+  @override
+  void visitNullableType(NullableType type, StringBuffer sb) {
+    visit(type.baseType, sb);
+    sb.write('?');
+  }
+
+  @override
+  void visitNeverType(NeverType type, StringBuffer sb) {
+    sb.write('Never');
+  }
+
+  @override
   void visitVoidType(VoidType type, StringBuffer sb) {
     sb.write('void');
   }
diff --git a/tests/compiler/dart2js/model/cfe_constant_evaluation_test.dart b/tests/compiler/dart2js/model/cfe_constant_evaluation_test.dart
index 180375b..5a5e639 100644
--- a/tests/compiler/dart2js/model/cfe_constant_evaluation_test.dart
+++ b/tests/compiler/dart2js/model/cfe_constant_evaluation_test.dart
@@ -19,6 +19,7 @@
 import 'package:compiler/src/kernel/element_map_impl.dart';
 import 'package:front_end/src/api_unstable/dart2js.dart' as ir;
 import 'package:kernel/ast.dart' as ir;
+import 'package:kernel/type_environment.dart' as ir;
 import '../helpers/memory_compiler.dart';
 
 class TestData {
@@ -575,6 +576,7 @@
     Compiler compiler = result.compiler;
     KernelFrontendStrategy frontEndStrategy = compiler.frontendStrategy;
     KernelToElementMapImpl elementMap = frontEndStrategy.elementMap;
+    ir.TypeEnvironment typeEnvironment = elementMap.typeEnvironment;
     KElementEnvironment elementEnvironment =
         compiler.frontendStrategy.elementEnvironment;
     ConstantValuefier constantValuefier = new ConstantValuefier(elementMap);
@@ -605,7 +607,8 @@
             errors.add(context.first.code.name);
             reportLocatedMessage(elementMap.reporter, message, context);
           }, environment: environment, supportReevaluationForTesting: true);
-          ir.Constant evaluatedConstant = evaluator.evaluate(initializer);
+          ir.Constant evaluatedConstant = evaluator.evaluate(
+              new ir.StaticTypeContext(node, typeEnvironment), initializer);
 
           ConstantValue value = evaluatedConstant is! ir.UnevaluatedConstant
               ? constantValuefier.visitConstant(evaluatedConstant)
diff --git a/tests/compiler/dart2js/model/cfe_constant_test.dart b/tests/compiler/dart2js/model/cfe_constant_test.dart
index a6ff5a0..a35b457 100644
--- a/tests/compiler/dart2js/model/cfe_constant_test.dart
+++ b/tests/compiler/dart2js/model/cfe_constant_test.dart
@@ -52,7 +52,7 @@
     KernelFrontendStrategy frontendStrategy = compiler.frontendStrategy;
     KernelToElementMapImpl elementMap = frontendStrategy.elementMap;
     ir.Member node = elementMap.getMemberNode(member);
-    new ConstantDataExtractor(compiler.reporter, actualMap, elementMap)
+    new ConstantDataExtractor(compiler.reporter, actualMap, elementMap, member)
         .run(node);
   }
 
@@ -75,15 +75,17 @@
 /// IR visitor for computing inference data for a member.
 class ConstantDataExtractor extends IrDataExtractor<String> {
   final KernelToElementMapImpl elementMap;
+  final MemberEntity member;
 
   ConstantDataExtractor(DiagnosticReporter reporter,
-      Map<Id, ActualData<String>> actualMap, this.elementMap)
+      Map<Id, ActualData<String>> actualMap, this.elementMap, this.member)
       : super(reporter, actualMap);
 
   @override
   String computeNodeValue(Id id, ir.TreeNode node) {
     if (node is ir.ConstantExpression) {
-      return constantToText(elementMap.getConstantValue(node));
+      return constantToText(elementMap.getConstantValue(
+          elementMap.getStaticTypeContext(member), node));
     }
     return null;
   }
diff --git a/tests/compiler/dart2js/model/type_substitution_test.dart b/tests/compiler/dart2js/model/type_substitution_test.dart
index 35730ab..85c5784 100644
--- a/tests/compiler/dart2js/model/type_substitution_test.dart
+++ b/tests/compiler/dart2js/model/type_substitution_test.dart
@@ -121,24 +121,24 @@
       """);
   InterfaceType Class_T_S = env["Class"];
   Expect.isNotNull(Class_T_S);
-  Expect.isTrue(Class_T_S.isInterfaceType);
+  Expect.isTrue(Class_T_S is InterfaceType);
   Expect.equals(2, Class_T_S.typeArguments.length);
 
   DartType T = Class_T_S.typeArguments[0];
   Expect.isNotNull(T);
-  Expect.isTrue(T.isTypeVariable);
+  Expect.isTrue(T is TypeVariableType);
 
   DartType S = Class_T_S.typeArguments[1];
   Expect.isNotNull(S);
-  Expect.isTrue(S.isTypeVariable);
+  Expect.isTrue(S is TypeVariableType);
 
   DartType intType = env['int'];
   Expect.isNotNull(intType);
-  Expect.isTrue(intType.isInterfaceType);
+  Expect.isTrue(intType is InterfaceType);
 
   DartType StringType = env['String'];
   Expect.isNotNull(StringType);
-  Expect.isTrue(StringType.isInterfaceType);
+  Expect.isTrue(StringType is InterfaceType);
 
   ClassEntity ListClass = env.getElement('List');
   ClassEntity MapClass = env.getElement('Map');
diff --git a/tests/compiler/dart2js/rti/emission/future_or_as_type_argument.dart b/tests/compiler/dart2js/rti/emission/future_or_as_type_argument.dart
index 402f2bc..837f824 100644
--- a/tests/compiler/dart2js/rti/emission/future_or_as_type_argument.dart
+++ b/tests/compiler/dart2js/rti/emission/future_or_as_type_argument.dart
@@ -9,7 +9,7 @@
 /*class: A:checkedInstance,checks=[],instance*/
 class A<T> {}
 
-/*class: B:checks=[],typeArgument*/
+/*class: B:checkedTypeArgument,checks=[],typeArgument*/
 class B {}
 
 /*class: C:checks=[],typeArgument*/
diff --git a/tests/compiler/dart2js/rti/emission/future_or_type_argument.dart b/tests/compiler/dart2js/rti/emission/future_or_type_argument.dart
index 374a758..756d26f 100644
--- a/tests/compiler/dart2js/rti/emission/future_or_type_argument.dart
+++ b/tests/compiler/dart2js/rti/emission/future_or_type_argument.dart
@@ -10,7 +10,7 @@
 /*class: A:checkedInstance,checks=[],instance*/
 class A<T> {}
 
-/*class: B:checks=[],typeArgument*/
+/*class: B:checkedTypeArgument,checks=[],typeArgument*/
 class B {}
 
 /*class: C:checks=[],typeArgument*/
diff --git a/tests/compiler/dart2js/rti/rti_need_test_helper.dart b/tests/compiler/dart2js/rti/rti_need_test_helper.dart
index 1514c94..32be3c8 100644
--- a/tests/compiler/dart2js/rti/rti_need_test_helper.dart
+++ b/tests/compiler/dart2js/rti/rti_need_test_helper.dart
@@ -204,6 +204,12 @@
   bool visitType(DartType type, _) => false;
 
   @override
+  bool visitLegacyType(LegacyType type, _) => visit(type.baseType, _);
+
+  @override
+  bool visitNullableType(NullableType type, _) => visit(type.baseType, _);
+
+  @override
   bool visitInterfaceType(InterfaceType type, _) {
     if (type.element == entity) return true;
     return visitTypes(type.typeArguments);
diff --git a/tests/compiler/dart2js/static_type/static_type_test.dart b/tests/compiler/dart2js/static_type/static_type_test.dart
index c546b5f..ae9d9de 100644
--- a/tests/compiler/dart2js/static_type/static_type_test.dart
+++ b/tests/compiler/dart2js/static_type/static_type_test.dart
@@ -32,13 +32,14 @@
 class StaticTypeDataComputer extends DataComputer<String> {
   ir.TypeEnvironment _typeEnvironment;
 
-  ir.TypeEnvironment getTypeEnvironment(KernelToElementMapImpl elementMap) {
+  ir.StaticTypeContext getStaticTypeContext(
+      KernelToElementMapImpl elementMap, ir.Member node) {
     if (_typeEnvironment == null) {
       ir.Component component = elementMap.env.mainComponent;
       _typeEnvironment = new ir.TypeEnvironment(
           new ir.CoreTypes(component), new ir.ClassHierarchy(component));
     }
-    return _typeEnvironment;
+    return new ir.StaticTypeContext(node, _typeEnvironment);
   }
 
   /// Compute type inference data for [member] from kernel based inference.
@@ -56,9 +57,11 @@
             compiler.reporter,
             actualMap,
             new CachedStaticType(
-                getTypeEnvironment(elementMap),
+                getStaticTypeContext(elementMap, node),
                 staticTypeCache,
-                new ThisInterfaceType.from(node.enclosingClass?.thisType)))
+                new ThisInterfaceType.from(node.enclosingClass?.getThisType(
+                    _typeEnvironment.coreTypes,
+                    node.enclosingLibrary.nonNullable))))
         .run(node);
   }
 
diff --git a/tests/compiler/dart2js_extra/empty_negative_test.dart b/tests/compiler/dart2js_extra/empty_negative_test.dart
deleted file mode 100644
index 8b13789..0000000
--- a/tests/compiler/dart2js_extra/empty_negative_test.dart
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/tests/compiler/dart2js_extra/timer_negative_test.dart b/tests/compiler/dart2js_extra/timer_negative_test.dart
deleted file mode 100644
index 8d5c850..0000000
--- a/tests/compiler/dart2js_extra/timer_negative_test.dart
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2012, 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:isolate';
-
-import 'async_helper.dart';
-
-void test(void onDone(bool success)) {
-  Duration ms = const Duration(milliseconds: 1);
-  int expected = 4;
-
-  void timerCallback() {
-    if (--expected == 0) onDone(false);
-  }
-
-  new Timer(ms * 0, timerCallback);
-  new Timer(ms * 10, timerCallback);
-  new Timer(ms * 100, timerCallback);
-  new Timer(ms * 1000, timerCallback);
-}
-
-main() {
-  asyncTest(test);
-}
diff --git a/tests/corelib/apply2_test.dart b/tests/corelib/apply2_test.dart
new file mode 100644
index 0000000..4973e87
--- /dev/null
+++ b/tests/corelib/apply2_test.dart
@@ -0,0 +1,96 @@
+// Copyright (c) 2012, 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";
+
+apply(Function function, List? positional, Map<Symbol, dynamic>? named) {
+  return Function.apply(function, positional, named);
+}
+
+void throwsNSME(
+    Function function, List? positional, Map<Symbol, dynamic>? named) {
+  Expect.throwsNoSuchMethodError(() => apply(function, positional, named));
+}
+
+main() {
+  var c1 = () => 'c1';
+  var c2 = (a) => 'c2 $a';
+  var c3 = ([a = 1]) => 'c3 $a';
+  var c4 = ({a: 1}) => 'c4 $a';
+  var c5 = ({a: 1, b: 2}) => 'c5 $a $b';
+  var c6 = ({b: 1, a: 2}) => 'c6 $a $b';
+  var c7 = (x, {b: 1, a: 2}) => 'c7 $x $a $b';
+  var c8 = (x, y, [a = 2, b = 3]) => 'c8 $x $y $a $b';
+
+  Expect.equals('c1', apply(c1, null, null));
+  Expect.equals('c1', apply(c1, [], null));
+  Expect.equals('c1', apply(c1, [], {}));
+  Expect.equals('c1', apply(c1, null, {}));
+  throwsNSME(c1, [1], null);
+  throwsNSME(c1, [1], {#a: 2});
+  throwsNSME(c1, null, {#a: 2});
+
+  Expect.equals('c2 1', apply(c2, [1], null));
+  Expect.equals('c2 1', apply(c2, [1], {}));
+  throwsNSME(c2, null, null);
+  throwsNSME(c2, [], null);
+  throwsNSME(c2, null, {});
+  throwsNSME(c2, null, {#a: 1});
+  throwsNSME(c2, [2], {#a: 1});
+
+  Expect.equals('c3 1', apply(c3, null, null));
+  Expect.equals('c3 1', apply(c3, [], null));
+  Expect.equals('c3 2', apply(c3, [2], {}));
+  throwsNSME(c3, [1, 2], null);
+  throwsNSME(c3, null, {#a: 1});
+
+  Expect.equals('c4 1', apply(c4, [], null));
+  Expect.equals('c4 2', apply(c4, [], {#a: 2}));
+  Expect.equals('c4 1', apply(c4, null, null));
+  Expect.equals('c4 1', apply(c4, [], {}));
+  throwsNSME(c4, [1], {#a: 1});
+  throwsNSME(c4, [1], {});
+  throwsNSME(c4, [], {#a: 1, #b: 2});
+
+  Expect.equals('c5 1 2', apply(c5, [], null));
+  Expect.equals('c5 3 2', apply(c5, [], {#a: 3}));
+  Expect.equals('c5 1 2', apply(c5, null, null));
+  Expect.equals('c5 1 2', apply(c5, [], {}));
+  Expect.equals('c5 3 4', apply(c5, [], {#a: 3, #b: 4}));
+  Expect.equals('c5 4 3', apply(c5, [], {#b: 3, #a: 4}));
+  Expect.equals('c5 1 3', apply(c5, [], {#b: 3}));
+  throwsNSME(c5, [1], {#a: 1});
+  throwsNSME(c5, [1], {});
+  throwsNSME(c5, [], {#a: 1, #b: 2, #c: 3});
+
+  Expect.equals('c6 2 1', apply(c6, [], null));
+  Expect.equals('c6 3 1', apply(c6, [], {#a: 3}));
+  Expect.equals('c6 2 1', apply(c6, null, null));
+  Expect.equals('c6 2 1', apply(c6, [], {}));
+  Expect.equals('c6 3 4', apply(c6, [], {#a: 3, #b: 4}));
+  Expect.equals('c6 4 3', apply(c6, [], {#b: 3, #a: 4}));
+  Expect.equals('c6 2 3', apply(c6, [], {#b: 3}));
+  throwsNSME(c6, [1], {#a: 1});
+  throwsNSME(c6, [1], {});
+  throwsNSME(c6, [], {#a: 1, #b: 2, #c: 3});
+
+  Expect.equals('c7 7 2 1', apply(c7, [7], null));
+  Expect.equals('c7 7 3 1', apply(c7, [7], {#a: 3}));
+  Expect.equals('c7 7 2 1', apply(c7, [7], {}));
+  Expect.equals('c7 7 3 4', apply(c7, [7], {#a: 3, #b: 4}));
+  Expect.equals('c7 7 4 3', apply(c7, [7], {#b: 3, #a: 4}));
+  Expect.equals('c7 7 2 3', apply(c7, [7], {#b: 3}));
+  throwsNSME(c7, [], {#a: 1});
+  throwsNSME(c7, [], {});
+  throwsNSME(c7, [7], {#a: 1, #b: 2, #c: 3});
+
+  Expect.equals('c8 7 8 2 3', apply(c8, [7, 8], null));
+  Expect.equals('c8 7 8 2 3', apply(c8, [7, 8], {}));
+  Expect.equals('c8 7 8 3 3', apply(c8, [7, 8, 3], null));
+  Expect.equals('c8 7 8 3 4', apply(c8, [7, 8, 3, 4], null));
+  throwsNSME(c8, [], null);
+  throwsNSME(c8, [], {});
+  throwsNSME(c8, [1], null);
+  throwsNSME(c8, [7, 8, 9, 10, 11], null);
+}
diff --git a/tests/corelib/apply3_test.dart b/tests/corelib/apply3_test.dart
new file mode 100644
index 0000000..5bf1bce
--- /dev/null
+++ b/tests/corelib/apply3_test.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2013, 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 [Function.apply] on user-defined classes that implement [noSuchMethod].
+
+import "package:expect/expect.dart";
+
+class F {
+  call([p1]) => "call";
+  noSuchMethod(Invocation invocation) => "NSM";
+}
+
+class G {
+  call() => '42';
+  noSuchMethod(Invocation invocation) => invocation;
+}
+
+class H {
+  call(required, {a}) => required + a;
+}
+
+main() {
+  Expect.equals('call', Function.apply(new F(), []));
+  Expect.equals('call', Function.apply(new F(), [1]));
+  Expect.throwsNoSuchMethodError(() => Function.apply(new F(), [1, 2]));
+  Expect.throwsNoSuchMethodError(() => Function.apply(new F(), [1, 2, 3]));
+
+  Expect.throwsNoSuchMethodError(() => Function.apply(new G(), [1], {#a: 42}));
+
+  // Test that [i] can be used to hit an existing method.
+  Expect.equals(43, new H().call(1, a: 42));
+  Expect.equals(43, Function.apply(new H(), [1], {#a: 42}));
+}
diff --git a/tests/corelib/apply4_test.dart b/tests/corelib/apply4_test.dart
new file mode 100644
index 0000000..fba4b9d
--- /dev/null
+++ b/tests/corelib/apply4_test.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2015, 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";
+
+// Testing Function.apply calls work correctly for arities that are not
+// otherwise present in the program (and thus might not have stubs
+// generated).
+
+class A {
+  foo(x, [y, z, a, b, c, d = 99, e, f, g, h, i, j]) => "$x $d";
+}
+
+main() {
+  var a = new A();
+  var clos = a.foo;
+  Expect.equals(Function.apply(clos, ["well"]), "well 99");
+  Expect.equals(Function.apply(clos, ["well", 0, 2, 4, 3, 6, 9, 10]), "well 9");
+}
diff --git a/tests/corelib/apply5_test.dart b/tests/corelib/apply5_test.dart
new file mode 100644
index 0000000..5435f10
--- /dev/null
+++ b/tests/corelib/apply5_test.dart
@@ -0,0 +1,23 @@
+// 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.
+
+import "package:expect/expect.dart";
+
+// Testing that, when compiled to JS, Function.apply works correctly for
+// functions with that will be invoked directly vs using .apply().
+
+class A {
+  foo([a = 10, b = 20, c = 30, d = 40, e = 50]) => "$a $b $c $d $e";
+}
+
+main() {
+  var a = new A();
+  var clos = a.foo;
+  Expect.equals(Function.apply(clos, []), "10 20 30 40 50");
+  Expect.equals(Function.apply(clos, [11]), "11 20 30 40 50");
+  Expect.equals(Function.apply(clos, [11, 21]), "11 21 30 40 50");
+  Expect.equals(Function.apply(clos, [11, 21, 31]), "11 21 31 40 50");
+  Expect.equals(Function.apply(clos, [11, 21, 31, 41]), "11 21 31 41 50");
+  Expect.equals(Function.apply(clos, [11, 21, 31, 41, 51]), "11 21 31 41 51");
+}
diff --git a/tests/corelib/apply_generic_function_test.dart b/tests/corelib/apply_generic_function_test.dart
new file mode 100644
index 0000000..b9e6e3e
--- /dev/null
+++ b/tests/corelib/apply_generic_function_test.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2018, 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";
+import "symbol_map_helper.dart";
+
+// Testing Function.apply calls correctly with generic type arguments.
+// This test is not testing error handling, only that correct parameters
+// cause a correct call.
+
+test0<T extends num>(T i, T j, {required T a}) => i + j + a;
+
+main() {
+  test(res, func, list, map) {
+    map = symbolMapToStringMap(map);
+    Expect.equals(res, Function.apply(func, list, map));
+  }
+
+  test(42, test0, [10, 15], {"a": 17});
+}
diff --git a/tests/corelib/apply_test.dart b/tests/corelib/apply_test.dart
new file mode 100644
index 0000000..0958dab
--- /dev/null
+++ b/tests/corelib/apply_test.dart
@@ -0,0 +1,78 @@
+// Copyright (c) 2012, 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";
+import "symbol_map_helper.dart";
+
+// Testing Function.apply calls correctly.
+// This test is not testing error handling, only that correct parameters
+// cause a correct call.
+
+int test0() => 42;
+int test0a({required int a}) => 37 + a;
+int test1(int i) => i + 1;
+int test1a(int i, {required int a}) => i + a;
+int test2(int i, int j) => i + j;
+int test2a(int i, int j, {required int a}) => i + j + a;
+
+class C {
+  int x = 10;
+  int foo(int y) => this.x + y;
+}
+
+class Callable {
+  int call(int x, int y) => x + y;
+}
+
+@pragma('dart2js:noInline')
+@pragma('dart2js:assumeDynamic')
+confuse(x) => x;
+
+main() {
+  testMap(res, func, map) {
+    Expect.equals(res, Function.apply(func, null, map));
+    Expect.equals(res, Function.apply(func, [], map));
+  }
+
+  testList(res, func, list) {
+    Expect.equals(res, Function.apply(func, list));
+    Expect.equals(res, Function.apply(func, list, null));
+    Expect.equals(res, Function.apply(func, list, new Map<Symbol, dynamic>()));
+  }
+
+  testListTyped(res, Function func, list) => testList(res, func, list);
+
+  test(res, func, list, map) {
+    Expect.equals(res, Function.apply(func, list, map));
+  }
+
+  testList(42, test0, null);
+  testList(42, test0, []);
+  testMap(42, test0a, {#a: 5});
+  testList(42, test1, [41]);
+  test(42, test1a, [20], {#a: 22});
+  testList(42, test2, [20, 22]);
+  test(42, test2a, [10, 15], {#a: 17});
+
+  // Test that "this" is correct when calling closurized functions.
+  var cfoo = new C().foo;
+  testList(42, cfoo, [32]);
+
+  // Test that apply works even with a different name.
+  var app = confuse(Function.apply);
+  Expect.equals(42, app(test2, [22, 20]));
+
+  // Test that apply can itself be applied.
+  Expect.equals(
+      42,
+      Function.apply(Function.apply, [
+        test2,
+        [17, 25]
+      ]));
+
+  // Test that apply works on callable objects when it is passed to a method
+  // that expects Function (and not dynamic).
+  Expect.throws(() => testList(42, new Callable(), [13, 29])); //# 01: ok
+  testListTyped(42, new Callable(), [13, 29]); //# 02: ok
+}
diff --git a/tests/corelib/corelib.status b/tests/corelib/corelib.status
new file mode 100644
index 0000000..834728b
--- /dev/null
+++ b/tests/corelib/corelib.status
@@ -0,0 +1,61 @@
+# Copyright (c) 2017, 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.
+
+[ $compiler == dartdevk ]
+regexp/lookbehind_test/01: Skip # Flaky in uncatchable way.  Issue 36280
+
+[ $mode == debug ]
+regexp/pcre_test: Slow # Issue 22008
+
+[ $arch == x64 && $system == windows ]
+stopwatch_test: Skip # Flaky test due to expected performance behaviour.
+
+[ $builder_tag == obfuscated && $runtime == dart_precompiled ]
+apply_generic_function_test: SkipByDesign # Function.apply with named args
+apply_test: Skip # Uses new Symbol via symbolMapToStringMap helper
+dynamic_nosuchmethod_test: SkipByDesign # Expects names in NSM
+error_stack_trace1_test: SkipByDesign # Expects unobfuscated stack trace
+type_tostring_test: SkipByDesign # Expects names in Type.toString()
+
+[ $compiler != dart2analyzer && $compiler != dart2js && $compiler != dartdevc && $compiler != dartdevk ]
+bigint_js_test: SkipByDesign # JavaScript-specific test
+
+[ $compiler == dart2js && $runtime != none ]
+regexp/pcre_test: Slow # Issue 21593
+
+# We no longer expect Dart2 tests to run with the standalone VM without the new
+# common front end, but for now we get better coverage by still running them in
+# checked mode, which is mostly Dart2-compatible.
+[ $compiler == none && !$checked && ($runtime == dart_precompiled || $runtime == vm) ]
+*: SkipByDesign
+
+[ $runtime != none && ($compiler == dart2js || $compiler == dartdevc || $compiler == dartdevk) ]
+int_parse_with_limited_ints_test: Skip # Requires fixed-size int64 support.
+typed_data_with_limited_ints_test: Skip # Requires fixed-size int64 support.
+
+[ $arch == simarm || $arch == simarm64 ]
+bigint_parse_radix_test: Skip # Issue 31659
+bigint_test: Skip # Issue 31659
+
+[ $compiler == dartdevc || $compiler == dartdevk ]
+bigint_test/03: SkipSlow # modPow is very slow
+bigint_test/15: SkipSlow # modPow is very slow
+int_parse_with_limited_ints_test: Skip # Requires fixed-size int64 support.
+typed_data_with_limited_ints_test: Skip # Requires fixed-size int64 support.
+uri_parse_test: Slow
+uri_test: Slow
+
+[ $compiler == dartkb || $compiler == dartkp ]
+bigint_parse_radix_test: Slow # --no_intrinsify
+bigint_test/03: SkipSlow # --no_intrinsify
+bigint_test/15: SkipSlow # --no_intrinsify
+
+[ $runtime == dart_precompiled || $runtime == vm ]
+regexp/global_test: Skip # Issue 21709
+regexp/pcre_test: Slow
+
+[ $hot_reload || $hot_reload_rollback ]
+bigint_parse_radix_test: Skip # Issue 31659. Issue 34361.
+bigint_test: Skip # Issue 31659
+integer_parsed_mul_div_vm_test: Slow # Slow
diff --git a/tests/corelib_2/date_time_parse_test.dart b/tests/corelib_2/date_time_parse_test.dart
index 6b3d58d..23b8b02 100644
--- a/tests/corelib_2/date_time_parse_test.dart
+++ b/tests/corelib_2/date_time_parse_test.dart
@@ -17,14 +17,14 @@
   check(new DateTime(2012, 02, 27, 13, 27), "2012-02-27 13:27:00");
   if (supportsMicroseconds) {
     check(new DateTime.utc(2012, 02, 27, 13, 27, 0, 123, 456),
-        "2012-02-27 13:27:00.123456z");
+        "2012-02-27 13:27:00.1234567891234z");
     check(new DateTime.utc(2012, 02, 27, 13, 27, 0, 123, 456),
-        "2012-02-27 13:27:00,123456z");
+        "2012-02-27 13:27:00,1234567891234z");
   } else {
-    check(new DateTime.utc(2012, 02, 27, 13, 27, 0, 123, 456),
-        "2012-02-27 13:27:00.123z");
-    check(new DateTime.utc(2012, 02, 27, 13, 27, 0, 123, 456),
-        "2012-02-27 13:27:00,123z");
+    check(new DateTime.utc(2012, 02, 27, 13, 27, 0, 123, 0),
+        "2012-02-27 13:27:00.1234567891234z");
+    check(new DateTime.utc(2012, 02, 27, 13, 27, 0, 123, 0),
+        "2012-02-27 13:27:00,1234567891234z");
   }
   check(new DateTime(2012, 02, 27, 13, 27), "20120227 13:27:00");
   check(new DateTime(2012, 02, 27, 13, 27), "20120227T132700");
diff --git a/tests/language/aborting_switch_case_test.dart b/tests/language/aborting_switch_case_test.dart
new file mode 100644
index 0000000..b8c7fe4
--- /dev/null
+++ b/tests/language/aborting_switch_case_test.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2013, 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.
+
+// Regression test for dart2js that used to be confused when inlining
+// method that always aborts in a switch case.
+
+import "package:expect/expect.dart";
+
+foo() {
+  throw 42;
+}
+
+main() {
+  var exception;
+  try {
+    switch (42) {
+      case 42:
+        foo();
+        foo();
+        break;
+    }
+  } catch (e) {
+    exception = e;
+  }
+  Expect.equals(42, exception);
+}
diff --git a/tests/language/abstract_beats_arguments_test.dart b/tests/language/abstract_beats_arguments_test.dart
new file mode 100644
index 0000000..d6687b4
--- /dev/null
+++ b/tests/language/abstract_beats_arguments_test.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2015, 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";
+
+// TODO(rnystrom): This test should be renamed since now it's just about
+// testing that constructing an abstract class generates an error.
+
+abstract class A {
+  A() {}
+}
+
+void main() {
+  /*@compile-error=unspecified*/ new A();
+}
diff --git a/tests/language/abstract_equal_test.dart b/tests/language/abstract_equal_test.dart
new file mode 100644
index 0000000..bcfb3e8
--- /dev/null
+++ b/tests/language/abstract_equal_test.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2019, 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 {
+  bool operator ==(other);
+  const A();
+}
+
+class B implements A {
+  const B();
+}
+
+class C extends A {
+  const C();
+}
+
+class Invalid {
+  bool operator ==(other) => false;
+  const Invalid();
+}
+
+class D implements Invalid {
+  const D();
+}
+
+main() {
+  print(const {A(): 1});
+  print(const {B(): 2});
+  print(const {C(): 3});
+  print(const {D(): 4});
+}
diff --git a/tests/language/abstract_exact_selector_test.dart b/tests/language/abstract_exact_selector_test.dart
new file mode 100644
index 0000000..a35adda
--- /dev/null
+++ b/tests/language/abstract_exact_selector_test.dart
@@ -0,0 +1,38 @@
+// Copyright (c) 2013, 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.
+
+// Regression test for dart2js that used to duplicate some `Object`
+// methods to handle `noSuchMethod`.
+
+import "package:expect/expect.dart";
+import "compiler_annotations.dart";
+
+abstract //# 01: compile-time error
+    class Foo {
+  noSuchMethod(im) => 42;
+}
+
+@DontInline()
+returnFoo() {
+  (() => 42)();
+  return new Foo();
+}
+
+class Bar {
+  operator ==(other) => false;
+}
+
+var a = [false, true, new Object(), new Bar()];
+
+main() {
+  if (a[0] as bool) {
+    // This `==` call will make the compiler create a selector with an
+    // exact `TypeMask` of `Foo`. Since `Foo` is abstract, such a call
+    // cannot happen, but we still used to generate a `==` method on
+    // the `Object` class to handle `noSuchMethod`.
+    print(returnFoo() == 42);
+  } else {
+    Expect.isFalse(a[2] == 42);
+  }
+}
diff --git a/tests/language/abstract_factory_constructor_test.dart b/tests/language/abstract_factory_constructor_test.dart
new file mode 100644
index 0000000..90713ca
--- /dev/null
+++ b/tests/language/abstract_factory_constructor_test.dart
@@ -0,0 +1,31 @@
+// Copyright (c) 2012, 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 test program for constructors and initializers.
+
+// Exercises issue 2282, factory constructors in abstract classes should
+// not emit a static type warning
+
+class B extends A1 {
+  B() {}
+  method() {}
+}
+
+abstract class A1 {
+  A1() {}
+  method(); // Abstract.
+  factory A1.make() {
+    return new B();
+  }
+}
+
+class A2 {
+  // Intentionally abstract method.
+  method(); //# 00: compile-time error
+  A2.make() {}
+}
+
+main() {
+  new A1.make();
+  new A2.make(); //# 00: continued
+}
diff --git a/tests/language/abstract_getter2_test.dart b/tests/language/abstract_getter2_test.dart
new file mode 100644
index 0000000..e1240c5
--- /dev/null
+++ b/tests/language/abstract_getter2_test.dart
@@ -0,0 +1,66 @@
+// 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.
+
+import "package:expect/expect.dart";
+
+class A {
+  int get x => 100;
+}
+
+abstract class B extends A {
+  int _x = 0;
+
+  int get x;
+  set x(int v) {
+    _x = v;
+  }
+}
+
+class C extends B {
+  int get x => super.x;
+}
+
+class GetterConcrete {
+  var _foo;
+
+  get foo => _foo;
+  set foo(x) => _foo = x;
+
+  var _bar;
+
+  get bar => _bar;
+  set bar(x) => _bar = x;
+}
+
+class AbstractGetterOverride1 extends GetterConcrete {
+  get foo;
+  set bar(x);
+}
+
+class AbstractGetterOverride2 extends Object with GetterConcrete {
+  get foo;
+  set bar(x);
+}
+
+void main() {
+  B b = new C();
+  b.x = 42;
+  Expect.equals(b._x, 42);
+  Expect.equals(b.x, 100);
+
+  /// Tests that overriding either the getter or setter with an abstract member
+  /// has no effect.
+  /// Regression test for https://github.com/dart-lang/sdk/issues/29914
+  var c1 = AbstractGetterOverride1()
+    ..foo = 123
+    ..bar = 456;
+  Expect.equals(c1.foo, 123);
+  Expect.equals(c1.bar, 456);
+
+  var c2 = AbstractGetterOverride2()
+    ..foo = 123
+    ..bar = 456;
+  Expect.equals(c2.foo, 123);
+  Expect.equals(c2.bar, 456);
+}
diff --git a/tests/language/abstract_getter_test.dart b/tests/language/abstract_getter_test.dart
new file mode 100644
index 0000000..73d43a3
--- /dev/null
+++ b/tests/language/abstract_getter_test.dart
@@ -0,0 +1,25 @@
+// Copyright (c) 2012, 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 to ensure that an abstract getter is not mistaken for a field.
+
+class Foo {
+  // Intentionally abstract:
+  get i; //# 01: compile-time error
+}
+
+class Bar {}
+
+checkIt(f) {
+  Expect.throwsNoSuchMethodError(() => f.i = 'hi'); // //# 01: continued
+  Expect.throwsNoSuchMethodError(() => print(f.i)); // //# 01: continued
+  Expect.throwsNoSuchMethodError(() => print(f.i())); // //# 01: continued
+}
+
+main() {
+  checkIt(new Foo());
+  checkIt(new Bar());
+}
diff --git a/tests/language/abstract_method_test.dart b/tests/language/abstract_method_test.dart
new file mode 100644
index 0000000..4532789
--- /dev/null
+++ b/tests/language/abstract_method_test.dart
@@ -0,0 +1,45 @@
+// Copyright (c) 2014, 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";
+
+// Checks that abstract instance methods are correctly resolved.
+
+int get length => throw "error: top-level getter called";
+set height(x) {
+  throw "error: top-level setter called";
+}
+
+width() {
+  throw "error: top-level function called";
+}
+
+abstract class A {
+  int get length; //    Abstract instance getter.
+  set height(int x); // Abstract instance setter.
+  int width(); //       Abstract instance method.
+
+  // Must resolve to non-abstract length getter in subclass.
+  get useLength => length;
+  // Must resolve to non-abstract height setter in subclass.
+  setHeight(x) => height = x;
+  // Must resolve to non-abstract width() method in subclass.
+  useWidth() => width();
+}
+
+class A1 extends A {
+  int length; // Implies a length getter.
+  int? height; // Implies a height setter.
+  int width() => 345;
+  A1(this.length);
+}
+
+main() {
+  var a = new A1(123);
+  Expect.equals(123, a.useLength);
+  a.setHeight(234);
+  Expect.equals(234, a.height);
+  Expect.equals(345, a.useWidth());
+  print([a.useLength, a.height, a.useWidth()]);
+}
diff --git a/tests/language/abstract_object_method_test.dart b/tests/language/abstract_object_method_test.dart
new file mode 100644
index 0000000..2d4af77c
--- /dev/null
+++ b/tests/language/abstract_object_method_test.dart
@@ -0,0 +1,25 @@
+// Copyright (c) 2013, 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";
+
+class A {
+  noSuchMethod(_) {
+    Expect.fail('Should not reach here');
+  }
+}
+
+class B extends A {
+  operator ==(other);
+}
+
+class C extends B {}
+
+var a = [new C()];
+
+main() {
+  C c = a[0];
+  a.add(c);
+  Expect.isTrue(c == a[1]);
+}
diff --git a/tests/language/abstract_override_adds_optional_args_concrete_subclass_test.dart b/tests/language/abstract_override_adds_optional_args_concrete_subclass_test.dart
new file mode 100644
index 0000000..12a023f
--- /dev/null
+++ b/tests/language/abstract_override_adds_optional_args_concrete_subclass_test.dart
@@ -0,0 +1,28 @@
+// Copyright (c) 2017, 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 {
+  void foo() {}
+}
+
+abstract class B extends A {
+  // If this class were concrete, there would be a problem, since `new
+  // B().foo(42)` would be statically allowed, but would lead to invalid
+  // arguments being passed to A.foo.  But since the class is abstract, there is
+  // no problem.
+  void foo([x]);
+}
+
+class /*@compile-error=unspecified*/ C extends B {
+  // However, there is a problem here because this class is concrete and doesn't
+  // override foo.
+}
+
+void f(B b) {
+  b.foo();
+}
+
+main() {
+  f(new C());
+}
diff --git a/tests/language/abstract_override_adds_optional_args_concrete_test.dart b/tests/language/abstract_override_adds_optional_args_concrete_test.dart
new file mode 100644
index 0000000..b8232e8
--- /dev/null
+++ b/tests/language/abstract_override_adds_optional_args_concrete_test.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2017, 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 {
+  void foo() {}
+}
+
+class B extends A {
+  // This class declaration violates soundness, since it allows `new
+  // B().foo(42)`, which would lead to invalid arguments being passed to A.foo.
+  void /*@compile-error=unspecified*/ foo([x]);
+}
+
+void f(B b) {
+  b.foo();
+}
+
+main() {
+  f(new B());
+}
diff --git a/tests/language/abstract_override_adds_optional_args_supercall_test.dart b/tests/language/abstract_override_adds_optional_args_supercall_test.dart
new file mode 100644
index 0000000..2a2bf3e
--- /dev/null
+++ b/tests/language/abstract_override_adds_optional_args_supercall_test.dart
@@ -0,0 +1,31 @@
+// Copyright (c) 2017, 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 {
+  void foo() {}
+}
+
+abstract class B extends A {
+  // If this class were concrete, there would be a problem, since `new
+  // B().foo(42)` would be statically allowed, but would lead to invalid
+  // arguments being passed to A.foo.  But since the class is abstract, there is
+  // no problem.
+  void foo([x]);
+}
+
+class C extends B {
+  void foo([x]) {
+    // But it is a problem to try to pass `x` along to super, since the super
+    // method is A.foo.
+    super.foo(/*@compile-error=unspecified*/ x);
+  }
+}
+
+void f(B b) {
+  b.foo(42);
+}
+
+main() {
+  f(new C());
+}
diff --git a/tests/language/abstract_override_adds_optional_args_test.dart b/tests/language/abstract_override_adds_optional_args_test.dart
new file mode 100644
index 0000000..d139307
--- /dev/null
+++ b/tests/language/abstract_override_adds_optional_args_test.dart
@@ -0,0 +1,33 @@
+// Copyright (c) 2017, 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.
+
+// This test exercises a corner case of override checking that is safe from a
+// soundness perspective, but which we haven't decided whether or not to allow
+// from a usability perspective.
+
+class A {
+  void foo() {}
+}
+
+abstract class B extends A {
+  // If this class were concrete, there would be a problem, since `new
+  // B().foo(42)` would be statically allowed, but would lead to invalid
+  // arguments being passed to A.foo.  But since the class is abstract, there is
+  // no problem.
+  void foo([x]);
+}
+
+class C extends B {
+  void foo([x]) {
+    super.foo();
+  }
+}
+
+void f(B b) {
+  b.foo(42);
+}
+
+main() {
+  f(new C());
+}
diff --git a/tests/language/abstract_syntax_test.dart b/tests/language/abstract_syntax_test.dart
new file mode 100644
index 0000000..fba3725
--- /dev/null
+++ b/tests/language/abstract_syntax_test.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2012, 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";
+
+main() {
+  var b = new B();
+  Expect.equals(42, b.foo());
+}
+
+class A {
+  foo(); // //# 00: compile-time error
+  static bar(); // //# 01: syntax error
+}
+
+class B extends A {
+  foo() => 42;
+  bar() => 87;
+}
diff --git a/tests/language/compiler_annotations.dart b/tests/language/compiler_annotations.dart
new file mode 100644
index 0000000..c920add
--- /dev/null
+++ b/tests/language/compiler_annotations.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2013, 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.
+
+library compiler_annotations;
+
+// This library contains annotations useful for testing.
+
+// TODO(ngeoffray): Implement in dart2js.
+class DontInline {
+  const DontInline();
+}
diff --git a/tests/language/language.status b/tests/language/language.status
new file mode 100644
index 0000000..796193b
--- /dev/null
+++ b/tests/language/language.status
@@ -0,0 +1,46 @@
+# Copyright (c) 2017, 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.
+
+[ $compiler != dart2analyzer ]
+switch_case_warn_test: Skip # Analyzer only, see language_analyzer2.status
+
+[ $compiler != fasta ]
+nonfunction_type_aliases/*: Skip # github.com/dart-lang/language/issues/115
+
+[ $compiler == none ]
+invalid_returns/*: Skip # https://github.com/dart-lang/sdk/issues/34013
+void/*: Skip # https://github.com/dart-lang/sdk/issues/34013
+
+[ $compiler == spec_parser ]
+double_literals/*: Skip # https://github.com/dart-lang/sdk/issues/34355
+invalid_returns/*: Skip # https://github.com/dart-lang/sdk/issues/34015
+mixin_declaration/*: Skip # See https://github.com/dart-lang/language/issues/7
+void/*: Skip # https://github.com/dart-lang/sdk/issues/34015
+
+[ $mode == debug ]
+large_class_declaration_test: Slow
+
+[ $mode == product ]
+assertion_test: SkipByDesign # Requires checked mode.
+generic_test: SkipByDesign # Requires checked mode.
+issue13474_test: SkipByDesign # Requires checked mode.
+map_literal4_test: SkipByDesign # Requires checked mode.
+named_parameters_type_test/01: SkipByDesign # Requires checked mode.
+named_parameters_type_test/02: SkipByDesign # Requires checked mode.
+named_parameters_type_test/03: SkipByDesign # Requires checked mode.
+positional_parameters_type_test/01: SkipByDesign # Requires checked mode.
+positional_parameters_type_test/02: SkipByDesign # Requires checked mode.
+regress_29784_test/02: SkipByDesign # Requires checked mode.
+stacktrace_demangle_ctors_test: SkipByDesign # Names are not scrubbed.
+type_checks_in_factory_method_test: SkipByDesign # Requires checked mode.
+
+[ $compiler != dart2js && $compiler != dartdevc && !$checked ]
+function_type/*: Skip # Needs checked mode.
+
+[ $compiler != dartk && $compiler != dartkb && $compiler != dartkp && $mode == debug && $runtime == vm ]
+built_in_identifier_type_annotation_test/set: Crash # Not supported by legacy VM front-end.
+
+[ $hot_reload || $hot_reload_rollback ]
+issue_22780_test/01: Crash # Issue 29094
+vm/optimized_stacktrace_test: Slow
diff --git a/tests/language/language_analyzer.status b/tests/language/language_analyzer.status
new file mode 100644
index 0000000..372d94b
--- /dev/null
+++ b/tests/language/language_analyzer.status
@@ -0,0 +1,11 @@
+# Copyright (c) 2017, 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.
+
+# Sections in this file should contain "$compiler == dart2analyzer".
+
+[ $compiler == dart2analyzer ]
+large_class_declaration_test: Slow
+vm/debug_break_enabled_vm_test: Skip
+vm/debug_break_vm_test/*: Skip
+vm/regress_27201_test: SkipByDesign # Loads bad library, so will always crash.
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
new file mode 100644
index 0000000..64bc2b8
--- /dev/null
+++ b/tests/language/language_dart2js.status
@@ -0,0 +1,31 @@
+# Copyright (c) 2017, 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.
+# Sections in this file should contain "$compiler == dart2js".
+
+[ $compiler == dart2js ]
+mixin_method_override_test/G5: Skip # Issue 34354
+vm/*: SkipByDesign # Tests for the VM.
+
+[ $compiler != dart2js ]
+minify_closure_variable_collision_test: SkipByDesign # Regression test for dart2js
+
+[ $builder_tag == dart2js_production && $compiler == dart2js ]
+control_flow_collections/for_non_bool_condition_test: Crash # Issue 36442
+
+[ $compiler == dart2js && $runtime == chromeOnAndroid ]
+override_field_test/02: Slow # TODO(kasperl): Please triage.
+
+[ $compiler == dart2js && $runtime == d8 ]
+conditional_import_string_test: SkipByDesign # No XHR in d8
+conditional_import_test: SkipByDesign # No XHR in d8
+
+[ $compiler == dart2js && $runtime == jsshell ]
+await_for_test: Skip # Jsshell does not provide periodic timers, Issue 7728
+
+[ $compiler == dart2js && $system == windows ]
+canonicalization_hashing_memoize_array_test: Skip # Issue 37631
+canonicalization_hashing_memoize_instance_test: Skip # Issue 37631
+canonicalization_hashing_shallow_collision_array_test: Skip # Issue 37631
+canonicalization_hashing_shallow_collision_instance_test: Skip # Issue 37631
+
diff --git a/tests/language/language_dartdevc.status b/tests/language/language_dartdevc.status
new file mode 100644
index 0000000..1aed49b
--- /dev/null
+++ b/tests/language/language_dartdevc.status
@@ -0,0 +1,23 @@
+# Copyright (c) 2017, 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.
+
+# Sections in this file should contain "$compiler == dartdevc" or dartdevk.
+[ $compiler == dartdevc ]
+const_double_in_int_op_test/dd6: Skip # Triple shift
+const_double_in_int_op_test/di6: Skip # Triple shift
+const_double_in_int_op_test/id6: Skip # Triple shift
+const_double_in_int_op_test/ii6: Skip # Triple shift
+extension_methods/*: SkipByDesign # Analyzer DDC is expected to be turned down before releasing extension methods.
+large_class_declaration_test: Slow
+nnbd/*: Skip
+variance/*: SkipByDesign # Analyzer DDC is expected to be turned down before releasing variance.
+
+[ $compiler == dartdevk && !$checked ]
+assertion_initializer_const_error2_test/*: SkipByDesign # DDC does not support non-checked mode.
+
+[ $compiler == dartdevc || $compiler == dartdevk ]
+asyncstar_throw_in_catch_test: Skip # Times out. Issue 29920
+int64_literal_test/*: Skip # This is testing Dart 2.0 int64 semantics.
+superinterface_variance/*: Skip # Issue dart-lang/language#113
+vm/*: SkipByDesign # VM only tests.; VM only tests.
diff --git a/tests/language/language_kernel.status b/tests/language/language_kernel.status
new file mode 100644
index 0000000..9b43134
--- /dev/null
+++ b/tests/language/language_kernel.status
@@ -0,0 +1,152 @@
+# Copyright (c) 2017, 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.
+
+
+[ $compiler == app_jitk ]
+no_main_test/01: Crash
+vm/regress_27671_test: SkipByDesign # Relies on string comparison of exception message which may return '<optimized out>'
+web_int_literals_test/*: SkipByDesign # Test applies only to JavaScript targets
+
+[ $compiler == dartkp ]
+web_int_literals_test/*: SkipByDesign # Test applies only to JavaScript targets
+
+[ $compiler == fasta ]
+async_await_syntax_test/e5: Crash # Assertion error: continuation.dart: Failed assertion: 'node.expression == null || node.expression is NullLiteral': is not true.
+async_await_syntax_test/e6: Crash # Assertion error: continuation.dart: Failed assertion: 'node.expression == null || node.expression is NullLiteral': is not true.
+web_int_literals_test/*: SkipByDesign # Test applies only to JavaScript targets
+
+[ $fasta ]
+nnbd/*: Skip
+superinterface_variance/abstract_class_error_test/27: Crash # Issue dart-lang/language#113
+superinterface_variance/concrete_class_error_test/27: Crash # Issue dart-lang/language#113
+superinterface_variance/mixin_error_test/27: Crash # Issue dart-lang/language#113
+superinterface_variance/mixin_error_test/37: Crash # Issue dart-lang/language#113
+superinterface_variance/mixin_error_test/38: Crash # Issue dart-lang/language#113
+superinterface_variance/mixin_error_test/40: Crash # Issue dart-lang/language#113
+superinterface_variance/mixin_error_test/41: Crash # Issue dart-lang/language#113
+superinterface_variance/mixin_error_test/42: Crash # Issue dart-lang/language#113
+superinterface_variance/mixin_error_test/43: Crash # Issue dart-lang/language#113
+superinterface_variance/mixin_error_test/44: Crash # Issue dart-lang/language#113
+superinterface_variance/mixin_error_test/46: Crash # Issue dart-lang/language#113
+superinterface_variance/mixin_error_test/47: Crash # Issue dart-lang/language#113
+superinterface_variance/mixin_error_test/48: Crash # Issue dart-lang/language#113
+
+[ $builder_tag == obfuscated && $compiler == dartkp ]
+generic_function_dcall_test/01: SkipByDesign # Prints type names
+many_named_arguments_test: SkipByDesign # Checks names of arguments
+mixin_generic_test: SkipByDesign # Prints type names
+mixin_mixin3_test: SkipByDesign # Prints type names
+mixin_mixin5_test: SkipByDesign # Prints type names
+mixin_mixin6_test: SkipByDesign # Prints type names
+mixin_mixin_bound2_test: SkipByDesign # Prints type names
+symbol_literal_test/02: SkipByDesign # We don't obfuscate const Symbol constructor
+type_literal_test: SkipByDesign # Uses lots of strings with type names in them
+vm/bool_check_stack_traces_test: SkipByDesign # Looks for filenames in stacktrace output
+vm/no_such_args_error_message_vm_test: SkipByDesign # Looks for function name in error message
+vm/no_such_method_error_message_callable_vm_test: SkipByDesign # Expects unobfuscated method names
+vm/no_such_method_error_message_vm_test: SkipByDesign # Looks for unobfuscated name in error message
+vm/regress_28325_test: SkipByDesign # Looks for filename in stack trace
+
+[ $compiler == dartk && $mode == debug && ($hot_reload || $hot_reload_rollback) ]
+inference_enum_list_test: Skip # Issue 35885
+
+[ $compiler == dartkp && $mode == debug && $runtime == dart_precompiled ]
+vm/precompiled_static_initializer_test: Slow
+
+# ==== dartkp + dart_precompiled status lines ====
+[ $compiler == dartkp && $runtime == dart_precompiled ]
+assert_with_type_test_or_cast_test: Crash
+const_evaluation_test: SkipByDesign
+ct_const2_test: Skip # Incompatible flag: --compile_all
+deferred_redirecting_factory_test: Crash # Issue 23408, KernelVM bug: Deferred loading kernel issue 30273.
+deopt_inlined_function_lazy_test: Skip # Incompatible flag: --deoptimize-alot
+enum_mirror_test: SkipByDesign
+export_ambiguous_main_test: Skip # Issue 29895 Fail Issue 14763
+export_double_same_main_test: Skip # Issue 29895 Crash Issue 29895
+field_increment_bailout_test: SkipByDesign
+generic_methods_recursive_bound_test/03: Crash
+hello_dart_test: Skip # Incompatible flag: --compile_all
+implicit_closure_test: Skip # Incompatible flag: --use_slow_path
+instance_creation_in_function_annotation_test: SkipByDesign
+invocation_mirror2_test: SkipByDesign
+invocation_mirror_invoke_on2_test: SkipByDesign
+invocation_mirror_invoke_on_test: SkipByDesign
+issue21079_test: SkipByDesign
+main_not_a_function_test: Skip
+many_overridden_no_such_method_test: SkipByDesign
+mixin_illegal_super_use_test: Skip # Issues 24478 and 23773
+mixin_illegal_superclass_test: Skip # Issues 24478 and 23773
+no_main_test/01: Skip
+no_such_method_test: SkipByDesign
+null_test/mirrors: Skip # Uses mirrors.
+null_test/none: SkipByDesign
+overridden_no_such_method_test: SkipByDesign
+redirecting_factory_reflection_test: SkipByDesign
+regress_13462_0_test: SkipByDesign
+regress_13462_1_test: SkipByDesign
+regress_18535_test: SkipByDesign
+regress_28255_test: SkipByDesign
+vm/causal_async_exception_stack2_test: SkipByDesign
+vm/causal_async_exception_stack_test: SkipByDesign
+vm/closure_memory_retention_test: Skip # KernelVM bug: Hits OOM
+vm/reflect_core_vm_test: SkipByDesign
+vm/regress_27671_test: Skip # Unsupported
+vm/regress_29145_test: Skip # Issue 29145
+
+[ $compiler == dartkp && $runtime == dart_precompiled && $checked ]
+assertion_initializer_const_error2_test/cc01: Crash
+assertion_initializer_const_error2_test/cc02: Crash
+assertion_initializer_const_error2_test/cc03: Crash
+assertion_initializer_const_error2_test/cc04: Crash
+assertion_initializer_const_error2_test/cc05: Crash
+assertion_initializer_const_error2_test/cc06: Crash
+assertion_initializer_const_error2_test/cc07: Crash
+assertion_initializer_const_error2_test/cc08: Crash
+assertion_initializer_const_error2_test/cc09: Crash
+assertion_initializer_const_error2_test/cc10: Crash
+assertion_initializer_const_error2_test/cc11: Crash
+
+[ $compiler == dartkp && $system == windows ]
+disassemble_test: Slow
+
+[ $mode == debug && $runtime == vm && ($compiler == app_jitk || $compiler == dartk || $compiler == dartkb) ]
+deopt_inlined_function_lazy_test: Skip
+
+[ $mode == debug && $hot_reload && ($compiler == dartk || $compiler == dartkb) ]
+async_star_test/01: Crash
+async_star_test/05: Crash
+
+[ $mode == debug && ($compiler == dartk || $compiler == dartkb) && ($hot_reload || $hot_reload_rollback) ]
+enum_duplicate_test/02: Crash # Issue 34606
+enum_duplicate_test/none: Crash # Issue 34606
+enum_private_test/01: Crash # Issue 34606
+enum_test: Crash # Issue 34606
+
+[ $mode == product && $runtime == vm && ($compiler == dartk || $compiler == dartkb) ]
+vm/causal_async_exception_stack2_test: SkipByDesign
+vm/causal_async_exception_stack_test: SkipByDesign
+
+# ===== dartk + vm status lines =====
+[ $runtime == vm && ($compiler == dartk || $compiler == dartkb) ]
+ct_const2_test: Crash # Flaky
+disassemble_test: Slow, Crash # dartbug.com/34971
+mixin_illegal_super_use_test: Skip # Issues 24478 and 23773
+mixin_illegal_superclass_test: Skip # Issues 24478 and 23773
+no_main_test/01: Skip
+vm/closure_memory_retention_test: Skip # KernelVM bug: Hits OOM
+vm/regress_29145_test: Skip # Issue 29145
+web_int_literals_test/*: SkipByDesign # Test applies only to JavaScript targets
+
+[ $hot_reload_rollback && ($compiler == dartk || $compiler == dartkb) ]
+symbol_conflict_test: Slow
+
+[ ($compiler == dartk || $compiler == dartkb) && ($hot_reload || $hot_reload_rollback) ]
+async_star_test/01: Skip # Timeout
+async_star_test/02: Skip # Timeout
+async_star_test/03: Skip # Timeout
+async_star_test/04: Skip # Timeout
+async_star_test/05: Skip # Timeout
+async_star_test/none: Skip # Timeout
+type_constants_test/none: Skip # Deferred libraries and hot reload.
+
diff --git a/tests/language/language_precompiled.status b/tests/language/language_precompiled.status
new file mode 100644
index 0000000..d7e999b
--- /dev/null
+++ b/tests/language/language_precompiled.status
@@ -0,0 +1,44 @@
+# Copyright (c) 2017, 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.
+# Sections in this file should start with "$runtime == dart_precompiled".
+
+[ $arch == arm64 && $runtime == dart_precompiled ]
+large_class_declaration_test: SkipSlow # Uses too much memory.
+setter4_test: MissingCompileTimeError
+
+[ $arch == ia32 && $runtime == dart_precompiled ]
+vm/regress_24517_test: Pass, Fail # Issue 24517.
+
+[ $compiler != dart2analyzer && $runtime == dart_precompiled ]
+mixin_mixin2_test: Skip
+
+[ $compiler == dartkp && $runtime == dart_precompiled ]
+async_star/async_star_await_for_test: RuntimeError
+async_star/async_star_cancel_test: RuntimeError
+async_star/async_star_test: RuntimeError
+
+[ $runtime == dart_precompiled && $minified ]
+cyclic_type_test/*: Skip
+enum_duplicate_test/*: Skip # Uses Enum.toString()
+enum_private_test/*: Skip # Uses Enum.toString()
+enum_test: Skip # Uses Enum.toString()
+full_stacktrace1_test: Skip
+full_stacktrace2_test: Skip
+full_stacktrace3_test: Skip
+mixin_generic_test: Skip
+mixin_mixin3_test: Skip
+mixin_mixin5_test: Skip
+mixin_mixin6_test: Skip
+mixin_mixin_bound2_test: Skip
+mixin_mixin_type_arguments_test: Skip
+mixin_super_2_test: Skip
+no_such_method_dispatcher_test: Skip # Uses new Symbol()
+vm/no_such_args_error_message_vm_test: Skip
+vm/no_such_method_error_message_callable_vm_test: Skip
+vm/no_such_method_error_message_vm_test: Skip
+vm/regress_28325_test: Skip
+
+[ $runtime == dart_precompiled && ($mode == product || $minified) ]
+stacktrace_rethrow_error_test: SkipByDesign # obfuscation/minification and instruction deduplication cause names of frames to be mangled (expected)
+stacktrace_rethrow_nonerror_test: SkipByDesign # obfuscation/minification and instruction deduplication cause names of frames to be mangled (expected)
diff --git a/tests/language/language_spec_parser.status b/tests/language/language_spec_parser.status
new file mode 100644
index 0000000..8ba5051
--- /dev/null
+++ b/tests/language/language_spec_parser.status
@@ -0,0 +1,18 @@
+# Copyright (c) 2017, 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.
+
+[ $compiler == spec_parser ]
+built_in_identifier_prefix_test: Skip # A built-in identifier can _not_ be a prefix.
+closure_type_test: Pass # Marked as RuntimeError for all in language_2.status.
+const_native_factory_test: Skip # Uses `native`.
+deep_nesting_expression_test: Skip # JVM stack overflow.
+deep_nesting_statement_test: Skip # JVM stack overflow.
+double_invalid_test: Skip # Contains illegaly formatted double.
+issue_1751477_test: Skip # Times out: 9 levels, exponential blowup => 430 secs.
+large_class_declaration_test: Skip # JVM stack overflow.
+nnbd/syntax/opt_out_nnbd_modifiers_test: Skip # Requires opt-out of NNBD.
+nnbd/syntax/pre_nnbd_modifiers_test: Skip # Requires opt-out of NNBD.
+variance: Skip # Not yet supported.
+vm/debug_break_enabled_vm_test/01: Fail # Uses debug break.
+vm/debug_break_enabled_vm_test/none: Fail # Uses debug break.
diff --git a/tests/language/language_vm.status b/tests/language/language_vm.status
new file mode 100644
index 0000000..ceb8ec6
--- /dev/null
+++ b/tests/language/language_vm.status
@@ -0,0 +1,32 @@
+# Copyright (c) 2017, 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.
+# Sections in this file should contain "$runtime == vm".
+
+[ $compiler == dartkp ]
+assertion_initializer_const_error2_test/cc01: MissingCompileTimeError # Not reporting failed assert() at compile time.
+assertion_initializer_const_error2_test/cc02: MissingCompileTimeError # Not reporting failed assert() at compile time.
+assertion_initializer_const_error2_test/cc03: MissingCompileTimeError # Not reporting failed assert() at compile time.
+assertion_initializer_const_error2_test/cc04: MissingCompileTimeError # Not reporting failed assert() at compile time.
+assertion_initializer_const_error2_test/cc05: MissingCompileTimeError # Not reporting failed assert() at compile time.
+assertion_initializer_const_error2_test/cc06: MissingCompileTimeError # Not reporting failed assert() at compile time.
+assertion_initializer_const_error2_test/cc07: MissingCompileTimeError # Not reporting failed assert() at compile time.
+assertion_initializer_const_error2_test/cc08: MissingCompileTimeError # Not reporting failed assert() at compile time.
+assertion_initializer_const_error2_test/cc09: MissingCompileTimeError # Not reporting failed assert() at compile time.
+assertion_initializer_const_error2_test/cc10: MissingCompileTimeError # Not reporting failed assert() at compile time.
+assertion_initializer_const_error2_test/cc11: MissingCompileTimeError # Not reporting failed assert() at compile time.
+
+[ $runtime == vm ]
+async_star/async_star_await_for_test: RuntimeError
+async_star/async_star_cancel_test: RuntimeError
+async_star/async_star_test: RuntimeError
+
+[ $arch == arm64 && $runtime == vm ]
+closure_cycles_test: Pass, Slow
+large_class_declaration_test: SkipSlow # Uses too much memory.
+
+[ $arch == ia32 && $mode == release && $runtime == vm ]
+deep_nesting_expression_test/01: Crash, Pass # Issue 31496
+
+[ $runtime == dart_precompiled || $runtime == vm ]
+superinterface_variance/*: Skip # Issue dart-lang/language#113
diff --git a/tests/language/nonfunction_type_aliases/basic_syntax_test.dart b/tests/language/nonfunction_type_aliases/basic_syntax_test.dart
new file mode 100644
index 0000000..4b153c9
--- /dev/null
+++ b/tests/language/nonfunction_type_aliases/basic_syntax_test.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2019, 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.
+
+// SharedOptions=--enable-experiment=nonfunction-type-aliases,non-nullable
+
+typedef T0 = void;
+typedef T1 = Function;
+typedef T2<X> = List<X>;
+typedef T3<X, Y> = Map<X, Y>;
+typedef T4 = void Function();
+typedef T5<X> = X Function(X, {X name});
+typedef T6<X, Y> = X Function(Y, [Map<Y, Y>]);
+typedef T7<X extends String, Y extends List<X>> = X Function(Y, [Map<Y, Y>]);
+
+void main() {
+  // ignore:unused_local_variable
+  var ensure_usage = [T0, T1, T2, T3, T4, T5, T6, T7];
+}
diff --git a/tests/language/nonfunction_type_aliases/nnbd_syntax_test.dart b/tests/language/nonfunction_type_aliases/nnbd_syntax_test.dart
new file mode 100644
index 0000000..9939bb0
--- /dev/null
+++ b/tests/language/nonfunction_type_aliases/nnbd_syntax_test.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2019, 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.
+
+// SharedOptions=--enable-experiment=nonfunction-type-aliases,non-nullable
+
+typedef T0 = Function?;
+typedef T1<X> = List<X?>?;
+typedef T2<X, Y> = Map<X?, Y?>?;
+typedef T3 = Never? Function(void)?;
+typedef T4<X> = X? Function(X?, {required X? name})?;
+typedef T5<X extends String, Y extends List<X?>> =
+    X? Function(Y?, [Map<Y, Y?>]);
+
+void main() {
+  // ignore:unused_local_variable
+  var ensure_usage = [T0, T1, T2, T3, T4, T5];
+}
diff --git a/tests/language_2/extension_methods/static_extension_getter_setter_conflicts_test.dart b/tests/language_2/extension_methods/static_extension_getter_setter_conflicts_test.dart
index 6ca87af..a2aea8c 100644
--- a/tests/language_2/extension_methods/static_extension_getter_setter_conflicts_test.dart
+++ b/tests/language_2/extension_methods/static_extension_getter_setter_conflicts_test.dart
@@ -82,11 +82,11 @@
   E0(c0)[0] += 0;
   //    ^^^
   // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_EXTENSION_OPERATOR
-  // [cfe] The method '[]' isn't defined for the class 'dynamic'.
+  // [cfe] The method '[]' isn't defined for the class 'C0'.
   E0(c0)[0]++;
   //    ^^^
   // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_EXTENSION_OPERATOR
-  // [cfe] The method '[]' isn't defined for the class 'dynamic'.
+  // [cfe] The method '[]' isn't defined for the class 'C0'.
 }
 
 // Conflicting extensions.
diff --git a/tests/language_2/function_type_parameter2_negative_test.dart b/tests/language_2/function_type_parameter2_negative_test.dart
deleted file mode 100644
index b1e92c6..0000000
--- a/tests/language_2/function_type_parameter2_negative_test.dart
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright (c) 2011, 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 that we detect that a function literal is not
-// a compile time constant.
-
-class FunctionTypeParameterNegativeTest {
-  static var formatter;
-
-  static SetFormatter([String fmt(int i) = (i) => "$i"]) {
-    formatter = fmt;
-  }
-
-  static void testMain() {
-    SetFormatter();
-  }
-}
-
-main() {
-  FunctionTypeParameterNegativeTest.testMain();
-}
diff --git a/tests/language_2/function_type_parameter3_test.dart b/tests/language_2/function_type_parameter3_test.dart
new file mode 100644
index 0000000..cb79201
--- /dev/null
+++ b/tests/language_2/function_type_parameter3_test.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2019, 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 that we detect that a function literal is not
+/// a compile time constant.
+
+test([String fmt(int i) = (i) => "$i"]) {}
+//                        ^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.NON_CONSTANT_DEFAULT_VALUE
+// [cfe] Not a constant expression.
+//                                 ^
+// [cfe] Not a constant expression.
+
+main() {
+  test();
+}
diff --git a/tests/language_2/function_type_parameter_negative_test.dart b/tests/language_2/function_type_parameter_negative_test.dart
deleted file mode 100644
index 9e2f006..0000000
--- a/tests/language_2/function_type_parameter_negative_test.dart
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) 2011, 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 that we detect that a function literal is not a compile time constant.
-
-class A {
-  static Function func;
-
-  static SetFunc([String fmt(int i) = (i) => "$i"]) {
-    func = fmt;
-  }
-}
-
-main() {
-  A.SetFunc();
-}
diff --git a/tests/language_2/getter_declaration_negative_test.dart b/tests/language_2/getter_declaration_negative_test.dart
deleted file mode 100644
index 813b8d3..0000000
--- a/tests/language_2/getter_declaration_negative_test.dart
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright (c) 2011, 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 that a getter has no arguments
-get m(var extraParam) {
-  return null;
-}
-
-main() {
-  m;
-}
-
diff --git a/tests/language_2/getter_declaration_test.dart b/tests/language_2/getter_declaration_test.dart
new file mode 100644
index 0000000..6ccc137
--- /dev/null
+++ b/tests/language_2/getter_declaration_test.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2019, 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 that a getter takes no parameters.
+get m(extraParam) {
+//   ^
+// [analyzer] SYNTACTIC_ERROR.GETTER_WITH_PARAMETERS
+// [cfe] A getter can't have formal parameters.
+  return null;
+}
+
+main() {
+  m;
+}
diff --git a/tests/language_2/inst_field_initializer1_negative_test.dart b/tests/language_2/inst_field_initializer1_negative_test.dart
deleted file mode 100644
index af446c7..0000000
--- a/tests/language_2/inst_field_initializer1_negative_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright (c) 2011, 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.
-// Catch illegal access to 'this' in initialized instance fields.
-
-class A {
-  A() {}
-  int x = 5;
-  int arr = new List(x); // Illegal access to 'this'.
-  // Also not a compile const expression.
-}
-
-void main() {
-  var foo = new A();
-}
diff --git a/tests/language_2/inst_field_initializer1_test.dart b/tests/language_2/inst_field_initializer1_test.dart
new file mode 100644
index 0000000..550a03e
--- /dev/null
+++ b/tests/language_2/inst_field_initializer1_test.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2019, 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.
+
+/// Catch illegal access to 'this' in initialized instance fields.
+
+class A {
+  var x = 5;
+  var arr = [x]; // Illegal access to 'this'.
+  //         ^
+  // [analyzer] COMPILE_TIME_ERROR.IMPLICIT_THIS_REFERENCE_IN_INITIALIZER
+  // [cfe] Can't access 'this' in a field initializer to read 'x'.
+}
+
+void main() {
+  A();
+}
diff --git a/tests/language_2/instance_call_wrong_argument_count_negative_test.dart b/tests/language_2/instance_call_wrong_argument_count_negative_test.dart
deleted file mode 100644
index a64a728..0000000
--- a/tests/language_2/instance_call_wrong_argument_count_negative_test.dart
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (c) 2011, 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 mismatch in argument counts.
-
-class InstanceCallWrongArgumentCountNegativeTest {
-  static void testMain() {
-    Niederhorn nh = new Niederhorn();
-    nh.goodCall(1, 2, 3);
-    // Bad call.
-    nh.goodCall(1, 2, 3, 4);
-  }
-}
-
-class Niederhorn {
-  Niederhorn() {}
-  int goodCall(int a, int b, int c) {
-    return a + b;
-  }
-}
-
-main() {
-  InstanceCallWrongArgumentCountNegativeTest.testMain();
-}
diff --git a/tests/language_2/instance_call_wrong_argument_count_test.dart b/tests/language_2/instance_call_wrong_argument_count_test.dart
new file mode 100644
index 0000000..8f0c710
--- /dev/null
+++ b/tests/language_2/instance_call_wrong_argument_count_test.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2019, 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 mismatch in argument counts.
+
+class Niederhorn {
+  int goodCall(int a, int b, int c) {
+    return a + b;
+  }
+}
+
+main() {
+  var niederhorn = Niederhorn();
+  niederhorn.goodCall(1, 2, 3);
+  niederhorn.goodCall(1, 2, 3, 4);
+  //                 ^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.EXTRA_POSITIONAL_ARGUMENTS
+  // [cfe] Too many positional arguments: 3 allowed, but 4 found.
+}
diff --git a/tests/language_2/instance_method2_negative_test.dart b/tests/language_2/instance_method2_negative_test.dart
deleted file mode 100644
index c0243bf9..0000000
--- a/tests/language_2/instance_method2_negative_test.dart
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (c) 2011, 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 test to check that we correctly flag the use of an
-// instance method (as a closure) from a static method.
-
-class Goofy {
-  String instMethod() {
-    return "woof";
-  }
-
-  static Function bark() {
-    return instMethod; // Should get error here.
-  }
-}
-
-class InstanceMethod2NegativeTest {
-  static testMain() {
-    var s = Goofy.bark();
-  }
-}
-
-main() {
-  InstanceMethod2NegativeTest.testMain();
-}
diff --git a/tests/language_2/instance_method2_test.dart b/tests/language_2/instance_method2_test.dart
new file mode 100644
index 0000000..de92967
--- /dev/null
+++ b/tests/language_2/instance_method2_test.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2019, 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.
+
+/// Check that we correctly flag the use of an instance method (as a closure)
+/// from a static method.
+
+class Goofy {
+  String instMethod() {
+    return "woof";
+  }
+
+  static Function bark() {
+    return instMethod;
+    //     ^^^^^^^^^^
+    // [analyzer] COMPILE_TIME_ERROR.INSTANCE_MEMBER_ACCESS_FROM_STATIC
+    // [cfe] Getter not found: 'instMethod'.
+  }
+}
+
+main() {
+  var s = Goofy.bark();
+}
diff --git a/tests/language_2/instance_method_negative_test.dart b/tests/language_2/instance_method_negative_test.dart
deleted file mode 100644
index ec9eaad..0000000
--- a/tests/language_2/instance_method_negative_test.dart
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (c) 2011, 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 test to check that we correctly flag the use of an
-// instance method from a static method.
-
-class Goofy {
-  String instMethod() {
-    return "woof";
-  }
-
-  static String bark() {
-    return instMethod(); // Should get error here.
-  }
-}
-
-class InstanceMethodNegativeTest {
-  static testMain() {
-    var s = Goofy.bark();
-  }
-}
-
-main() {
-  InstanceMethodNegativeTest.testMain();
-}
diff --git a/tests/language_2/instance_method_test.dart b/tests/language_2/instance_method_test.dart
new file mode 100644
index 0000000..f2de913
--- /dev/null
+++ b/tests/language_2/instance_method_test.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2019, 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.
+
+/// Check that we correctly flag the use of an instance method from a static
+/// method.
+
+class Goofy {
+  String instMethod() {
+    return "woof";
+  }
+
+  static String bark() {
+    return instMethod();
+    //     ^^^^^^^^^^
+    // [analyzer] COMPILE_TIME_ERROR.INSTANCE_MEMBER_ACCESS_FROM_STATIC
+    // [cfe] Method not found: 'instMethod'.
+  }
+}
+
+main() {
+  Goofy.bark();
+}
diff --git a/tests/language_2/interface2_negative_test.dart b/tests/language_2/interface2_negative_test.dart
deleted file mode 100644
index c4a23b1..0000000
--- a/tests/language_2/interface2_negative_test.dart
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright (c) 2012, 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 test program for testing wrong abstract class reference:
-// A class must implement a known interface.
-
-class Interface2NegativeTest implements BooHoo {
-  static testMain() {}
-}
-
-main() {
-  Interface2NegativeTest.testMain();
-}
diff --git a/tests/language_2/interface2_test.dart b/tests/language_2/interface2_test.dart
new file mode 100644
index 0000000..7b8282c
--- /dev/null
+++ b/tests/language_2/interface2_test.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2019, 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.
+
+/// A class must implement a known interface.
+
+class Interface2NegativeTest implements BooHoo {}
+//                                      ^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.IMPLEMENTS_NON_CLASS
+// [cfe] Type 'BooHoo' not found.
+//                                      ^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.UNDEFINED_CLASS
+
+main() {
+  Interface2NegativeTest();
+}
diff --git a/tests/language_2/interface_static_method_negative_test.dart b/tests/language_2/interface_static_method_negative_test.dart
deleted file mode 100644
index 5e8a83c..0000000
--- a/tests/language_2/interface_static_method_negative_test.dart
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright (c) 2012, 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.
-
-abstract class A {
-  static void foo();
-}
-
-class InterfaceStaticMethodNegativeTest {
-
-  static testMain() {
-    var a = new A();
-  }
-}
-
-main() {
-  InterfaceStaticMethodNegativeTest.testMain();
-}
diff --git a/tests/language_2/interface_static_method_test.dart b/tests/language_2/interface_static_method_test.dart
new file mode 100644
index 0000000..9170aac
--- /dev/null
+++ b/tests/language_2/interface_static_method_test.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2019, 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.
+
+abstract class A {
+  static void foo();
+  //               ^
+  // [analyzer] SYNTACTIC_ERROR.MISSING_FUNCTION_BODY
+  // [cfe] Expected a function body or '=>'.
+}
+
+main() {
+  A();
+//^
+// [analyzer] STATIC_WARNING.NEW_WITH_ABSTRACT_CLASS
+// [cfe] The class 'A' is abstract and can't be instantiated.
+}
diff --git a/tests/language_2/interface_static_non_final_fields_negative_test.dart b/tests/language_2/interface_static_non_final_fields_negative_test.dart
deleted file mode 100644
index 9da2007..0000000
--- a/tests/language_2/interface_static_non_final_fields_negative_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright (c) 2012, 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.
-
-abstract class A {
-  static var a;
-}
-
-class InterfaceStaticNonConstFieldsNegativeTest {
-  static testMain() {}
-}
-
-main() {
-  InterfaceStaticNonFinalFieldsNegativeTest.testMain();
-}
diff --git a/tests/language_2/is_not_class1_negative_test.dart b/tests/language_2/is_not_class1_negative_test.dart
deleted file mode 100644
index 5fafbbd..0000000
--- a/tests/language_2/is_not_class1_negative_test.dart
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (c) 2011, 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 test program for catch that we expect a class after an 'is'.
-
-class A {
-  const A();
-}
-
-class IsNotClass1NegativeTest {
-  static testMain() {
-    var a = new A();
-
-    if (a is "A") {
-      return 0;
-    }
-    return 0;
-  }
-}
-
-main() {
-  IsNotClass1NegativeTest.testMain();
-}
diff --git a/tests/language_2/is_not_class1_test.dart b/tests/language_2/is_not_class1_test.dart
new file mode 100644
index 0000000..6de8f8b
--- /dev/null
+++ b/tests/language_2/is_not_class1_test.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2011, 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 that we expect a class after an 'is'.
+class A {}
+
+main() {
+  var a = A();
+  if (a is "A") return 0;
+  // [error line 10, column 12, length 0]
+  // [analyzer] STATIC_WARNING.TYPE_TEST_WITH_UNDEFINED_NAME
+  // [cfe] Expected ')' before this.
+  //       ^^^
+  // [analyzer] SYNTACTIC_ERROR.EXPECTED_TOKEN
+  // [cfe] Expected a type, but got '"A"'.
+  //       ^^^
+  // [analyzer] SYNTACTIC_ERROR.EXPECTED_TYPE_NAME
+  // [cfe] This couldn't be parsed.
+}
diff --git a/tests/language_2/is_not_class4_negative_test.dart b/tests/language_2/is_not_class4_negative_test.dart
deleted file mode 100644
index 84ef5ed1..0000000
--- a/tests/language_2/is_not_class4_negative_test.dart
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (c) 2011, 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 test program to test that the parser emits an error when
-// two 'is' expressions follow each other.
-
-class A {
-  const A();
-}
-
-class IsNotClass4NegativeTest {
-  static testMain() {
-    var a = new A();
-
-    if (a is A is A) {
-      return 0;
-    }
-    return 0;
-  }
-}
-
-main() {
-  IsNotClass4NegativeTest.testMain();
-}
diff --git a/tests/language_2/is_not_class4_test.dart b/tests/language_2/is_not_class4_test.dart
new file mode 100644
index 0000000..a3adae2
--- /dev/null
+++ b/tests/language_2/is_not_class4_test.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2019, 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 that the parser emits an error when one 'is' expression follows
+/// another.
+class A {}
+
+main() {
+  var a = A();
+  if (a is A is A) return 0;
+  //         ^^
+  // [analyzer] SYNTACTIC_ERROR.UNEXPECTED_TOKEN
+  // [cfe] Unexpected token 'is'.
+}
diff --git a/tests/language_2/issue1578_negative_test.dart b/tests/language_2/issue1578_negative_test.dart
deleted file mode 100644
index ff3d0d7..0000000
--- a/tests/language_2/issue1578_negative_test.dart
+++ /dev/null
@@ -1,7 +0,0 @@
-// Copyright (c) 2012, 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.
-
-// Regression test for issue 1578.
-
-]~<)$
diff --git a/tests/language_2/issue1578_test.dart b/tests/language_2/issue1578_test.dart
new file mode 100644
index 0000000..ad355ae
--- /dev/null
+++ b/tests/language_2/issue1578_test.dart
@@ -0,0 +1,25 @@
+// Copyright (c) 2012, 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.
+
+// Regression test for issue 1578.
+
+]~<)$
+// [error line 7, column 1, length 1]
+// [analyzer] SYNTACTIC_ERROR.EXPECTED_EXECUTABLE
+// [cfe] Expected a declaration, but got ']'.
+// [error line 7, column 2, length 1]
+// [analyzer] SYNTACTIC_ERROR.EXPECTED_EXECUTABLE
+// [cfe] Expected a declaration, but got '~'.
+//^
+// [analyzer] SYNTACTIC_ERROR.EXPECTED_EXECUTABLE
+// [cfe] Expected a declaration, but got '<'.
+// ^
+// [analyzer] SYNTACTIC_ERROR.EXPECTED_EXECUTABLE
+// [cfe] Expected a declaration, but got ')'.
+//  ^
+// [analyzer] SYNTACTIC_ERROR.EXPECTED_TOKEN
+// [cfe] Expected ';' after this.
+//  ^
+// [analyzer] SYNTACTIC_ERROR.MISSING_CONST_FINAL_VAR_OR_TYPE
+// [cfe] Variables must be declared using the keywords 'const', 'final', 'var' or a type name.
diff --git a/tests/language_2/language_2.status b/tests/language_2/language_2.status
index 8902133..796193b 100644
--- a/tests/language_2/language_2.status
+++ b/tests/language_2/language_2.status
@@ -5,6 +5,9 @@
 [ $compiler != dart2analyzer ]
 switch_case_warn_test: Skip # Analyzer only, see language_analyzer2.status
 
+[ $compiler != fasta ]
+nonfunction_type_aliases/*: Skip # github.com/dart-lang/language/issues/115
+
 [ $compiler == none ]
 invalid_returns/*: Skip # https://github.com/dart-lang/sdk/issues/34013
 void/*: Skip # https://github.com/dart-lang/sdk/issues/34013
diff --git a/tests/language_2/language_2_spec_parser.status b/tests/language_2/language_2_spec_parser.status
index 7cd6359..8ba5051 100644
--- a/tests/language_2/language_2_spec_parser.status
+++ b/tests/language_2/language_2_spec_parser.status
@@ -9,56 +9,10 @@
 deep_nesting_expression_test: Skip # JVM stack overflow.
 deep_nesting_statement_test: Skip # JVM stack overflow.
 double_invalid_test: Skip # Contains illegaly formatted double.
-getter_declaration_negative_test: Fail # Negative, uses getter with parameter.
-inst_field_initializer1_negative_test: Skip # Negative, not syntax.
-instance_call_wrong_argument_count_negative_test: Skip # Negative, not syntax.
-instance_method2_negative_test: Skip # Negative, not syntax.
-instance_method_negative_test: Skip # Negative, not syntax.
-interface2_negative_test: Skip # Negative, not syntax.
-interface_static_method_negative_test: Skip # Negative, not syntax.
-interface_static_non_final_fields_negative_test: Skip # Negative, not syntax.
-is_not_class1_negative_test: Fail # Negative, uses `a is "A"`.
-is_not_class4_negative_test: Fail # Negative, uses `a is A is A`.
-issue1578_negative_test: Fail # Negative, is line noise.
 issue_1751477_test: Skip # Times out: 9 levels, exponential blowup => 430 secs.
 large_class_declaration_test: Skip # JVM stack overflow.
-list_literal2_negative_test: Skip # Negative, not syntax.
-list_literal_negative_test: Fail # Negative, uses `new List<int>[1, 2]`.
-map_literal2_negative_test: Skip # Negative, not syntax.
-map_literal_negative_test: Fail # Negative, uses `new Map<int>{..}`.
-new_expression1_negative_test: Fail # Negative, uses `new id`.
-new_expression2_negative_test: Fail # Negative, uses `new id(`.
-new_expression3_negative_test: Fail # Negative, uses `new id(...`.
 nnbd/syntax/opt_out_nnbd_modifiers_test: Skip # Requires opt-out of NNBD.
 nnbd/syntax/pre_nnbd_modifiers_test: Skip # Requires opt-out of NNBD.
-no_such_method_negative_test: Skip # Negative, not syntax.
-non_const_super_negative_test: Skip # Negative, not syntax.
-operator1_negative_test: Fail # Negative, declares static operator.
-operator2_negative_test: Fail # Negative, declares `operator ===`.
-override_field_method1_negative_test: Skip # Negative, not syntax.
-override_field_method2_negative_test: Skip # Negative, not syntax.
-override_field_method4_negative_test: Skip # Negative, not syntax.
-override_field_method5_negative_test: Skip # Negative, not syntax.
-parameter_initializer1_negative_test: Skip # Negative, not syntax.
-parameter_initializer2_negative_test: Skip # Negative, not syntax.
-parameter_initializer3_negative_test: Skip # Negative, not syntax.
-parameter_initializer4_negative_test: Skip # Negative, not syntax.
-parameter_initializer6_negative_test: Skip # Negative, not syntax.
-private_member1_negative_test: Skip # Negative, not syntax.
-private_member2_negative_test: Skip # Negative, not syntax.
-private_member3_negative_test: Skip # Negative, not syntax.
-script1_negative_test: Skip # Negative, not syntax.
-script2_negative_test: Skip # Negative, not syntax.
-string_escape4_negative_test: Fail # Negative, uses newline in string literal.
-string_interpolate1_negative_test: Fail # Negative, misplaced '$'.
-string_interpolate2_negative_test: Fail # Negative, misplaced '$'.
-string_unicode1_negative_test: Skip # Negative, not syntax.
-string_unicode2_negative_test: Skip # Negative, not syntax.
-string_unicode3_negative_test: Skip # Negative, not syntax.
-string_unicode4_negative_test: Skip # Negative, not syntax.
-switch1_negative_test: Fail # Negative, `default` clause not last.
-test_negative_test: Fail # Negative, uses non-terminated string literal.
-unary_plus_negative_test: Fail # Negative, uses non-existing unary plus.
 variance: Skip # Not yet supported.
 vm/debug_break_enabled_vm_test/01: Fail # Uses debug break.
 vm/debug_break_enabled_vm_test/none: Fail # Uses debug break.
diff --git a/tests/language_2/list_literal2_negative_test.dart b/tests/language_2/list_literal2_negative_test.dart
deleted file mode 100644
index 08e9cc8..0000000
--- a/tests/language_2/list_literal2_negative_test.dart
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright (c) 2011, 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 test program const map literals.
-
-class ListLiteral2NegativeTest<T> {
-  test() {
-    try {
-      var m = const <T>[0, 1]; // Type parameter is not allowed with const.
-    } on TypeError catch (error) {}
-  }
-}
-
-main() {
-  var t = new ListLiteral2NegativeTest<int>();
-  t.test();
-}
diff --git a/tests/language_2/list_literal5_test.dart b/tests/language_2/list_literal5_test.dart
new file mode 100644
index 0000000..81969be
--- /dev/null
+++ b/tests/language_2/list_literal5_test.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2019, 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.
+
+/// Legacy compound literal syntax that should go away.
+
+main() {
+  new List<int>[1, 2];
+  //          ^
+  // [analyzer] SYNTACTIC_ERROR.EXPECTED_TOKEN
+  // [cfe] Expected '(' after this.
+  //             ^
+  // [analyzer] SYNTACTIC_ERROR.EXPECTED_TOKEN
+  // [cfe] Expected ']' before this.
+}
diff --git a/tests/language_2/list_literal6_test.dart b/tests/language_2/list_literal6_test.dart
new file mode 100644
index 0000000..7d6e3d9
--- /dev/null
+++ b/tests/language_2/list_literal6_test.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2019, 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 test program const map literals.
+
+class ListLiteral2NegativeTest<T> {
+  test() {
+    // Type parameter is not allowed with const.
+    var m = const <T>[];
+    //             ^
+    // [analyzer] COMPILE_TIME_ERROR.INVALID_TYPE_ARGUMENT_IN_CONST_LIST
+    // [cfe] Type variables can't be used as constants.
+  }
+}
+
+main() {
+  ListLiteral2NegativeTest<int>().test();
+}
diff --git a/tests/language_2/list_literal_negative_test.dart b/tests/language_2/list_literal_negative_test.dart
deleted file mode 100644
index 4c9ad6d..0000000
--- a/tests/language_2/list_literal_negative_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright (c) 2011, 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.
-// Legacy compound literal syntax that should go away.
-
-class ListLiteralNegativeTest {
-
-  static testMain() {
-    var funny = new List<int>[1, 2];
-  }
-}
-
-main() {
-  ListLiteralNegativeTest.testMain();
-}
diff --git a/tests/language_2/map_literal13_test.dart b/tests/language_2/map_literal13_test.dart
new file mode 100644
index 0000000..f32082d
--- /dev/null
+++ b/tests/language_2/map_literal13_test.dart
@@ -0,0 +1,81 @@
+// Copyright (c) 2019, 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.
+
+/// Legacy compound literal syntax that should go away.
+
+main() {
+  var map = new Map<int>{ "a": 1, "b": 2, "c": 3 };
+  //            ^^^^^^^^
+  // [analyzer] STATIC_WARNING.NEW_WITH_INVALID_TYPE_PARAMETERS
+  // [cfe] Expected 2 type arguments.
+  //                   ^
+  // [analyzer] SYNTACTIC_ERROR.EXPECTED_TOKEN
+  // [cfe] Expected '(' after this.
+  //                    ^
+  // [analyzer] SYNTACTIC_ERROR.EXPECTED_TOKEN
+  // [cfe] Expected ';' after this.
+  //                      ^^^
+  // [analyzer] SYNTACTIC_ERROR.EXPECTED_TOKEN
+  // [cfe] Expected ';' after this.
+  //                         ^
+  // [analyzer] SYNTACTIC_ERROR.EXPECTED_TOKEN
+  // [cfe] Expected ';' after this.
+  //                         ^
+  // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+  // [cfe] Expected an identifier, but got ':'.
+  //                         ^
+  // [analyzer] SYNTACTIC_ERROR.UNEXPECTED_TOKEN
+  // [cfe] Unexpected token ':'.
+  //                           ^
+  // [analyzer] SYNTACTIC_ERROR.EXPECTED_TOKEN
+  // [cfe] Expected ';' after this.
+  //                            ^
+  // [analyzer] SYNTACTIC_ERROR.EXPECTED_TOKEN
+  // [cfe] Expected ';' after this.
+  //                            ^
+  // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+  // [cfe] Expected an identifier, but got ','.
+  //                            ^
+  // [analyzer] SYNTACTIC_ERROR.UNEXPECTED_TOKEN
+  // [cfe] Unexpected token ','.
+  //                              ^^^
+  // [analyzer] SYNTACTIC_ERROR.EXPECTED_TOKEN
+  // [cfe] Expected ';' after this.
+  //                                 ^
+  // [analyzer] SYNTACTIC_ERROR.EXPECTED_TOKEN
+  // [cfe] Expected ';' after this.
+  //                                 ^
+  // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+  // [cfe] Expected an identifier, but got ':'.
+  //                                 ^
+  // [analyzer] SYNTACTIC_ERROR.UNEXPECTED_TOKEN
+  // [cfe] Unexpected token ':'.
+  //                                   ^
+  // [analyzer] SYNTACTIC_ERROR.EXPECTED_TOKEN
+  // [cfe] Expected ';' after this.
+  //                                    ^
+  // [analyzer] SYNTACTIC_ERROR.EXPECTED_TOKEN
+  // [cfe] Expected ';' after this.
+  //                                    ^
+  // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+  // [cfe] Expected an identifier, but got ','.
+  //                                    ^
+  // [analyzer] SYNTACTIC_ERROR.UNEXPECTED_TOKEN
+  // [cfe] Unexpected token ','.
+  //                                      ^^^
+  // [analyzer] SYNTACTIC_ERROR.EXPECTED_TOKEN
+  // [cfe] Expected ';' after this.
+  //                                         ^
+  // [analyzer] SYNTACTIC_ERROR.EXPECTED_TOKEN
+  // [cfe] Expected ';' after this.
+  //                                         ^
+  // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+  // [cfe] Expected an identifier, but got ':'.
+  //                                         ^
+  // [analyzer] SYNTACTIC_ERROR.UNEXPECTED_TOKEN
+  // [cfe] Unexpected token ':'.
+  //                                           ^
+  // [analyzer] SYNTACTIC_ERROR.EXPECTED_TOKEN
+  // [cfe] Expected ';' after this.
+}
diff --git a/tests/language_2/map_literal14_test.dart b/tests/language_2/map_literal14_test.dart
new file mode 100644
index 0000000..4351eb9
--- /dev/null
+++ b/tests/language_2/map_literal14_test.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2019, 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 test program const map literals.
+
+class MapLiteral2NegativeTest<T> {
+  test() {
+    var m = const <String, T>{};
+    //                     ^
+    // [analyzer] COMPILE_TIME_ERROR.INVALID_TYPE_ARGUMENT_IN_CONST_MAP
+    // [cfe] Type variables can't be used as constants.
+  }
+}
+
+main() {
+  MapLiteral2NegativeTest<int>().test();
+}
diff --git a/tests/language_2/map_literal2_negative_test.dart b/tests/language_2/map_literal2_negative_test.dart
deleted file mode 100644
index c2b47ee..0000000
--- a/tests/language_2/map_literal2_negative_test.dart
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-// VMOptions=--enable_type_checks
-//
-// Dart test program const map literals.
-
-class MapLiteral2NegativeTest<T> {
-  test() {
-    var m = const <String, T>{"a": 0}; /*@compile-error=unspecified*/
-  }
-}
-
-main() {
-  var t = new MapLiteral2NegativeTest<int>();
-  t.test();
-}
diff --git a/tests/language_2/map_literal_negative_test.dart b/tests/language_2/map_literal_negative_test.dart
deleted file mode 100644
index dd4b65d..0000000
--- a/tests/language_2/map_literal_negative_test.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright (c) 2011, 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.
-// Legacy compound literal syntax that should go away.
-
-class MapLiteralNegativeTest {
-  static testMain() {
-    var map = new Map<int>{ "a": 1, "b": 2, "c": 3 };
-  }
-}
-
-main() {
-  MapLiteralNegativeTest.testMain();
-}
diff --git a/tests/language_2/new_expression1_negative_test.dart b/tests/language_2/new_expression1_negative_test.dart
deleted file mode 100644
index 4ed4882..0000000
--- a/tests/language_2/new_expression1_negative_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright (c) 2011, 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 NewExpressionNegativeTest {
-   NewExpressionNegativeTest() { }
-
-   static void testMain() {
-     new NewExpressionNegativeTest;
-   }
- }
-
-main() {
-  NewExpressionNegativeTest.testMain();
-}
diff --git a/tests/language_2/new_expression1_test.dart b/tests/language_2/new_expression1_test.dart
new file mode 100644
index 0000000..b06ff2a
--- /dev/null
+++ b/tests/language_2/new_expression1_test.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2019, 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 {}
+
+main() {
+  new C;
+  //  ^
+  // [analyzer] SYNTACTIC_ERROR.EXPECTED_TOKEN
+  // [cfe] Expected '(' after this.
+}
diff --git a/tests/language_2/new_expression2_negative_test.dart b/tests/language_2/new_expression2_negative_test.dart
deleted file mode 100644
index 90e3c2f..0000000
--- a/tests/language_2/new_expression2_negative_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright (c) 2011, 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 NewExpressionNegativeTest {
-   NewExpressionNegativeTest() { }
-
-   static void testMain() {
-     new NewExpressionNegativeTest(;
-   }
- }
-
-main() {
-  NewExpressionNegativeTest.testMain();
-}
diff --git a/tests/language_2/new_expression2_test.dart b/tests/language_2/new_expression2_test.dart
new file mode 100644
index 0000000..6695b3b
--- /dev/null
+++ b/tests/language_2/new_expression2_test.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2019, 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 {}
+
+main() {
+  new C(;
+  //   ^
+  // [cfe] Can't find ')' to match '('.
+  //   ^
+  // [cfe] Too many positional arguments: 0 allowed, but 1 found.
+  //    ^
+  // [analyzer] SYNTACTIC_ERROR.EXPECTED_TOKEN
+  // [cfe] Expected an identifier, but got ';'.
+  //    ^
+  // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+}
diff --git a/tests/language_2/new_expression3_negative_test.dart b/tests/language_2/new_expression3_negative_test.dart
deleted file mode 100644
index 50b2d44..0000000
--- a/tests/language_2/new_expression3_negative_test.dart
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright (c) 2011, 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 NewExpressionNegativeTest {
-   NewExpressionNegativeTest() { }
-
-   static void testMain() {
-     new NewExpressionNegativeTest(...;
-   }
- }
-
-main() {
-  NewExpressionNegativeTest.testMain();
-}
diff --git a/tests/language_2/new_expression3_test.dart b/tests/language_2/new_expression3_test.dart
new file mode 100644
index 0000000..ee1edff
--- /dev/null
+++ b/tests/language_2/new_expression3_test.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2019, 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 {}
+
+main() {
+  new C(...;
+  //   ^
+  // [cfe] Can't find ')' to match '('.
+  //   ^
+  // [cfe] Too many positional arguments: 0 allowed, but 1 found.
+  //    ^^^
+  // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+  // [cfe] Expected an identifier, but got '...'.
+  //       ^
+  // [analyzer] SYNTACTIC_ERROR.EXPECTED_TOKEN
+}
diff --git a/tests/language_2/nnbd/syntax/late_modifier_edge_cases_test.dart b/tests/language_2/nnbd/syntax/late_modifier_edge_cases_test.dart
new file mode 100644
index 0000000..45a0dcd
--- /dev/null
+++ b/tests/language_2/nnbd/syntax/late_modifier_edge_cases_test.dart
@@ -0,0 +1,54 @@
+// Copyright (c) 2019, 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.
+
+// SharedOptions=--enable-experiment=non-nullable
+import 'package:expect/expect.dart';
+
+class A {
+  late int lateField = initLateField();
+
+  int initLateField() {
+    lateField = 456;
+    Expect.equals(456, lateField);
+    return 123;
+  }
+
+  late final int lateFinalField = initLateFinalField();
+
+  int count = 0;
+  int initLateFinalField() {
+    if (count == 5) return count;
+    return ++count + lateFinalField;
+  }
+
+  static late int staticLateField = initStaticLateField();
+
+  static int initStaticLateField() {
+    staticLateField = 456;
+    Expect.equals(456, staticLateField);
+    return 123;
+  }
+
+  static late final int staticLateFinalField = initStaticLateFinalField();
+
+  static int staticCount = 0;
+  static int initStaticLateFinalField() {
+    if (staticCount == 5) return staticCount;
+    return ++staticCount + staticLateFinalField;
+  }
+}
+
+lateFieldWithInitThatWritesIntermediateValue() {
+  A a = A();
+  Expect.equals(123, a.lateField);
+  Expect.throws(() => print(a.lateFinalField));
+  Expect.equals(5, a.lateFinalField);
+  Expect.equals(123, A.staticLateField);
+  Expect.throws(() => print(A.staticLateFinalField));
+  Expect.equals(5, A.staticLateFinalField);
+}
+
+main() {
+  lateFieldWithInitThatWritesIntermediateValue();
+}
diff --git a/tests/language_2/nnbd/syntax/late_modifier_final_local_var_test.dart b/tests/language_2/nnbd/syntax/late_modifier_final_local_var_test.dart
new file mode 100644
index 0000000..9deb9c5
--- /dev/null
+++ b/tests/language_2/nnbd/syntax/late_modifier_final_local_var_test.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2019, 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.
+
+// SharedOptions=--enable-experiment=non-nullable
+import 'package:expect/expect.dart';
+
+int initCalls = 0;
+int init() {
+  ++initCalls;
+  return 123;
+}
+
+main() {
+  late final int fieldWithInit = init();
+  Expect.equals(0, initCalls);
+  Expect.equals(123, fieldWithInit);
+  Expect.equals(1, initCalls);
+  Expect.equals(123, fieldWithInit);
+  Expect.equals(1, initCalls);
+
+  late final int fieldWithNoInit;
+  Expect.throws(
+      () => fieldWithNoInit, (error) => error is LateInitializationError);
+  fieldWithNoInit = 123;
+  Expect.equals(123, fieldWithNoInit);
+  Expect.throws(() => {fieldWithNoInit = 456},
+      (error) => error is LateInitializationError);
+  Expect.equals(123, fieldWithNoInit);
+}
diff --git a/tests/language_2/nnbd/syntax/late_modifier_global_var_test.dart b/tests/language_2/nnbd/syntax/late_modifier_global_var_test.dart
new file mode 100644
index 0000000..7a7f9c9
--- /dev/null
+++ b/tests/language_2/nnbd/syntax/late_modifier_global_var_test.dart
@@ -0,0 +1,80 @@
+// Copyright (c) 2019, 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.
+
+// SharedOptions=--enable-experiment=non-nullable
+import 'package:expect/expect.dart';
+
+int initCalls = 0;
+int init() {
+  ++initCalls;
+  return 123;
+}
+
+late int varWithInit = init();
+late int varWithInit2 = init();
+late int? varWithInit3 = init();
+late int varWithTrivialInit = 123;
+late int? varWithNullInit = null;
+late int varWithNoInit;
+late final int finalVarWithInit = init();
+late final int finalVarWithTrivialInit = 123;
+late final int? finalVarWithNullInit = null;
+late final int finalVarWithNoInit;
+
+main() {
+  Expect.equals(0, initCalls);
+  Expect.equals(123, varWithInit);
+  Expect.equals(123, varWithTrivialInit);
+  Expect.equals(null, varWithNullInit);
+  Expect.throws(
+      () => varWithNoInit, (error) => error is LateInitializationError);
+  Expect.equals(1, initCalls);
+  Expect.equals(123, varWithInit);
+  Expect.equals(123, varWithTrivialInit);
+  Expect.equals(null, varWithNullInit);
+  Expect.throws(
+      () => varWithNoInit, (error) => error is LateInitializationError);
+  Expect.equals(1, initCalls);
+  varWithInit = 456;
+  varWithTrivialInit = 456;
+  varWithNullInit = 456;
+  varWithNoInit = 456;
+  Expect.equals(1, initCalls);
+  Expect.equals(456, varWithInit);
+  Expect.equals(456, varWithTrivialInit);
+  Expect.equals(456, varWithNullInit);
+  Expect.equals(456, varWithNoInit);
+  Expect.equals(1, initCalls);
+  initCalls = 0;
+
+  Expect.equals(0, initCalls);
+  varWithInit2 = 456;
+  Expect.equals(0, initCalls);
+  Expect.equals(456, varWithInit2);
+  Expect.equals(0, initCalls);
+
+  Expect.equals(0, initCalls);
+  varWithInit3 = null;
+  Expect.equals(0, initCalls);
+  Expect.equals(null, varWithInit3);
+  Expect.equals(0, initCalls);
+
+  Expect.equals(0, initCalls);
+  Expect.equals(123, finalVarWithInit);
+  Expect.equals(123, finalVarWithTrivialInit);
+  Expect.equals(null, finalVarWithNullInit);
+  Expect.equals(1, initCalls);
+  Expect.equals(123, finalVarWithInit);
+  Expect.equals(123, finalVarWithTrivialInit);
+  Expect.equals(null, finalVarWithNullInit);
+  Expect.equals(1, initCalls);
+
+  Expect.throws(
+      () => finalVarWithNoInit, (error) => error is LateInitializationError);
+  finalVarWithNoInit = 123;
+  Expect.equals(123, finalVarWithNoInit);
+  Expect.throws(() => {finalVarWithNoInit = 456},
+      (error) => error is LateInitializationError);
+  Expect.equals(123, finalVarWithNoInit);
+}
diff --git a/tests/language_2/nnbd/syntax/late_modifier_local_var_test.dart b/tests/language_2/nnbd/syntax/late_modifier_local_var_test.dart
new file mode 100644
index 0000000..d52ff6f
--- /dev/null
+++ b/tests/language_2/nnbd/syntax/late_modifier_local_var_test.dart
@@ -0,0 +1,70 @@
+// Copyright (c) 2019, 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.
+
+// SharedOptions=--enable-experiment=non-nullable
+import 'package:expect/expect.dart';
+
+int initCalls = 0;
+int init() {
+  ++initCalls;
+  return 123;
+}
+
+main() {
+  late int varWithInit = init();
+  late int varWithTrivialInit = 123;
+  late int? varWithNullInit = null;
+  late int varWithNoInit;
+  Expect.equals(0, initCalls);
+  Expect.equals(123, varWithInit);
+  Expect.equals(123, varWithTrivialInit);
+  Expect.equals(null, varWithNullInit);
+  Expect.throws(
+      () => varWithNoInit, (error) => error is LateInitializationError);
+  Expect.equals(1, initCalls);
+  Expect.equals(123, varWithInit);
+  Expect.equals(123, varWithTrivialInit);
+  Expect.equals(null, varWithNullInit);
+  Expect.throws(
+      () => varWithNoInit, (error) => error is LateInitializationError);
+  Expect.equals(1, initCalls);
+  varWithInit = 456;
+  varWithTrivialInit = 456;
+  varWithNullInit = 456;
+  varWithNoInit = 456;
+  Expect.equals(1, initCalls);
+  Expect.equals(456, varWithInit);
+  Expect.equals(456, varWithTrivialInit);
+  Expect.equals(456, varWithNullInit);
+  Expect.equals(456, varWithNoInit);
+  Expect.equals(1, initCalls);
+  initCalls = 0;
+
+  late int varWithInit2 = init();
+  Expect.equals(0, initCalls);
+  varWithInit2 = 456;
+  Expect.equals(0, initCalls);
+  Expect.equals(456, varWithInit2);
+  Expect.equals(0, initCalls);
+
+  late int? varWithInit3 = init();
+  Expect.equals(0, initCalls);
+  varWithInit3 = null;
+  Expect.equals(0, initCalls);
+  Expect.equals(null, varWithInit3);
+  Expect.equals(0, initCalls);
+
+  late int varWithCondInit = null ?? init();
+  var lambda = () {
+    Expect.equals(123, varWithCondInit);
+    Expect.equals(1, initCalls);
+  };
+  lambda();
+  lambda();
+  lambda();
+  initCalls = 0;
+
+  if (true) late int varNotInBlock = init();
+  Expect.equals(0, initCalls);
+}
diff --git a/tests/language_2/nnbd/syntax/late_modifier_static_final_field_test.dart b/tests/language_2/nnbd/syntax/late_modifier_static_final_field_test.dart
new file mode 100644
index 0000000..ff6e144
--- /dev/null
+++ b/tests/language_2/nnbd/syntax/late_modifier_static_final_field_test.dart
@@ -0,0 +1,39 @@
+// Copyright (c) 2019, 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.
+
+// SharedOptions=--enable-experiment=non-nullable
+import 'package:expect/expect.dart';
+
+int initCalls = 0;
+int init() {
+  ++initCalls;
+  return 123;
+}
+
+class A {
+  static late final int fieldWithInit = init();
+  static late final int fieldWithTrivialInit = 123;
+  static late final int? fieldWithNullInit = null;
+  static late final int fieldWithNoInit;
+}
+
+main() {
+  Expect.equals(0, initCalls);
+  Expect.equals(123, A.fieldWithInit);
+  Expect.equals(123, A.fieldWithTrivialInit);
+  Expect.equals(null, A.fieldWithNullInit);
+  Expect.equals(1, initCalls);
+  Expect.equals(123, A.fieldWithInit);
+  Expect.equals(123, A.fieldWithTrivialInit);
+  Expect.equals(null, A.fieldWithNullInit);
+  Expect.equals(1, initCalls);
+
+  Expect.throws(
+      () => A.fieldWithNoInit, (error) => error is LateInitializationError);
+  A.fieldWithNoInit = 123;
+  Expect.equals(123, A.fieldWithNoInit);
+  Expect.throws(() => {A.fieldWithNoInit = 456},
+      (error) => error is LateInitializationError);
+  Expect.equals(123, A.fieldWithNoInit);
+}
diff --git a/tests/language_2/no_such_method4_test.dart b/tests/language_2/no_such_method4_test.dart
new file mode 100644
index 0000000..23b2feb
--- /dev/null
+++ b/tests/language_2/no_such_method4_test.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2019, 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';
+
+class NoSuchMethodNegativeTest {
+  foo() {
+    return 1;
+  }
+}
+
+main() {
+  var obj = new NoSuchMethodNegativeTest() as dynamic;
+  Expect.throwsNoSuchMethodError(() {
+    obj.moo();
+  });
+}
diff --git a/tests/language_2/no_such_method_negative_test.dart b/tests/language_2/no_such_method_negative_test.dart
deleted file mode 100644
index 7abd826..0000000
--- a/tests/language_2/no_such_method_negative_test.dart
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (c) 2011, 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 test program testing that NoSuchMethodError stops the program.
-
-class NoSuchMethodNegativeTest {
-  NoSuchMethodNegativeTest() {}
-
-  foo() {
-    return 1;
-  }
-
-  static testMain() {
-    var obj = new NoSuchMethodNegativeTest();
-    return obj.moo(); // NoSuchMethodError thrown here
-  }
-}
-
-main() {
-  NoSuchMethodNegativeTest.testMain();
-}
diff --git a/tests/language_2/non_const_super_negative_test.dart b/tests/language_2/non_const_super_negative_test.dart
deleted file mode 100644
index 32742e2..0000000
--- a/tests/language_2/non_const_super_negative_test.dart
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (c) 2011, 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.
-// Check fails because const class extends from non const class.
-
-class Base {
-  Base() {}
-}
-
-class Sub extends Base {
-  const Sub(a) : a_ = a;
-  final a_;
-}
-
-class NonConstSuperNegativeTest {
-  static testMain() {
-    var a = new Sub();
-  }
-}
-
-main() {
-  NonConstSuperNegativeTest.testMain();
-}
diff --git a/tests/language_2/non_const_super_test.dart b/tests/language_2/non_const_super_test.dart
new file mode 100644
index 0000000..06c9f73
--- /dev/null
+++ b/tests/language_2/non_const_super_test.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2019, 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.
+
+/// Check fails because const class extends from non const class.
+
+class Base {
+  Base() {}
+}
+
+class Sub extends Base {
+  const Sub(a) : a_ = a;
+  //    ^^^
+  // [analyzer] COMPILE_TIME_ERROR.CONST_CONSTRUCTOR_WITH_NON_CONST_SUPER
+  // [cfe] A constant constructor can't call a non-constant super constructor.
+  final a_;
+}
+
+main() {
+  Sub(0);
+}
diff --git a/tests/language_2/nonfunction_type_aliases/basic_syntax_test.dart b/tests/language_2/nonfunction_type_aliases/basic_syntax_test.dart
new file mode 100644
index 0000000..545f533
--- /dev/null
+++ b/tests/language_2/nonfunction_type_aliases/basic_syntax_test.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2019, 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.
+
+// SharedOptions=--enable-experiment=nonfunction-type-aliases
+
+typedef T0 = void;
+typedef T1 = Function;
+typedef T2<X> = List<X>;
+typedef T3<X, Y> = Map<X, Y>;
+typedef T4 = void Function();
+typedef T5<X> = X Function(X, {X name});
+typedef T6<X, Y> = X Function(Y, [Map<Y, Y>]);
+typedef T7<X extends String, Y extends List<X>> = X Function(Y, [Map<Y, Y>]);
+
+void main() {
+  // ignore:unused_local_variable
+  var ensure_usage = [T0, T1, T2, T3, T4, T5, T6, T7];
+}
diff --git a/tests/language_2/nonfunction_type_aliases/nnbd_syntax_test.dart b/tests/language_2/nonfunction_type_aliases/nnbd_syntax_test.dart
new file mode 100644
index 0000000..9939bb0
--- /dev/null
+++ b/tests/language_2/nonfunction_type_aliases/nnbd_syntax_test.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2019, 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.
+
+// SharedOptions=--enable-experiment=nonfunction-type-aliases,non-nullable
+
+typedef T0 = Function?;
+typedef T1<X> = List<X?>?;
+typedef T2<X, Y> = Map<X?, Y?>?;
+typedef T3 = Never? Function(void)?;
+typedef T4<X> = X? Function(X?, {required X? name})?;
+typedef T5<X extends String, Y extends List<X?>> =
+    X? Function(Y?, [Map<Y, Y?>]);
+
+void main() {
+  // ignore:unused_local_variable
+  var ensure_usage = [T0, T1, T2, T3, T4, T5];
+}
diff --git a/tests/language_2/operator1_negative_test.dart b/tests/language_2/operator1_negative_test.dart
deleted file mode 100644
index 7f9c24d..0000000
--- a/tests/language_2/operator1_negative_test.dart
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright (c) 2011, 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.
-// Operator dart test program (operator functions cannot be static).
-
-class Helper {
-  int i;
-  Helper(int val) : i = val { }
-  static operator +(int index) {
-    return index;
-  }
-}
-
-class Operator1NegativeTest {
-  static testMain() {
-    Helper obj = new Helper(10);
-  }
-}
-
-main() {
-  Operator1NegativeTest.testMain();
-}
diff --git a/tests/language_2/operator1_test.dart b/tests/language_2/operator1_test.dart
new file mode 100644
index 0000000..5ba6722
--- /dev/null
+++ b/tests/language_2/operator1_test.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2019, 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.
+
+/// Operator functions cannot be static.
+
+class C {
+  static operator +(int index) {
+//^^^^^^
+// [analyzer] SYNTACTIC_ERROR.STATIC_OPERATOR
+// [cfe] Operators can't be static.
+    return index;
+  }
+}
+
+main() {
+  C();
+}
diff --git a/tests/language_2/operator2_negative_test.dart b/tests/language_2/operator2_negative_test.dart
deleted file mode 100644
index 5ee7096..0000000
--- a/tests/language_2/operator2_negative_test.dart
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright (c) 2011, 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.
-// Operator dart test program (=== cannot have an operator function).
-
-class Helper {
-  int i;
-  Helper(int val) : i = val { }
-  operator ===(int index) {
-    return index;
-  }
-}
-
-class Operator2NegativeTest {
-  static testMain() {
-    Helper obj = new Helper(10);
-  }
-}
-
-main() {
-  Operator2NegativeTest.testMain();
-}
diff --git a/tests/language_2/operator7_test.dart b/tests/language_2/operator7_test.dart
new file mode 100644
index 0000000..ff43b64
--- /dev/null
+++ b/tests/language_2/operator7_test.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2019, 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.
+
+/// No "===" operator.
+
+class C {
+  operator ===(int index) {
+  //       ^
+  // [analyzer] SYNTACTIC_ERROR.UNSUPPORTED_OPERATOR
+  // [cfe] The '===' operator is not supported.
+    return index;
+  }
+}
+
+main() {
+  C();
+}
diff --git a/tests/language_2/override_field_method1_negative_test.dart b/tests/language_2/override_field_method1_negative_test.dart
deleted file mode 100644
index 4113590..0000000
--- a/tests/language_2/override_field_method1_negative_test.dart
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright (c) 2011, 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 test error for overriding field with method.
-
-class A {
-  var foo;
-}
-
-class B extends A {
-  foo() {} // method cannot override field.
-}
-
-class OverrideFieldMethod1NegativeTest {
-  static testMain() {
-    new B().foo();
-  }
-}
-
-main() {
-  OverrideFieldMethod1NegativeTest.testMain();
-}
diff --git a/tests/language_2/override_field_method1_test.dart b/tests/language_2/override_field_method1_test.dart
new file mode 100644
index 0000000..bee5869
--- /dev/null
+++ b/tests/language_2/override_field_method1_test.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2019, 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.
+
+/// Overriding field with method.
+
+class A {
+  var foo;
+}
+
+class B extends A {
+  foo() {}
+//^^^
+// [analyzer] COMPILE_TIME_ERROR.CONFLICTING_METHOD_AND_FIELD
+// [cfe] Can't declare a member that conflicts with an inherited one.
+}
+
+main() {
+  B().foo();
+}
diff --git a/tests/language_2/override_field_method2_negative_test.dart b/tests/language_2/override_field_method2_negative_test.dart
deleted file mode 100644
index c695fb3..0000000
--- a/tests/language_2/override_field_method2_negative_test.dart
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (c) 2011, 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 test error for overriding getter with method.
-
-class A {
-  get foo {
-    return 123;
-  }
-}
-
-class B extends A {
-  foo() {} // method cannot override getter.
-}
-
-class OverrideFieldMethod2NegativeTest {
-  static testMain() {
-    new B().foo();
-  }
-}
-
-main() {
-  OverrideFieldMethod2NegativeTest.testMain();
-}
diff --git a/tests/language_2/override_field_method2_test.dart b/tests/language_2/override_field_method2_test.dart
new file mode 100644
index 0000000..0b5e4b3
--- /dev/null
+++ b/tests/language_2/override_field_method2_test.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2019, 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.
+
+/// Overriding getter with method.
+
+class A {
+  get foo => 123;
+}
+
+class B extends A {
+  foo() {}
+//^^^
+// [analyzer] COMPILE_TIME_ERROR.CONFLICTING_METHOD_AND_FIELD
+// [cfe] Can't declare a member that conflicts with an inherited one.
+}
+
+main() {
+  B().foo();
+}
diff --git a/tests/language_2/override_field_method3_test.dart b/tests/language_2/override_field_method3_test.dart
new file mode 100644
index 0000000..dbd5cfe
--- /dev/null
+++ b/tests/language_2/override_field_method3_test.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2019, 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.
+
+/// Overriding method with field.
+
+class A {
+  foo() {}
+}
+
+class B extends A {
+  var foo;
+  //  ^^^
+  // [analyzer] COMPILE_TIME_ERROR.CONFLICTING_FIELD_AND_METHOD
+  // [cfe] Can't declare a member that conflicts with an inherited one.
+}
+
+main() {
+  B().foo;
+}
diff --git a/tests/language_2/override_field_method4_negative_test.dart b/tests/language_2/override_field_method4_negative_test.dart
deleted file mode 100644
index 65837e7..0000000
--- a/tests/language_2/override_field_method4_negative_test.dart
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright (c) 2011, 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 test error for overriding method with field.
-
-class A {
-  foo() {}
-}
-
-class B extends A {
-  var foo; // Field cannot override method.
-}
-
-class OverrideFieldMethod4NegativeTest {
-  static testMain() {
-    print(new B().foo);
-  }
-}
-
-main() {
-  OverrideFieldMethod4NegativeTest.testMain();
-}
diff --git a/tests/language_2/override_field_method4_test.dart b/tests/language_2/override_field_method4_test.dart
new file mode 100644
index 0000000..eecea07
--- /dev/null
+++ b/tests/language_2/override_field_method4_test.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2019, 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.
+
+/// Overriding method with getter.
+
+class A {
+  foo() => 999;
+}
+
+class B extends A {
+  get foo => 123;
+  //  ^^^
+  // [analyzer] COMPILE_TIME_ERROR.CONFLICTING_FIELD_AND_METHOD
+  // [cfe] Can't declare a member that conflicts with an inherited one.
+}
+
+main() {
+  B().foo;
+}
diff --git a/tests/language_2/override_field_method5_negative_test.dart b/tests/language_2/override_field_method5_negative_test.dart
deleted file mode 100644
index 7484c30..0000000
--- a/tests/language_2/override_field_method5_negative_test.dart
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (c) 2011, 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 test error for overriding method with getter.
-
-class A {
-  foo() {
-    return 999;
-  }
-}
-
-class B extends A {
-  get foo {
-    return 123;
-  } // getter cannot override method
-}
-
-class OverrideFieldMethod5NegativeTest {
-  static testMain() {
-    print(new B().foo);
-  }
-}
-
-main() {
-  OverrideFieldMethod5NegativeTest.testMain();
-}
diff --git a/tests/language_2/parameter_initializer1_negative_test.dart b/tests/language_2/parameter_initializer1_negative_test.dart
deleted file mode 100644
index c433dce..0000000
--- a/tests/language_2/parameter_initializer1_negative_test.dart
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (c) 2011, 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.
-
-// Fails because this.x parameter is used in a function.
-
-class Foo {
-  var x;
-  Foo() {}
-  foo(this.x) {
-  }
-}
-
-
-class ParameterInitializer1NegativeTest {
-  static testMain() {
-    new Foo().foo(2);
-  }
-}
-
-main() {
-  ParameterInitializer1NegativeTest.testMain();
-}
diff --git a/tests/language_2/parameter_initializer1_test.dart b/tests/language_2/parameter_initializer1_test.dart
new file mode 100644
index 0000000..34465a4
--- /dev/null
+++ b/tests/language_2/parameter_initializer1_test.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2019, 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.
+
+/// Fails because this.x parameter is used in a function.
+
+class Foo {
+  var x;
+  foo(this.x) {}
+  //  ^^^^
+  // [analyzer] SYNTACTIC_ERROR.FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR
+  // [cfe] Field formal parameters can only be used in a constructor.
+  //  ^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR
+}
+
+main() {
+  Foo().foo(2);
+}
diff --git a/tests/language_2/parameter_initializer2_negative_test.dart b/tests/language_2/parameter_initializer2_negative_test.dart
deleted file mode 100644
index c0758f5..0000000
--- a/tests/language_2/parameter_initializer2_negative_test.dart
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (c) 2011, 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.
-
-// Fails because this.x parameter is used in a setter.
-
-class Foo {
-  var x;
-  Foo() {}
-  set y(this.x) {
-  }
-}
-
-
-class ParameterInitializer2NegativeTest {
-  static testMain() {
-    (new Foo()).y = 2;
-  }
-}
-
-main() {
-  ParameterInitializer2NegativeTest.testMain();
-}
diff --git a/tests/language_2/parameter_initializer3_negative_test.dart b/tests/language_2/parameter_initializer3_negative_test.dart
deleted file mode 100644
index 8b4ec6b..0000000
--- a/tests/language_2/parameter_initializer3_negative_test.dart
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (c) 2011, 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.
-
-// Fails because this.x parameter is used in a factory.
-
-class Foo {
-  var x;
-  factory Foo(this.x) {
-    return new Foo.named();
-  }
-  Foo.named() {}
-}
-
-class ParameterInitializer3NegativeTest {
-  static testMain() {
-    new Foo(2);
-  }
-}
-
-main() {
-  ParameterInitializer3NegativeTest.testMain();
-}
diff --git a/tests/language_2/parameter_initializer3_test.dart b/tests/language_2/parameter_initializer3_test.dart
new file mode 100644
index 0000000..bf81a6d
--- /dev/null
+++ b/tests/language_2/parameter_initializer3_test.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2011, 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.
+
+/// Fails because this.x parameter is used in a factory.
+
+class Foo {
+  var x;
+  factory Foo(this.x) => new Foo.named();
+  //          ^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.FIELD_INITIALIZER_FACTORY_CONSTRUCTOR
+  // [cfe] Field formal parameters can only be used in a constructor.
+  Foo.named() {}
+}
+
+main() {
+  Foo(2);
+}
diff --git a/tests/language_2/parameter_initializer4_negative_test.dart b/tests/language_2/parameter_initializer4_negative_test.dart
deleted file mode 100644
index 9b32fae..0000000
--- a/tests/language_2/parameter_initializer4_negative_test.dart
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright (c) 2011, 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.
-
-// Fails because this.x parameter is used in a static function.
-
-class Foo {
-  var x;
-  static foo(this.x) {
-  }
-}
-
-
-class ParameterInitializer4NegativeTest {
-  static testMain() {
-    Foo.foo();
-  }
-}
-
-main() {
-  ParameterInitializer4NegativeTest.testMain();
-}
diff --git a/tests/language_2/parameter_initializer4_test.dart b/tests/language_2/parameter_initializer4_test.dart
new file mode 100644
index 0000000..49cf633
--- /dev/null
+++ b/tests/language_2/parameter_initializer4_test.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2019, 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.
+
+/// Fails because this.x parameter is used in a static function.
+
+class Foo {
+  var x;
+  static foo(this.x) {}
+  //         ^^^^
+  // [analyzer] SYNTACTIC_ERROR.FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR
+  // [cfe] Field formal parameters can only be used in a constructor.
+  //         ^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR
+}
+
+main() {
+  Foo.foo(1);
+}
diff --git a/tests/language_2/parameter_initializer6_negative_test.dart b/tests/language_2/parameter_initializer6_negative_test.dart
deleted file mode 100644
index 40a2231..0000000
--- a/tests/language_2/parameter_initializer6_negative_test.dart
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (c) 2012, 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";
-
-// It is a compile-time error if a named formal parameter begins with an '_'
-
-class Foo {
-  num _y;
-  Foo.optional_private({this._y: 77}) {}
-}
-
-main() {
-  var obj;
-  obj = new Foo.optional_private(_y: 222);
-  Expect.equals(222, obj._y);
-
-  obj = new Foo.optional_private();
-  Expect.equals(77, obj._y);
-}
diff --git a/tests/language_2/parameter_initializer6_test.dart b/tests/language_2/parameter_initializer6_test.dart
new file mode 100644
index 0000000..9a5ebda
--- /dev/null
+++ b/tests/language_2/parameter_initializer6_test.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2019, 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";
+
+/// It is a compile-time error if a named formal parameter begins with an '_'.
+
+class Foo {
+  num _y;
+  Foo.private({this._y: 77}) {}
+  //           ^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.PRIVATE_OPTIONAL_PARAMETER
+  //                ^
+  // [cfe] An optional named parameter can't start with '_'.
+}
+
+main() {
+  Foo.private(_y: 222);
+}
diff --git a/tests/language_2/parameter_initializer7_test.dart b/tests/language_2/parameter_initializer7_test.dart
new file mode 100644
index 0000000..b1bca78
--- /dev/null
+++ b/tests/language_2/parameter_initializer7_test.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2019, 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.
+
+/// Fails because this.x parameter is used in a setter.
+
+class Foo {
+  var x;
+  set y(this.x) {}
+  //    ^^^^
+  // [analyzer] SYNTACTIC_ERROR.FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR
+  // [cfe] Field formal parameters can only be used in a constructor.
+  //    ^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR
+}
+
+main() {
+  Foo().y = 2;
+}
diff --git a/tests/language_2/part_self_test.dart b/tests/language_2/part_self_test.dart
new file mode 100644
index 0000000..1f44de8
--- /dev/null
+++ b/tests/language_2/part_self_test.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2019, 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 "part_self_test.dart";
+//   ^^^^^^^^^^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.PART_OF_NON_PART
+
+main() {
+  print('should not be able to recursively include self as library part');
+}
diff --git a/tests/language_2/private_member1_lib.dart b/tests/language_2/private_member1_lib.dart
new file mode 100644
index 0000000..fb6fdb2
--- /dev/null
+++ b/tests/language_2/private_member1_lib.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2019, 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 'private_member1_test.dart';
+
+class B extends A {
+  bool _instanceField;
+}
diff --git a/tests/language_2/private_member1_lib_b.dart b/tests/language_2/private_member1_lib_b.dart
deleted file mode 100644
index b0f0bf5..0000000
--- a/tests/language_2/private_member1_lib_b.dart
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright (c) 2011, 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.
-
-library PrivateMemberLibB;
-
-import 'private_member1_negative_test.dart';
-
-class B extends A {
-  bool _instanceField;
-}
diff --git a/tests/language_2/private_member1_negative_test.dart b/tests/language_2/private_member1_negative_test.dart
deleted file mode 100644
index 054bea9..0000000
--- a/tests/language_2/private_member1_negative_test.dart
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright (c) 2011, 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.
-
-library PrivateMemberLibA;
-
-import 'private_member1_lib_b.dart';
-
-class A {}
-
-class Test extends B {
-  test() {
-    _instanceField = true;
-  }
-}
-
-void main() {
-  new Test().test();
-}
diff --git a/tests/language_2/private_member1_test.dart b/tests/language_2/private_member1_test.dart
new file mode 100644
index 0000000..4a8ecb9
--- /dev/null
+++ b/tests/language_2/private_member1_test.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2019, 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 'private_member1_lib.dart';
+
+class A {}
+
+class Test extends B {
+  test() {
+    _instanceField = true;
+//  ^^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.UNDEFINED_IDENTIFIER
+// [cfe] The setter '_instanceField' isn't defined for the class 'Test'.
+  }
+}
+
+void main() {
+  Test().test();
+}
diff --git a/tests/language_2/private_member2_lib.dart b/tests/language_2/private_member2_lib.dart
new file mode 100644
index 0000000..0b2590c
--- /dev/null
+++ b/tests/language_2/private_member2_lib.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2019, 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 'private_member2_test.dart';
+
+class B extends A {
+  static bool _staticField;
+}
diff --git a/tests/language_2/private_member2_lib_b.dart b/tests/language_2/private_member2_lib_b.dart
deleted file mode 100644
index 1b60b38..0000000
--- a/tests/language_2/private_member2_lib_b.dart
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright (c) 2011, 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.
-
-library PrivateMemberLibB;
-
-import 'private_member2_negative_test.dart';
-
-class B extends A {
-  static bool _staticField;
-}
diff --git a/tests/language_2/private_member2_negative_test.dart b/tests/language_2/private_member2_negative_test.dart
deleted file mode 100644
index 1846c01..0000000
--- a/tests/language_2/private_member2_negative_test.dart
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright (c) 2011, 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.
-
-library PrivateMemberLibA;
-
-import 'private_member2_lib_b.dart';
-
-class A {}
-
-class Test extends B {
-  test() {
-    _staticField = true;
-  }
-}
-
-void main() {
-  new Test().test();
-}
diff --git a/tests/language_2/private_member2_test.dart b/tests/language_2/private_member2_test.dart
new file mode 100644
index 0000000..15e3747
--- /dev/null
+++ b/tests/language_2/private_member2_test.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2019, 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 'private_member2_lib.dart';
+
+class A {}
+
+class Test extends B {
+  test() {
+    _staticField = true;
+//  ^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.UNDEFINED_IDENTIFIER
+// [cfe] The setter '_staticField' isn't defined for the class 'Test'.
+  }
+}
+
+void main() {
+  Test().test();
+}
diff --git a/tests/language_2/private_member3_lib_b.dart b/tests/language_2/private_member3_lib.dart
similarity index 60%
rename from tests/language_2/private_member3_lib_b.dart
rename to tests/language_2/private_member3_lib.dart
index 71beac6..00309f9 100644
--- a/tests/language_2/private_member3_lib_b.dart
+++ b/tests/language_2/private_member3_lib.dart
@@ -1,10 +1,8 @@
-// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2019, 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.
 
-library PrivateMemberLibB;
-
-import 'private_member3_negative_test.dart';
+import 'private_member3_test.dart';
 
 class B extends A {
   bool _fun() {
diff --git a/tests/language_2/private_member3_negative_test.dart b/tests/language_2/private_member3_negative_test.dart
deleted file mode 100644
index 91052cb..0000000
--- a/tests/language_2/private_member3_negative_test.dart
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright (c) 2011, 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.
-
-library PrivateMemberLibA;
-
-import 'private_member3_lib_b.dart';
-
-class A {}
-
-class Test extends B {
-  test() {
-    _fun();
-  }
-}
-
-void main() {
-  new Test().test();
-}
diff --git a/tests/language_2/private_member3_test.dart b/tests/language_2/private_member3_test.dart
new file mode 100644
index 0000000..4e7675f
--- /dev/null
+++ b/tests/language_2/private_member3_test.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2019, 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 'private_member3_lib.dart';
+
+class A {}
+
+class Test extends B {
+  test() {
+    _fun();
+//  ^^^^
+// [analyzer] STATIC_TYPE_WARNING.UNDEFINED_METHOD
+// [cfe] The method '_fun' isn't defined for the class 'Test'.
+  }
+}
+
+void main() {
+  Test().test();
+}
diff --git a/tests/language_2/regress_124683_test.dart b/tests/language_2/regress_124683_test.dart
new file mode 100644
index 0000000..4efe4f6
--- /dev/null
+++ b/tests/language_2/regress_124683_test.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2019, 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.
+
+// Regression test for ddc failure triggered by
+// https://dart-review.googlesource.com/c/sdk/+/124683
+
+class Class {
+  String toString() {
+    void local() {}
+
+    return '${runtimeType.toString()}';
+  }
+}
+
+main() {
+  new Class().toString();
+}
\ No newline at end of file
diff --git a/tests/compiler/dart2js_extra/invalid_length_negative_test.dart b/tests/language_2/script1_lib.dart
similarity index 61%
rename from tests/compiler/dart2js_extra/invalid_length_negative_test.dart
rename to tests/language_2/script1_lib.dart
index 9836653..525b2ca 100644
--- a/tests/compiler/dart2js_extra/invalid_length_negative_test.dart
+++ b/tests/language_2/script1_lib.dart
@@ -1,7 +1,5 @@
-// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2019, 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.
 
-main() {
-  new List("foo");
-}
+int ok = 1;
diff --git a/tests/language_2/script1_negative_lib.dart b/tests/language_2/script1_negative_lib.dart
deleted file mode 100644
index 312103b..0000000
--- a/tests/language_2/script1_negative_lib.dart
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright (c) 2011, 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.
-
-// Imported library has wrong order of import and source tags.
-
-library Script1NegativeLib;
-part "script_source.dart";
-import "script_lib.dart";
-
-class A {
-  var a;
-}
diff --git a/tests/language_2/script1_negative_test.dart b/tests/language_2/script1_negative_test.dart
deleted file mode 100644
index e2af064..0000000
--- a/tests/language_2/script1_negative_test.dart
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright (c) 2011, 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.
-
-// Imported library has wrong order of import and source tags.
-
-library Script1NegativeTest.dart;
-
-import "script1_negative_lib.dart";
-
-main() {
-  print("Should not reach here.");
-}
diff --git a/tests/language_2/script1_part.dart b/tests/language_2/script1_part.dart
new file mode 100644
index 0000000..15bd30d
--- /dev/null
+++ b/tests/language_2/script1_part.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2019, 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 "script1_test.dart";
+
+const int scriptPart = 1;
diff --git a/tests/language_2/script1_test.dart b/tests/language_2/script1_test.dart
new file mode 100644
index 0000000..8d714e9
--- /dev/null
+++ b/tests/language_2/script1_test.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2019, 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.
+
+/// Wrong order of import and part directives.
+
+part "script1_part.dart";
+import "script1_lib.dart";
+// [error line 8, column 1, length 6]
+// [analyzer] SYNTACTIC_ERROR.IMPORT_DIRECTIVE_AFTER_PART_DIRECTIVE
+// [cfe] Import directives must precede part directives.
+
+main() {
+  print("Should not reach here.");
+}
diff --git a/tests/language_2/script2_negative_lib.dart b/tests/language_2/script2_negative_lib.dart
deleted file mode 100644
index c436080..0000000
--- a/tests/language_2/script2_negative_lib.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright (c) 2011, 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.
-
-// Imported library has source file with library tags.
-
-library Script2NegativeLib;
-
-import "script_lib.dart";
-part "script2_negative_source.dart";
-
-class A {
-  var a;
-}
diff --git a/tests/language_2/script2_negative_source.dart b/tests/language_2/script2_negative_source.dart
deleted file mode 100644
index 1674541..0000000
--- a/tests/language_2/script2_negative_source.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-// Copyright (c) 2011, 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.
-
-// Imported library has source file with library tags.
-
-library Script2NegativeSource;
-
-const int script_2_negative_source = 1;
diff --git a/tests/language_2/script2_negative_test.dart b/tests/language_2/script2_negative_test.dart
deleted file mode 100644
index 731eddb..0000000
--- a/tests/language_2/script2_negative_test.dart
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright (c) 2011, 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.
-
-// Imported library has source file with library tags.
-
-library Script2NegativeTest.dart;
-
-import "script2_negative_lib.dart";
-
-main() {
-  print("Should not reach here.");
-}
diff --git a/tests/language_2/script2_part.dart b/tests/language_2/script2_part.dart
new file mode 100644
index 0000000..44f24e8
--- /dev/null
+++ b/tests/language_2/script2_part.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2019, 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.
+
+library Script2Part;
+import "script_lib.dart";
+
+part of "script2_test.dart";
+
+const int scriptPart = 1;
diff --git a/tests/language_2/script2_test.dart b/tests/language_2/script2_test.dart
new file mode 100644
index 0000000..7ab8397
--- /dev/null
+++ b/tests/language_2/script2_test.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2019, 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 file has library and import directives.
+
+/*@compile-error=unspecified*/
+// TODO(rnystrom): Using the above tag instead of making this a static error
+// test because the error is reported in the part file and not in this file.
+// Static error tests only support errors reported in the main test file itself.
+part "script2_part.dart";
+
+main() {
+  print("Should not reach here.");
+}
diff --git a/tests/language_2/script_lib.dart b/tests/language_2/script_lib.dart
index 95a911d..eafca26 100644
--- a/tests/language_2/script_lib.dart
+++ b/tests/language_2/script_lib.dart
@@ -6,4 +6,4 @@
 
 library ScriptLib;
 
-const int script_lib = 1;
+const int scriptLib = 1;
diff --git a/tests/language_2/setter_declaration2_negative_test.dart b/tests/language_2/setter_declaration2_negative_test.dart
deleted file mode 100644
index 617000b..0000000
--- a/tests/language_2/setter_declaration2_negative_test.dart
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright (c) 2011, 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 that a setter has a single argument
-
-// too few arguments
-set m() {}
-
-main() {
-  m = 1;
-}
diff --git a/tests/language_2/setter_declaration_negative_test.dart b/tests/language_2/setter_declaration_negative_test.dart
deleted file mode 100644
index 3e66ea8..0000000
--- a/tests/language_2/setter_declaration_negative_test.dart
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright (c) 2011, 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 that a setter has a single argument
-
-// too many arguments
-set m(var value, var extra) {}
-
-main() {
-  m = 1;
-}
diff --git a/tests/language_2/setter_declaration_test.dart b/tests/language_2/setter_declaration_test.dart
new file mode 100644
index 0000000..cc5e6a7
--- /dev/null
+++ b/tests/language_2/setter_declaration_test.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2019, 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 that a setter has a single argument.
+
+set tooFew() {}
+//  ^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_NUMBER_OF_PARAMETERS_FOR_SETTER
+//        ^
+// [cfe] A setter should have exactly one formal parameter.
+
+set tooMany(var value, var extra) {}
+//  ^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_NUMBER_OF_PARAMETERS_FOR_SETTER
+//         ^
+// [cfe] A setter should have exactly one formal parameter.
+
+main() {
+  tooFew = 1;
+  tooMany = 2;
+}
diff --git a/tests/language_2/source_self_negative_test.dart b/tests/language_2/source_self_negative_test.dart
deleted file mode 100644
index b9b2e7e..0000000
--- a/tests/language_2/source_self_negative_test.dart
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright (c) 2011, 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 test program importing the core library explicitly.
-
-library SourceSelfNegativeTest;
-
-part "source_self_negative_test.dart"; // recursive reference to self.
-
-main() {
-  print('should not be able to recursively include self as library part');
-}
diff --git a/tests/language_2/static_call_wrong_argument_count_negative_test.dart b/tests/language_2/static_call_wrong_argument_count_negative_test.dart
deleted file mode 100644
index 2bc0509..0000000
--- a/tests/language_2/static_call_wrong_argument_count_negative_test.dart
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright (c) 2011, 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 mismatch in argument counts.
-
-class StaticCallWrongArgumentCountNegativeTest {
-  static void testMain() {
-    Niesen.goodCall(1, 2, 3);
-    // Bad call.
-    Niesen.goodCall(1, 2, 3, 4);
-  }
-}
-
-class Niesen {
-  static int goodCall(int a, int b, int c) {
-    return a + b;
-  }
-}
-
-main() {
-  StaticCallWrongArgumentCountNegativeTest.testMain();
-}
diff --git a/tests/language_2/static_call_wrong_argument_count_test.dart b/tests/language_2/static_call_wrong_argument_count_test.dart
new file mode 100644
index 0000000..575c486
--- /dev/null
+++ b/tests/language_2/static_call_wrong_argument_count_test.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2019, 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 mismatch in argument counts.
+class Niesen {
+  static int goodCall(int a, int b, int c) {
+    return a + b;
+  }
+}
+
+main() {
+  Niesen.goodCall(1, 2, 3);
+
+  Niesen.goodCall(1, 2, 3, 4);
+  //             ^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.EXTRA_POSITIONAL_ARGUMENTS
+  // [cfe] Too many positional arguments: 3 allowed, but 4 found.
+}
diff --git a/tests/language_2/string_escape2_negative_test_helper.dart b/tests/language_2/string_escape2_negative_test_helper.dart
deleted file mode 100644
index 92c10d9..0000000
--- a/tests/language_2/string_escape2_negative_test_helper.dart
+++ /dev/null
@@ -1,5 +0,0 @@
-// Copyright (c) 2012, 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.
-
-// An empty file, attempted sourced by string_escape2_negative_test.dart.
diff --git a/tests/language_2/string_escape3_negative_test_helper.dart b/tests/language_2/string_escape3_negative_test_helper.dart
deleted file mode 100644
index 2d14a8d..0000000
--- a/tests/language_2/string_escape3_negative_test_helper.dart
+++ /dev/null
@@ -1,7 +0,0 @@
-// Copyright (c) 2012, 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.
-
-// An empty library, imported by string_escape3_negative_test.dart.
-
-library empty;
diff --git a/tests/language_2/string_escape4_negative_test.dart b/tests/language_2/string_escape4_negative_test.dart
deleted file mode 100644
index d12cdd2..0000000
--- a/tests/language_2/string_escape4_negative_test.dart
+++ /dev/null
@@ -1,10 +0,0 @@
-// Copyright (c) 2012, 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 that newlines cannot be escaped in strings.
-
-main() {
-  print('Hello, World!\
-');
-}
diff --git a/tests/language_2/string_escape4_test.dart b/tests/language_2/string_escape4_test.dart
new file mode 100644
index 0000000..6f4efba
--- /dev/null
+++ b/tests/language_2/string_escape4_test.dart
@@ -0,0 +1,31 @@
+// Copyright (c) 2019, 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 that newlines cannot be escaped in strings.
+
+main() {
+  // Note: The newline inside a string literal doesn't play nice with the
+  // static error updater tool, so if you need to tweak the static error
+  // expectations in this test, you may need to do so manually.
+  print('Hello, World!\
+');
+// [error line 11, column 8, length 1]
+// [cfe] Can't find ')' to match '('.
+// [error line 11, column 9, length 1]
+// [cfe] String starting with ' must end with '.
+// [error line 11, column 23, length 1]
+// [analyzer] SYNTACTIC_ERROR.INVALID_UNICODE_ESCAPE
+// [cfe] An escape sequence starting with '\u' must be followed by 4 hexadecimal digits or from 1 to 6 digits between '{' and '}'.
+// [error line 11, column 23, length 1]
+// [analyzer] SYNTACTIC_ERROR.UNTERMINATED_STRING_LITERAL
+// [error line 12, column 1, length 3]
+// [analyzer] SYNTACTIC_ERROR.EXPECTED_TOKEN
+// [cfe] Expected ';' after this.
+// [error line 12, column 1]
+// [cfe] String starting with ' must end with '.
+// [error line 12, column 3, length 1]
+// [analyzer] SYNTACTIC_ERROR.UNTERMINATED_STRING_LITERAL
+}
+// [error line 29, column 1, length 1]
+// [analyzer] SYNTACTIC_ERROR.EXPECTED_TOKEN
diff --git a/tests/language_2/string_interpolate1_negative_test.dart b/tests/language_2/string_interpolate1_negative_test.dart
deleted file mode 100644
index 5a38e52..0000000
--- a/tests/language_2/string_interpolate1_negative_test.dart
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright (c) 2011, 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 test program testing that the interpolated identifier does not start
-// with '$'.
-
-class StringInterpolate1NegativeTest {
-
-  static testMain() {
-    var $x = 1;
-    var s = "eins und $$x macht zwei.";
-    print(s);
-  }
-
-}
-
-main() {
-  StringInterpolate1NegativeTest.testMain();
-}
diff --git a/tests/language_2/string_interpolate1_test.dart b/tests/language_2/string_interpolate1_test.dart
new file mode 100644
index 0000000..1bc80c0
--- /dev/null
+++ b/tests/language_2/string_interpolate1_test.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// The interpolated identifier can't start with '$'.
+
+main() {
+  var $x = 1;
+  var s = "eins und $$x macht zwei.";
+  //                 ^
+  // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+  // [cfe] A '$' has special meaning inside a string, and must be followed by an identifier or an expression in curly braces ({}).
+  //                  ^
+  // [analyzer] STATIC_WARNING.UNDEFINED_IDENTIFIER
+  // [cfe] Getter not found: 'x'.
+}
diff --git a/tests/language_2/string_interpolate2_negative_test.dart b/tests/language_2/string_interpolate2_negative_test.dart
deleted file mode 100644
index 0acbd7d..0000000
--- a/tests/language_2/string_interpolate2_negative_test.dart
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright (c) 2011, 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 test program testing that the interpolated identifier starts with an
-// ident start character.
-
-class StringInterpolate2NegativeTest {
-
-  static testMain() {
-    var $x = 1;
-    var s = "eins und $-x macht zwei.";
-    print(s);
-  }
-
-}
-
-main() {
-  StringInterpolate2NegativeTest.testMain();
-}
diff --git a/tests/language_2/string_interpolate3_test.dart b/tests/language_2/string_interpolate3_test.dart
new file mode 100644
index 0000000..ada7879
--- /dev/null
+++ b/tests/language_2/string_interpolate3_test.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// The interpolated identifier must start with an identifier start character.
+
+main() {
+  var x = 1;
+  var s = "eins und $-x macht zwei.";
+  //                 ^
+  // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+  // [cfe] A '$' has special meaning inside a string, and must be followed by an identifier or an expression in curly braces ({}).
+}
diff --git a/tests/language_2/string_unicode1_negative_test.dart b/tests/language_2/string_unicode1_negative_test.dart
deleted file mode 100644
index 72c06e14..0000000
--- a/tests/language_2/string_unicode1_negative_test.dart
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright (c) 2011, 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 StringUnicode1NegativeTest {
-
-  static testMain() {
-    // (backslash) uXXXX must have exactly 4 hex digits
-    String str = "Foo\u00";
-    str = "Foo\uDEEMBar";
-  }
-}
-
-main() {
-  StringUnicode1NegativeTest.testMain();
-}
diff --git a/tests/language_2/string_unicode1_test.dart b/tests/language_2/string_unicode1_test.dart
new file mode 100644
index 0000000..04a9f5f
--- /dev/null
+++ b/tests/language_2/string_unicode1_test.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2019, 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.
+
+/// (backslash) uXXXX must have exactly 4 hex digits.
+
+main() {
+  var str = "Foo\u00";
+  //            ^^^^
+  // [analyzer] SYNTACTIC_ERROR.INVALID_UNICODE_ESCAPE
+  // [cfe] An escape sequence starting with '\u' must be followed by 4 hexadecimal digits or from 1 to 6 digits between '{' and '}'.
+  str = "Foo\uDEEMBar";
+  //        ^^^^^
+  // [analyzer] SYNTACTIC_ERROR.INVALID_UNICODE_ESCAPE
+  // [cfe] An escape sequence starting with '\u' must be followed by 4 hexadecimal digits or from 1 to 6 digits between '{' and '}'.
+}
diff --git a/tests/language_2/string_unicode2_negative_test.dart b/tests/language_2/string_unicode2_negative_test.dart
deleted file mode 100644
index c38040c..0000000
--- a/tests/language_2/string_unicode2_negative_test.dart
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) 2011, 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 StringUnicode2NegativeTest {
-
-  static testMain() {
-    // \u{X*} should have 1-6 hex digits
-    String str = "Foo\u{}Bar";
-    str = "Foo\u{000000000}Bar";
-    str = "Foo\u{DEAF!}Bar";
-  }
-}
-
-main() {
-  StringUnicode2NegativeTest.testMain();
-}
diff --git a/tests/language_2/string_unicode2_test.dart b/tests/language_2/string_unicode2_test.dart
new file mode 100644
index 0000000..4624fbd
--- /dev/null
+++ b/tests/language_2/string_unicode2_test.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2019, 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.
+
+/// \u{X*} should have 1-6 hex digits.
+
+main() {
+  var str = "Foo\u{}Bar";
+  //            ^^^^
+  // [analyzer] SYNTACTIC_ERROR.INVALID_UNICODE_ESCAPE
+  // [cfe] An escape sequence starting with '\u' must be followed by 4 hexadecimal digits or from 1 to 6 digits between '{' and '}'.
+  str = "Foo\u{000000000}Bar";
+  str = "Foo\u{DEAF!}Bar";
+  //        ^^^^^^^^
+  // [analyzer] SYNTACTIC_ERROR.INVALID_UNICODE_ESCAPE
+  // [cfe] An escape sequence starting with '\u' must be followed by 4 hexadecimal digits or from 1 to 6 digits between '{' and '}'.
+}
diff --git a/tests/language_2/string_unicode3_negative_test.dart b/tests/language_2/string_unicode3_negative_test.dart
deleted file mode 100644
index 15cdf38..0000000
--- a/tests/language_2/string_unicode3_negative_test.dart
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright (c) 2011, 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 StringUnicode3NegativeTest {
-
-  static testMain() {
-    // (backslash) xXX must have exactly 2 hex digits
-    String str = "Foo\x0";
-    str = "Foo\xF Bar";
-  }
-}
-
-main() {
-  StringUnicode3NegativeTest.testMain();
-}
diff --git a/tests/language_2/string_unicode3_test.dart b/tests/language_2/string_unicode3_test.dart
new file mode 100644
index 0000000..3c04303
--- /dev/null
+++ b/tests/language_2/string_unicode3_test.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2019, 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.
+
+/// Backslash xXX must have exactly 2 hex digits.
+
+main() {
+  var str = "Foo\x0";
+  //            ^^^
+  // [analyzer] SYNTACTIC_ERROR.INVALID_HEX_ESCAPE
+  // [cfe] An escape sequence starting with '\x' must be followed by 2 hexadecimal digits.
+  str = "Foo\xF Bar";
+  //        ^^^
+  // [analyzer] SYNTACTIC_ERROR.INVALID_HEX_ESCAPE
+  // [cfe] An escape sequence starting with '\x' must be followed by 2 hexadecimal digits.
+}
diff --git a/tests/language_2/string_unicode4_negative_test.dart b/tests/language_2/string_unicode4_negative_test.dart
deleted file mode 100644
index b4ee30f..0000000
--- a/tests/language_2/string_unicode4_negative_test.dart
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) 2011, 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 StringUnicode4NegativeTest {
-
-  static testMain() {
-    // Unicode escapes must refer to valid Unicode points and not surrogate characters
-    String str = "Foo\u{FFFFFF}";
-    str = "Foo\uD800";
-    str = "Foo\uDC00";
-  }
-}
-
-main() {
-  StringUnicode4NegativeTest.testMain();
-}
diff --git a/tests/language_2/string_unicode4_test.dart b/tests/language_2/string_unicode4_test.dart
new file mode 100644
index 0000000..89095fa
--- /dev/null
+++ b/tests/language_2/string_unicode4_test.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2019, 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.
+
+/// Unicode escapes must refer to valid Unicode points and not surrogate
+/// characters.
+
+main() {
+  var str = "Foo\u{FFFFFF}";
+  //            ^^^^^^^^^
+  // [analyzer] SYNTACTIC_ERROR.INVALID_CODE_POINT
+  // [cfe] The escape sequence starting with '\u' isn't a valid code point.
+  str = "Foo\uD800";
+  str = "Foo\uDC00";
+}
diff --git a/tests/language_2/switch1_negative_test.dart b/tests/language_2/switch1_negative_test.dart
deleted file mode 100644
index 5648b22..0000000
--- a/tests/language_2/switch1_negative_test.dart
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (c) 2011, 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.
-// Check that default clause must be last case.
-
-class Switch1NegativeTest {
-
-  static testMain() {
-    var a = 5;
-    var x;
-    S: switch (a) {
-      case 1: x = 1; break;
-      case 6: x = 2; break S;
-      default:
-      case 8:  break;
-    }
-    return a;
-  }
-}
-
-main() {
-  Switch1NegativeTest.testMain();
-}
diff --git a/tests/language_2/switch1_test.dart b/tests/language_2/switch1_test.dart
new file mode 100644
index 0000000..ffae0f2
--- /dev/null
+++ b/tests/language_2/switch1_test.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2019, 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.
+
+/// Check that default clause must be last case.
+
+main() {
+  var a = 5;
+  var x;
+  S: switch (a) {
+    case 1: x = 1; break;
+    case 6: x = 2; break S;
+    default:
+//  ^
+// [cfe] Switch case may fall through to the next case.
+    case 8:  break;
+//  ^^^^
+// [analyzer] SYNTACTIC_ERROR.SWITCH_HAS_CASE_AFTER_DEFAULT_CASE
+// [cfe] The default case should be the last case in a switch statement.
+  }
+  return a;
+}
diff --git a/tests/language_2/switch3_negative_test.dart b/tests/language_2/switch3_negative_test.dart
deleted file mode 100644
index 1232537..0000000
--- a/tests/language_2/switch3_negative_test.dart
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright (c) 2011, 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.
-// Check that 'continue' to switch statement is illegal.
-
-class Switch3NegativeTest {
-
-  static testMain() {
-    var a = 5;
-    var x;
-    switch (a) {
-      case 1: x = 1; break;
-      case 6: x = 2; continue;  // illegal jump target
-      case 8:  break;
-    }
-    return a;
-  }
-}
-
-main() {
-  Switch3NegativeTest.testMain();
-}
diff --git a/tests/language_2/switch3_test.dart b/tests/language_2/switch3_test.dart
new file mode 100644
index 0000000..cdcbdef
--- /dev/null
+++ b/tests/language_2/switch3_test.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2019, 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.
+
+/// Check that 'continue' to switch statement is illegal.
+
+main() {
+  var a = 5;
+  var x;
+  switch (a) {
+    case 1: x = 1; break;
+    case 6: x = 2; continue;
+//  ^
+// [cfe] Switch case may fall through to the next case.
+//                 ^^^^^^^^
+// [analyzer] SYNTACTIC_ERROR.CONTINUE_WITHOUT_LABEL_IN_CASE
+// [cfe] A continue statement in a switch statement must have a label as a target.
+    case 8:  break;
+  }
+  return a;
+}
diff --git a/tests/language_2/switch4_negative_test.dart b/tests/language_2/switch4_negative_test.dart
deleted file mode 100644
index e4f7723..0000000
--- a/tests/language_2/switch4_negative_test.dart
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (c) 2011, 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.
-// Discover unresolved case labels.
-
-class Switch4NegativeTest {
-  static testMain() {
-    var a = 5;
-    var x;
-    switch (a) {
-      case 1:
-        x = 1;
-        continue L; // unresolved forward reference
-      case 6:
-        x = 2;
-        break;
-      case 8:
-        break;
-    }
-    return a;
-  }
-}
-
-main() {
-  Switch4NegativeTest.testMain();
-}
diff --git a/tests/language_2/switch4_test.dart b/tests/language_2/switch4_test.dart
new file mode 100644
index 0000000..d90fc65
--- /dev/null
+++ b/tests/language_2/switch4_test.dart
@@ -0,0 +1,25 @@
+// Copyright (c) 2019, 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.
+
+/// Discover unresolved case labels.
+
+main() {
+  var a = 5;
+  var x;
+  switch (a) {
+    case 1:
+      x = 1;
+      continue L;
+//    ^
+// [cfe] Can't find label 'L'.
+      //       ^
+      // [analyzer] COMPILE_TIME_ERROR.LABEL_UNDEFINED
+    case 6:
+      x = 2;
+      break;
+    case 8:
+      break;
+  }
+  return a;
+}
diff --git a/tests/language_2/switch5_negative_test.dart b/tests/language_2/switch5_negative_test.dart
deleted file mode 100644
index 639c983..0000000
--- a/tests/language_2/switch5_negative_test.dart
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) 2011, 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.
-// Break' to case label is illegal.
-
-class Switch5NegativeTest {
-  static testMain() {
-    var a = 5;
-    var x;
-    switch (a) {
-      L:
-      case 1:
-        x = 1;
-        break;
-      case 6:
-        x = 2;
-        break L; // illegal
-      default:
-        break;
-    }
-    return a;
-  }
-}
-
-main() {
-  Switch5NegativeTest.testMain();
-}
diff --git a/tests/language_2/switch5_test.dart b/tests/language_2/switch5_test.dart
new file mode 100644
index 0000000..7f23f3f
--- /dev/null
+++ b/tests/language_2/switch5_test.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2019, 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.
+
+/// Break' to case label is illegal.
+
+main() {
+  var a = 5;
+  var x;
+  switch (a) {
+    L:
+    case 1:
+      x = 1;
+      break;
+    case 6:
+//  ^
+// [cfe] Switch case may fall through to the next case.
+      x = 2;
+      break L;
+      //    ^
+      // [analyzer] COMPILE_TIME_ERROR.BREAK_LABEL_ON_SWITCH_MEMBER
+      // [cfe] Can't break to 'L'.
+    default:
+      break;
+  }
+  return a;
+}
diff --git a/tests/language_2/switch7_negative_test.dart b/tests/language_2/switch7_negative_test.dart
deleted file mode 100644
index 7426f41..0000000
--- a/tests/language_2/switch7_negative_test.dart
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright (c) 2011, 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.
-// Illegal to reference a labeled case stmt with break
-
-class Switch7NegativeTest {
-  static testMain() {
-    var x = 1;
-    L:
-    while (true) {
-      switch (x) {
-        L:
-        case 1: // Shadowing another label is OK.
-          break L; // illegal, can't reference labeled case stmt from break
-      }
-    }
-  }
-}
-
-main() {
-  Switch7NegativeTest.testMain();
-}
diff --git a/tests/language_2/switch7_test.dart b/tests/language_2/switch7_test.dart
new file mode 100644
index 0000000..e47d7e5
--- /dev/null
+++ b/tests/language_2/switch7_test.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2019, 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.
+
+/// Illegal to reference a labeled case statement with break.
+
+main() {
+  var x = 1;
+  L:
+  while (true) {
+    switch (x) {
+      L:
+      case 1: // Shadowing another label is OK.
+        break L; // Illegal, can't reference labeled case from break.
+        //    ^
+        // [analyzer] COMPILE_TIME_ERROR.BREAK_LABEL_ON_SWITCH_MEMBER
+        // [cfe] Can't break to 'L'.
+    }
+  }
+}
diff --git a/tests/language_2/test_negative_test.dart b/tests/language_2/test_negative_test.dart
deleted file mode 100644
index 831d9dd..0000000
--- a/tests/language_2/test_negative_test.dart
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (c) 2011, 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 test program which has a syntax error. This test is to
-// ensure that the resulting parse error message is correctly
-// displayed without being garbled.
-
-class Test {
-  static foo() {
-    return "hi
-  }
-  static testMain() {
-    List a = {1 : 1};
-    List b = {1 : 1};
-    return a == b;
-  }
-}
-
-main() {
-  TestNegativeTest.testMain();
-}
diff --git a/tests/language_2/unary_plus_negative_test.dart b/tests/language_2/unary_plus_negative_test.dart
deleted file mode 100644
index 86f2942..0000000
--- a/tests/language_2/unary_plus_negative_test.dart
+++ /dev/null
@@ -1,10 +0,0 @@
-// Copyright (c) 2012, 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.
-
-// There is no unary plus operator in Dart.
-
-main() {
-  var a = 1;
-  var b = +a; /*@compile-error=unspecified*/
-}
diff --git a/tests/language_2/unary_plus_test.dart b/tests/language_2/unary_plus_test.dart
new file mode 100644
index 0000000..ac6e9ce
--- /dev/null
+++ b/tests/language_2/unary_plus_test.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2019, 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.
+
+/// There is no unary plus operator in Dart.
+
+main() {
+  var a = 1;
+  var b = +a;
+  //      ^
+  // [analyzer] SYNTACTIC_ERROR.MISSING_IDENTIFIER
+  // [cfe] '+' is not a prefix operator.
+}
diff --git a/tests/language_2/variance/variance_downwards_inference_test.dart b/tests/language_2/variance/variance_downwards_inference_test.dart
index 7de0e22..b6cd329 100644
--- a/tests/language_2/variance/variance_downwards_inference_test.dart
+++ b/tests/language_2/variance/variance_downwards_inference_test.dart
@@ -26,6 +26,11 @@
   void set y(S _value) {}
 }
 
+class D<in T> {
+  D(T x, void Function(T) y) {}
+  void set x(T val) {}
+}
+
 main() {
   // int <: T <: Object
   // Choose int
@@ -41,4 +46,8 @@
   // int <: S <: Object
   // Choose Object
   C<Object, Object> c = new C(3, 3)..x+=1..y="hello";
+
+  // int <: T <: num
+  // Choose num due to contravariant heuristic.
+  D<int> d = new D(3, (num x) {})..x=2.2;
 }
diff --git a/tests/language_2/variance/variance_in_field_error_test.dart b/tests/language_2/variance/variance_in_field_error_test.dart
index 2250cda..6419bf6 100644
--- a/tests/language_2/variance/variance_in_field_error_test.dart
+++ b/tests/language_2/variance/variance_in_field_error_test.dart
@@ -9,53 +9,70 @@
 class A<in T> {
   final T a = null;
   //      ^
-  // [analyzer] unspecified
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   // [cfe] Can't use 'in' type variable 'T' in an 'out' position.
 
   final T Function() b = () => null;
   //                 ^
-  // [analyzer] unspecified
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   // [cfe] Can't use 'in' type variable 'T' in an 'out' position.
 
   T get c => null;
-  //      ^
-  // [analyzer] unspecified
-  // [cfe] Can't use 'in' type variable 'T' in an 'out' position in the return type.
+//^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
+//        ^
+// [cfe] Can't use 'in' type variable 'T' in an 'out' position in the return type.
 
   T d;
-  //^
-  // [analyzer] unspecified
-  // [cfe] Can't use 'in' type variable 'T' in an 'out' position.
+//  ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
+// [cfe] Can't use 'in' type variable 'T' in an 'out' position.
 
   covariant T e;
   //          ^
-  // [analyzer] unspecified
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   // [cfe] Can't use 'in' type variable 'T' in an 'out' position.
 }
 
 mixin BMixin<in T> {
   final T a = null;
   //      ^
-  // [analyzer] unspecified
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   // [cfe] Can't use 'in' type variable 'T' in an 'out' position.
 
   final T Function() b = () => null;
   //                 ^
-  // [analyzer] unspecified
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   // [cfe] Can't use 'in' type variable 'T' in an 'out' position.
 
   T get c => null;
-  //      ^
-  // [analyzer] unspecified
-  // [cfe] Can't use 'in' type variable 'T' in an 'out' position in the return type.
+//^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
+//        ^
+// [cfe] Can't use 'in' type variable 'T' in an 'out' position in the return type.
 
   T d;
-  //^
-  // [analyzer] unspecified
-  // [cfe] Can't use 'in' type variable 'T' in an 'out' position.
+//  ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
+// [cfe] Can't use 'in' type variable 'T' in an 'out' position.
 
   covariant T e;
   //          ^
-  // [analyzer] unspecified
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
+  // [cfe] Can't use 'in' type variable 'T' in an 'out' position.
+}
+
+abstract class C<in T> {
+  T get a;
+//^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
+//       ^
+// [cfe] Can't use 'in' type variable 'T' in an 'out' position in the return type.
+}
+
+class D<in T> extends C<T> {
+  var a;
+  //  ^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   // [cfe] Can't use 'in' type variable 'T' in an 'out' position.
 }
diff --git a/tests/language_2/variance/variance_in_inference_error_test.dart b/tests/language_2/variance/variance_in_inference_error_test.dart
index 35b994d..b481d4dd 100644
--- a/tests/language_2/variance/variance_in_inference_error_test.dart
+++ b/tests/language_2/variance/variance_in_inference_error_test.dart
@@ -15,51 +15,87 @@
 class Middle extends Upper {}
 class Lower extends Middle {}
 
+class ContraBound<in T> {
+  ContraBound(T x, void Function(T) y) {}
+}
+
 Exactly<T> inferCovContra<T>(Covariant<T> x, Contravariant<T> y) => new Exactly<T>();
 Exactly<T> inferContraContra<T>(Contravariant<T> x, Contravariant<T> y) => new Exactly<T>();
+Exactly<T> inferContraBound<T>(ContraBound<T> x) => new Exactly<T>();
 
 main() {
   Exactly<Upper> upper;
+  Exactly<Lower> lower;
 
+  // T <: Upper and T <: Middle.
+  // We choose Middle.
   var inferredMiddle = inferContraContra(Contravariant<Upper>(), Contravariant<Middle>());
   upper = inferredMiddle;
-  //      ^
-  // [analyzer] unspecified
+  //      ^^^^^^^^^^^^^^
+  // [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT
   // [cfe] A value of type 'Exactly<Middle>' can't be assigned to a variable of type 'Exactly<Upper>'.
 
+  // T <: Upper and T <: Lower.
+  // We choose Lower.
   var inferredLower = inferContraContra(Contravariant<Upper>(), Contravariant<Lower>());
   upper = inferredLower;
-  //      ^
-  // [analyzer] unspecified
+  //      ^^^^^^^^^^^^^
+  // [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT
   // [cfe] A value of type 'Exactly<Lower>' can't be assigned to a variable of type 'Exactly<Upper>'.
 
   // int <: T <: String is not a valid constraint.
   inferCovContra(Covariant<int>(), Contravariant<String>());
-  //                               ^
-  // [analyzer] unspecified
-  // [cfe] The argument type 'Contravariant<String>' can't be assigned to the parameter type 'Contravariant<int>'.
+//^^^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
+//                                 ^^^^^^^^^^^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ARGUMENT_TYPE_NOT_ASSIGNABLE
+// [cfe] The argument type 'Contravariant<String>' can't be assigned to the parameter type 'Contravariant<int>'.
 
   // String <: T <: int is not a valid constraint.
   inferCovContra(Covariant<String>(), Contravariant<int>());
-  //                                  ^
-  // [analyzer] unspecified
-  // [cfe] The argument type 'Contravariant<int>' can't be assigned to the parameter type 'Contravariant<String>'.
+//^^^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
+//                                    ^^^^^^^^^^^^^^^^^^^^
+// [analyzer] STATIC_WARNING.ARGUMENT_TYPE_NOT_ASSIGNABLE
+// [cfe] The argument type 'Contravariant<int>' can't be assigned to the parameter type 'Contravariant<String>'.
 
   // Middle <: T <: Lower is not a valid constraint
   inferCovContra(Covariant<Middle>(), Contravariant<Lower>());
-  //                                  ^
-  // [analyzer] unspecified
-  // [cfe] The constructor returns type 'Contravariant<Lower>' that isn't of expected type 'Contravariant<Middle>'.
+//^^^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
+//                                    ^^^^^^^^^^^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.INVALID_CAST_NEW_EXPR
+// [cfe] The constructor returns type 'Contravariant<Lower>' that isn't of expected type 'Contravariant<Middle>'.
 
   // Upper <: T <: Lower is not a valid constraint
   inferCovContra(Covariant<Upper>(), Contravariant<Lower>());
-  //                                 ^
-  // [analyzer] unspecified
-  // [cfe] The constructor returns type 'Contravariant<Lower>' that isn't of expected type 'Contravariant<Upper>'.
+//^^^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
+//                                   ^^^^^^^^^^^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.INVALID_CAST_NEW_EXPR
+// [cfe] The constructor returns type 'Contravariant<Lower>' that isn't of expected type 'Contravariant<Upper>'.
 
   // Upper <: T <: Middle is not a valid constraint
   inferCovContra(Covariant<Upper>(), Contravariant<Middle>());
-  //                                 ^
-  // [analyzer] unspecified
-  // [cfe] The constructor returns type 'Contravariant<Middle>' that isn't of expected type 'Contravariant<Upper>'.
+//^^^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
+//                                   ^^^^^^^^^^^^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.INVALID_CAST_NEW_EXPR
+// [cfe] The constructor returns type 'Contravariant<Middle>' that isn't of expected type 'Contravariant<Upper>'.
+
+  // Inference for Contrabound(...) produces Lower <: T <: Upper.
+  // Since T is contravariant, we choose Upper as the solution.
+  var inferredContraUpper = inferContraBound(ContraBound(Lower(), (Upper x) {}));
+  lower = inferredContraUpper;
+  //      ^^^^^^^^^^^^^^^^^^^
+  // [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT
+  // [cfe] A value of type 'Exactly<Upper>' can't be assigned to a variable of type 'Exactly<Lower>'.
+
+  // Inference for Contrabound(...) produces Lower <: T <: Middle.
+  // Since T is contravariant, we choose Middle as the solution.
+  var inferredContraMiddle = inferContraBound(ContraBound(Lower(), (Middle x) {}));
+  lower = inferredContraMiddle;
+  //      ^^^^^^^^^^^^^^^^^^^^
+  // [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT
+  // [cfe] A value of type 'Exactly<Middle>' can't be assigned to a variable of type 'Exactly<Lower>'.
 }
diff --git a/tests/language_2/variance/variance_in_inference_test.dart b/tests/language_2/variance/variance_in_inference_test.dart
index 742911d..03277fb 100644
--- a/tests/language_2/variance/variance_in_inference_test.dart
+++ b/tests/language_2/variance/variance_in_inference_test.dart
@@ -15,10 +15,16 @@
 class Middle extends Upper {}
 class Lower extends Middle {}
 
+class ContraBound<in T> {
+  ContraBound(T x, void Function(T) y) {}
+}
+
 Exactly<T> inferCovContra<T>(Covariant<T> x, Contravariant<T> y) => new Exactly<T>();
 Exactly<T> inferContraContra<T>(Contravariant<T> x, Contravariant<T> y) => new Exactly<T>();
+Exactly<T> inferContraBound<T>(ContraBound<T> x) => new Exactly<T>();
 
 main() {
+  Exactly<Upper> upper;
   Exactly<Middle> middle;
   Exactly<Lower> lower;
 
@@ -57,4 +63,14 @@
   // Choose Lower since it is the greatest lower bound of Middle and Lower.
   var inferredLower5 = inferContraContra(Contravariant<Lower>(), Contravariant<Middle>());
   lower = inferredLower5;
+
+  // Lower <: T <: Upper
+  // Choose Upper.
+  var inferredContraUpper = inferContraBound(ContraBound(Lower(), (Upper x) {}));
+  upper = inferredContraUpper;
+
+  // Lower <: T <: Middle
+  // Choose Middle.
+  var inferredContraMiddle = inferContraBound(ContraBound(Lower(), (Middle x) {}));
+  middle = inferredContraMiddle;
 }
diff --git a/tests/language_2/variance/variance_in_method_error_test.dart b/tests/language_2/variance/variance_in_method_error_test.dart
index 98c8033..e7e26c4 100644
--- a/tests/language_2/variance/variance_in_method_error_test.dart
+++ b/tests/language_2/variance/variance_in_method_error_test.dart
@@ -17,40 +17,47 @@
 class A<in T> {
   // TODO (kallentu): Come NNBD, change `T` to `T?`
   T method1() => null;
+//^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //       ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'out' position in the return type.
 
   void method2(Contra<T> x) {}
+  //           ^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                     ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'out' position.
 
   Cov<T> method3() {
+//^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //            ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'out' position in the return type.
     return () => null;
   }
 
   void method4(Contra<Cov<T>> x) {}
+  //           ^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                          ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'out' position.
 
   void method5(Cov<Contra<T>> x) {}
+  //           ^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                          ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'out' position.
 
   Contra<Contra<T>> method6() => (Contra<T> x) {};
+//^^^^^^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                       ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'out' position in the return type.
 
   Cov<Cov<T>> method7() {
+//^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                 ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'out' position in the return type.
     return () {
       return () => null;
@@ -58,133 +65,153 @@
   }
 
   Inv<T> method8() => null;
+//^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //            ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'inout' position in the return type.
 
   void method9(Inv<T> x) {}
+  //           ^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                  ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'inout' position.
 
   Covariant<T> method10() => null;
+//^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                   ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'out' position in the return type.
 
   void method11(Contravariant<T> x) {}
+  //            ^^^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                             ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'out' position.
 
   Invariant<T> method12() => null;
+//^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                   ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'inout' position in the return type.
 
   void method13(Invariant<T> x) {}
+  //            ^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                         ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'inout' position.
 
   void method14(Contravariant<Covariant<T>> x) {}
+  //            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                                        ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'out' position.
 
   void method15(Covariant<Contravariant<T>> x) {}
+  //            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                                        ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'out' position.
 
   Contravariant<Contravariant<T>> method16() => Contravariant<Contravariant<T>>();
+//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                                      ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'out' position in the return type.
 
   Covariant<Covariant<T>> method17() => Covariant<Covariant<T>>();
+//^^^^^^^^^^^^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                              ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'out' position in the return type.
 
   void method18<X extends T>() {}
-  //            ^
-  // [analyzer] unspecified
+  //            ^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   // [cfe] Can't use 'in' type variable 'T' in an 'inout' position.
 
   void method19<X extends Cov<T>>() {}
-  //            ^
-  // [analyzer] unspecified
+  //            ^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   // [cfe] Can't use 'in' type variable 'T' in an 'inout' position.
 
   void method20<X extends Covariant<T>>() {}
-  //            ^
-  // [analyzer] unspecified
+  //            ^^^^^^^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   // [cfe] Can't use 'in' type variable 'T' in an 'inout' position.
 
   void method21({Contra<T> x}) {}
+  //             ^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                       ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'out' position.
 
   void method22({Contravariant<T> x}) {}
+  //             ^^^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                              ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'out' position.
 
   void method23({Covariant<T> x, Contravariant<T> y}) {}
+  //                             ^^^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                                              ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'out' position.
 
   void method24<X extends Contra<T>>() {}
-  //            ^
-  // [analyzer] unspecified
+  //            ^^^^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   // [cfe] Can't use 'in' type variable 'T' in an 'inout' position.
 
   void method25<X extends Contravariant<T>>() {}
-  //            ^
-  // [analyzer] unspecified
+  //            ^^^^^^^^^^^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   // [cfe] Can't use 'in' type variable 'T' in an 'inout' position.
 }
 
 mixin BMixin<in T> {
   // TODO (kallentu): Come NNBD, change `T` to `T?`
   T method1() => null;
+//^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //       ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'out' position in the return type.
 
   void method2(Contra<T> x) {}
+  //           ^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                     ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'out' position.
 
   Cov<T> method3() {
+//^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //            ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'out' position in the return type.
     return () => null;
   }
 
   void method4(Contra<Cov<T>> x) {}
+  //           ^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                          ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'out' position.
 
   void method5(Cov<Contra<T>> x) {}
+  //           ^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                          ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'out' position.
 
   Contra<Contra<T>> method6() => (Contra<T> x) {};
+//^^^^^^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                       ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'out' position in the return type.
 
   Cov<Cov<T>> method7() {
+//^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                 ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'out' position in the return type.
     return () {
       return () => null;
@@ -192,104 +219,119 @@
   }
 
   Inv<T> method8() => null;
+//^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //            ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'inout' position in the return type.
 
   void method9(Inv<T> x) {}
+  //           ^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                  ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'inout' position.
 
   Covariant<T> method10() => null;
+//^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                   ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'out' position in the return type.
 
   void method11(Contravariant<T> x) {}
+  //            ^^^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                             ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'out' position.
 
   Invariant<T> method12() => null;
+//^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                   ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'inout' position in the return type.
 
   void method13(Invariant<T> x) {}
+  //            ^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                         ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'inout' position.
 
   void method14(Contravariant<Covariant<T>> x) {}
+  //            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                                        ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'out' position.
 
   void method15(Covariant<Contravariant<T>> x) {}
+  //            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                                        ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'out' position.
 
   Contravariant<Contravariant<T>> method16() => Contravariant<Contravariant<T>>();
+//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                                      ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'out' position in the return type.
 
   Covariant<Covariant<T>> method17() => Covariant<Covariant<T>>();
+//^^^^^^^^^^^^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                              ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'out' position in the return type.
 
   void method18<X extends T>() {}
-  //            ^
-  // [analyzer] unspecified
+  //            ^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   // [cfe] Can't use 'in' type variable 'T' in an 'inout' position.
 
   void method19<X extends Cov<T>>() {}
-  //            ^
-  // [analyzer] unspecified
+  //            ^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   // [cfe] Can't use 'in' type variable 'T' in an 'inout' position.
 
   void method20<X extends Covariant<T>>() {}
-  //            ^
-  // [analyzer] unspecified
+  //            ^^^^^^^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   // [cfe] Can't use 'in' type variable 'T' in an 'inout' position.
 
   void method21({Contra<T> x}) {}
+  //             ^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                       ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'out' position.
 
   void method22({Contravariant<T> x}) {}
+  //             ^^^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                              ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'out' position.
 
   void method23({Covariant<T> x, Contravariant<T> y}) {}
+  //                             ^^^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                                              ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'out' position.
 
   void method24<X extends Contra<T>>() {}
-  //            ^
-  // [analyzer] unspecified
+  //            ^^^^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   // [cfe] Can't use 'in' type variable 'T' in an 'inout' position.
 
   void method25<X extends Contravariant<T>>() {}
-  //            ^
-  // [analyzer] unspecified
+  //            ^^^^^^^^^^^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   // [cfe] Can't use 'in' type variable 'T' in an 'inout' position.
 }
 
 class B<in T> {
   void method1(A<T> x) {}
+  //           ^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'out' position.
   Contra<A<T>> method2() {
+//^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                  ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'out' position in the return type.
     return null;
   }
@@ -302,7 +344,8 @@
 class D<in T> extends C<void Function(T)> {
   @override
   void method(void Function(T) x) {}
+  //          ^^^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                           ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'in' type variable 'T' in an 'out' position.
 }
diff --git a/tests/language_2/variance/variance_in_subclass_error_test.dart b/tests/language_2/variance/variance_in_subclass_error_test.dart
index 6899685..123b3e5 100644
--- a/tests/language_2/variance/variance_in_subclass_error_test.dart
+++ b/tests/language_2/variance/variance_in_subclass_error_test.dart
@@ -21,103 +21,124 @@
 
 class A<in T> extends LegacyCovariant<T> {}
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'LegacyCovariant'.
+//         ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class B<in T> implements LegacyCovariant<T> {}
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'LegacyCovariant'.
+//         ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class C<in T> with MLegacyCovariant<T> {}
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'MLegacyCovariant'.
+//         ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class D<in T> extends Covariant<T> {}
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'Covariant'.
+//         ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class E<in T> implements Covariant<T> {}
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'Covariant'.
+//         ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class F<in T> with MCovariant<T> {}
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'MCovariant'.
+//         ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class G<in T> extends Invariant<T> {}
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'in' type variable 'T' in an 'inout' position in supertype 'Invariant'.
+//         ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class H<in T> implements Invariant<T> {}
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'in' type variable 'T' in an 'inout' position in supertype 'Invariant'.
+//         ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class I<in T> with MInvariant<T> {}
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'in' type variable 'T' in an 'inout' position in supertype 'MInvariant'.
+//         ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class J<in T> extends Covariant<Covariant<T>> {}
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'Covariant'.
+//         ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class K<in T> extends Contravariant<Contravariant<T>> {}
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'Contravariant'.
+//         ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class L<in T> extends Covariant<CovFunction<T>> {}
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'Covariant'.
+//         ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class M<in T> extends Covariant<ContraFunction<ContraFunction<T>>> {}
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'Covariant'.
+//         ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class N<in T> extends Contravariant<CovFunction<Contravariant<T>>> {}
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'Contravariant'.
+//         ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class O<in T> extends Covariant<CovFunction<Covariant<T>>> {}
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'Covariant'.
+//         ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class P<in T> extends Covariant<Covariant<Covariant<T>>> {}
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'Covariant'.
+//         ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class Q<in T> extends Invariant<InvFunction<T>> {}
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'in' type variable 'T' in an 'inout' position in supertype 'Invariant'.
+//         ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class R<in T> = Covariant<T> with MContravariant<T>;
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'Covariant'.
+//         ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class S<in T> = Contravariant<T> with MCovariant<T>;
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'MCovariant'.
+//         ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class T<in X> = Invariant<X> with MInvariant<X>;
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'in' type variable 'X' in an 'inout' position in supertype 'Invariant'.
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'in' type variable 'X' in an 'inout' position in supertype 'MInvariant'.
+//         ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
+//         ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
diff --git a/tests/language_2/variance/variance_inout_inference_error_test.dart b/tests/language_2/variance/variance_inout_inference_error_test.dart
index 361ec92..ce4109f 100644
--- a/tests/language_2/variance/variance_inout_inference_error_test.dart
+++ b/tests/language_2/variance/variance_inout_inference_error_test.dart
@@ -23,38 +23,48 @@
 main() {
   // Middle <: T <: Middle and int <: T <: int are not valid constraints.
   inferInvInv(Invariant<Middle>(), Invariant<int>());
-  //          ^
-  // [analyzer] unspecified
+//^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
+  //          ^^^^^^^^^^^^^^^^^^^
+  // [analyzer] STATIC_WARNING.ARGUMENT_TYPE_NOT_ASSIGNABLE
   // [cfe] The argument type 'Invariant<Middle>' can't be assigned to the parameter type 'Invariant<Object>'.
-  //                               ^
-  // [analyzer] unspecified
+  //                               ^^^^^^^^^^^^^^^^
+  // [analyzer] STATIC_WARNING.ARGUMENT_TYPE_NOT_ASSIGNABLE
   // [cfe] The argument type 'Invariant<int>' can't be assigned to the parameter type 'Invariant<Object>'.
 
   // Middle <: T <: Middle and Upper <: T <: Upper are not valid constraints.
   inferInvInv(Invariant<Middle>(), Invariant<Upper>());
-  //          ^
-  // [analyzer] unspecified
+//^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
+  //          ^^^^^^^^^^^^^^^^^^^
+  // [analyzer] STATIC_WARNING.ARGUMENT_TYPE_NOT_ASSIGNABLE
   // [cfe] The argument type 'Invariant<Middle>' can't be assigned to the parameter type 'Invariant<Upper>'.
 
   // Middle <: T <: Middle and Lower <: T <: Lower are not valid constraints.
   inferInvInv(Invariant<Middle>(), Invariant<Lower>());
-  //                               ^
-  // [analyzer] unspecified
+//^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
+  //                               ^^^^^^^^^^^^^^^^^^
+  // [analyzer] STATIC_WARNING.ARGUMENT_TYPE_NOT_ASSIGNABLE
   // [cfe] The argument type 'Invariant<Lower>' can't be assigned to the parameter type 'Invariant<Middle>'.
 
   // Upper <: T
   // Middle <: T <: Middle
   // Upper <: T <: Middle is not a valid constraint.
   inferInvCov(Invariant<Middle>(), Covariant<Upper>());
-  //          ^
-  // [analyzer] unspecified
+//^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
+  //          ^^^^^^^^^^^^^^^^^^^
+  // [analyzer] STATIC_WARNING.ARGUMENT_TYPE_NOT_ASSIGNABLE
   // [cfe] The argument type 'Invariant<Middle>' can't be assigned to the parameter type 'Invariant<Upper>'.
 
   // T <: Lower
   // Middle <: T <: Lower
   // Middle <: T <: Lower is not a valid constraint
   inferInvContra(Invariant<Middle>(), Contravariant<Lower>());
-  //                                  ^
-  // [analyzer] unspecified
+//^^^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
+  //                                  ^^^^^^^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.INVALID_CAST_NEW_EXPR
   // [cfe] The constructor returns type 'Contravariant<Lower>' that isn't of expected type 'Contravariant<Middle>'.
 }
diff --git a/tests/language_2/variance/variance_inout_method_test.dart b/tests/language_2/variance/variance_inout_method_test.dart
index 62b1f2e..ae46510 100644
--- a/tests/language_2/variance/variance_inout_method_test.dart
+++ b/tests/language_2/variance/variance_inout_method_test.dart
@@ -273,6 +273,10 @@
 
   F<Object> f = new H<String>((String s) {});
   Expect.throws(() => f.method(3));
+
+  // Tests reified type is the type expected for F and not G.
+  Expect.type<int Function(Object)>(f.method);
+  Expect.type<int Function(Object)>(new H<String>((String s){}).method);
 }
 
 main() {
diff --git a/tests/language_2/variance/variance_method_tearoff_test.dart b/tests/language_2/variance/variance_method_tearoff_test.dart
new file mode 100644
index 0000000..03261ac
--- /dev/null
+++ b/tests/language_2/variance/variance_method_tearoff_test.dart
@@ -0,0 +1,52 @@
+// Copyright (c) 2019, 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.
+
+// Tests reified types of torn-off methods with type parameters that have
+// explicit variance modifiers.
+
+// SharedOptions=--enable-experiment=variance
+
+import "package:expect/expect.dart";
+
+class Contravariant<in T> {
+  int method(T x) {}
+}
+
+class Invariant<inout T> {
+  T method(T x) {}
+}
+
+class LegacyCovariant<T> {
+  int method(T x) {}
+}
+
+class NoSuchMethod<inout T> implements Invariant<T> {
+  noSuchMethod(_) => 3;
+}
+
+main() {
+  Contravariant<int> contraDiff = new Contravariant<num>();
+  Expect.notType<int Function(Object)>(contraDiff.method);
+  Expect.type<int Function(num)>(contraDiff.method);
+
+  Contravariant<num> contraSame = new Contravariant<num>();
+  Expect.notType<int Function(Object)>(contraSame.method);
+  Expect.type<int Function(num)>(contraSame.method);
+
+  Invariant<num> invSame = new Invariant<num>();
+  Expect.notType<num Function(Object)>(invSame.method);
+  Expect.type<num Function(num)>(invSame.method);
+
+  LegacyCovariant<num> legacyDiff = new LegacyCovariant<int>();
+  Expect.type<int Function(Object)>(legacyDiff.method);
+  Expect.type<int Function(num)>(legacyDiff.method);
+
+  LegacyCovariant<num> legacySame = new LegacyCovariant<num>();
+  Expect.type<int Function(Object)>(legacySame.method);
+  Expect.type<int Function(num)>(legacySame.method);
+
+  NoSuchMethod<num> nsm = new NoSuchMethod<num>();
+  Expect.notType<num Function(Object)>(nsm.method);
+  Expect.type<num Function(num)>(nsm.method);
+}
diff --git a/tests/language_2/variance/variance_multi_subclass_error_test.dart b/tests/language_2/variance/variance_multi_subclass_error_test.dart
index 18e2db2..ed790c7 100644
--- a/tests/language_2/variance/variance_multi_subclass_error_test.dart
+++ b/tests/language_2/variance/variance_multi_subclass_error_test.dart
@@ -17,55 +17,68 @@
 
 class A<in T, out U, inout V> extends Covariant<T> {}
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'Covariant'.
+//         ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class B<in T> extends MultiThree<T, T, T> {}
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'in' type variable 'T' in an 'inout' position in supertype 'MultiThree'.
+//         ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class C<in T, out U, inout V> extends MultiTwo<U, T> {}
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'MultiTwo'.
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'out' type variable 'U' in an 'in' position in supertype 'MultiTwo'.
+//         ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
+//                ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class D<in T, out U, inout V> extends MultiThree<V, U, T> {}
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'in' type variable 'T' in an 'inout' position in supertype 'MultiThree'.
+//         ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class E<in T, out U, inout V> extends MultiThree<Covariant<U>, Covariant<T>, Covariant<U>> {}
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'MultiThree'.
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'out' type variable 'U' in an 'inout' position in supertype 'MultiThree'.
+//         ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
+//                ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class F<in T, out U, inout V> extends MultiTwo<Contravariant<T>, Contravariant<U>> {}
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'MultiTwo'.
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'out' type variable 'U' in an 'in' position in supertype 'MultiTwo'.
+//         ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
+//                ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class G<in T, out U, inout V> extends MultiThree<CovFunction<U>, CovFunction<T>, CovFunction<U>> {}
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'MultiThree'.
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'out' type variable 'U' in an 'inout' position in supertype 'MultiThree'.
+//         ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
+//                ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class H<in T, out U, inout V> extends MultiTwo<ContraFunction<T>, ContraFunction<U>> {}
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'in' type variable 'T' in an 'out' position in supertype 'MultiTwo'.
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'out' type variable 'U' in an 'in' position in supertype 'MultiTwo'.
+//         ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
+//                ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
diff --git a/tests/language_2/variance/variance_out_field_error_test.dart b/tests/language_2/variance/variance_out_field_error_test.dart
index 629cf96..2123b9d 100644
--- a/tests/language_2/variance/variance_out_field_error_test.dart
+++ b/tests/language_2/variance/variance_out_field_error_test.dart
@@ -8,30 +8,46 @@
 
 class A<out T> {
   void set a(T value) => value;
+  //         ^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //           ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position.
   final void Function(T) b = (T val) {};
   //                     ^
-  // [analyzer] unspecified
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position.
   T c;
-  //^
-  // [analyzer] unspecified
-  // [cfe] Can't use 'out' type variable 'T' in an 'in' position.
+//  ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
+// [cfe] Can't use 'out' type variable 'T' in an 'in' position.
 }
 
 mixin BMixin<out T> {
   void set a(T value) => value;
+  //         ^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //           ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position.
   final void Function(T) b = (T val) {};
   //                     ^
-  // [analyzer] unspecified
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position.
   T c;
-  //^
-  // [analyzer] unspecified
+//  ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
+// [cfe] Can't use 'out' type variable 'T' in an 'in' position.
+}
+
+abstract class C<out T> {
+  void set a(T value) => value;
+  //         ^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
+  //           ^
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position.
 }
+
+class D<out T> extends C<T> {
+  var a;
+  //  ^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
+}
diff --git a/tests/language_2/variance/variance_out_inference_error_test.dart b/tests/language_2/variance/variance_out_inference_error_test.dart
index cc2f448..809cdfb 100644
--- a/tests/language_2/variance/variance_out_inference_error_test.dart
+++ b/tests/language_2/variance/variance_out_inference_error_test.dart
@@ -14,20 +14,47 @@
 class Middle extends Upper {}
 class Lower extends Middle {}
 
+class CovBound<out T> {
+  CovBound(T x, void Function(T) y) {}
+}
+
 Exactly<T> inferCovCov<T>(Covariant<T> x, Covariant<T> y) => new Exactly<T>();
+Exactly<T> inferCovBound<T>(CovBound<T> x) => new Exactly<T>();
 
 main() {
+  Exactly<Upper> upper;
+  Exactly<Middle> middle;
   Exactly<Lower> lower;
 
+  // Lower <: T <: Middle.
+  // We choose Middle.
   var inferredMiddle = inferCovCov(Covariant<Lower>(), Covariant<Middle>());
   lower = inferredMiddle;
-  //      ^
-  // [analyzer] unspecified
+  //      ^^^^^^^^^^^^^^
+  // [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT
   // [cfe] A value of type 'Exactly<Middle>' can't be assigned to a variable of type 'Exactly<Lower>'.
 
+  // Lower <: T <: Upper.
+  // We choose Upper.
   var inferredUpper = inferCovCov(Covariant<Lower>(), Covariant<Upper>());
   lower = inferredUpper;
-  //      ^
-  // [analyzer] unspecified
+  //      ^^^^^^^^^^^^^
+  // [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT
   // [cfe] A value of type 'Exactly<Upper>' can't be assigned to a variable of type 'Exactly<Lower>'.
+
+  // Inference for Covbound(...) produces Lower <: T <: Upper.
+  // Since T is covariant, we choose Lower as the solution.
+  var inferredCovLower = inferCovBound(CovBound(Lower(), (Upper x) {}));
+  upper = inferredCovLower;
+  //      ^^^^^^^^^^^^^^^^
+  // [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT
+  // [cfe] A value of type 'Exactly<Lower>' can't be assigned to a variable of type 'Exactly<Upper>'.
+
+  // Inference for Covbound(...) produces Lower <: T <: Middle.
+  // Since T is covariant, we choose Lower as the solution.
+  var inferredCovLower2 = inferCovBound(CovBound(Lower(), (Middle x) {}));
+  middle = inferredCovLower2;
+  //       ^^^^^^^^^^^^^^^^^
+  // [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT
+  // [cfe] A value of type 'Exactly<Lower>' can't be assigned to a variable of type 'Exactly<Middle>'.
 }
diff --git a/tests/language_2/variance/variance_out_inference_test.dart b/tests/language_2/variance/variance_out_inference_test.dart
index 8ba2f49..14b49e1 100644
--- a/tests/language_2/variance/variance_out_inference_test.dart
+++ b/tests/language_2/variance/variance_out_inference_test.dart
@@ -14,10 +14,16 @@
 class Middle extends Upper {}
 class Lower extends Middle {}
 
+class CovBound<out T> {
+  CovBound(T x, void Function(T) y) {}
+}
+
 Exactly<T> inferCovCov<T>(Covariant<T> x, Covariant<T> y) => new Exactly<T>();
+Exactly<T> inferCovBound<T>(CovBound<T> x) => new Exactly<T>();
 
 main() {
   Exactly<Upper> upper;
+  Exactly<Lower> lower;
 
   // Upper <: T
   // Upper <: T
@@ -36,4 +42,14 @@
   // Choose Upper since it is the lowest upper bound of Upper and Lower.
   var inferredUpper3 = inferCovCov(Covariant<Upper>(), Covariant<Lower>());
   upper = inferredUpper3;
+
+  // Lower <: T <: Upper
+  // Choose Lower.
+  var inferredCovLower = inferCovBound(CovBound(Lower(), (Upper x) {}));
+  lower = inferredCovLower;
+
+  // Lower <: T <: Middle
+  // Choose Lower.
+  var inferredCovLower2 = inferCovBound(CovBound(Lower(), (Middle x) {}));
+  lower = inferredCovLower2;
 }
diff --git a/tests/language_2/variance/variance_out_method_error_test.dart b/tests/language_2/variance/variance_out_method_error_test.dart
index 905763a..1705207 100644
--- a/tests/language_2/variance/variance_out_method_error_test.dart
+++ b/tests/language_2/variance/variance_out_method_error_test.dart
@@ -16,33 +16,39 @@
 
 class A<out T> {
   void method1(T x) {}
+  //           ^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //             ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position.
 
   void method2(Cov<T> x) {}
+  //           ^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                  ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position.
 
   Contra<T> method3() => (T val) {};
+//^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //               ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position in the return type.
 
   void method4(Cov<Cov<T>> x) {}
+  //           ^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                       ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position.
 
   Contra<Cov<T>> method5() => (Cov<T> method) {};
+//^^^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                    ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position in the return type.
 
   Cov<Contra<T>> method6() {
+//^^^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                    ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position in the return type.
     return () {
       return (T x) {};
@@ -50,135 +56,156 @@
   }
 
   void method7(Contra<Contra<T>> x) {}
+  //           ^^^^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                             ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position.
 
   Inv<T> method8() => null;
+//^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //            ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'inout' position in the return type.
 
   void method9(Inv<T> x) {}
+  //           ^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                  ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'inout' position.
 
   Contravariant<T> method10() => null;
+//^^^^^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                       ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position in the return type.
 
   void method11(Covariant<T> x) {}
+  //            ^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                         ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position.
 
   Invariant<T> method12() => null;
+//^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                   ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'inout' position in the return type.
 
   void method13(Invariant<T> x) {}
+  //            ^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                         ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'inout' position.
 
   void method14(Covariant<Covariant<T>> x) {}
+  //            ^^^^^^^^^^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                                    ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position.
 
   void method15(Contravariant<Contravariant<T>> x) {}
+  //            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                                            ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position.
 
   Contravariant<Covariant<T>> method16() => Contravariant<Covariant<T>>();
+//^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                                  ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position in the return type.
 
   Covariant<Contravariant<T>> method17() => Covariant<Contravariant<T>>();
+//^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                                  ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position in the return type.
 
   void method18<X extends Contra<T>>() {}
-  //            ^
-  // [analyzer] unspecified
+  //            ^^^^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   // [cfe] Can't use 'out' type variable 'T' in an 'inout' position.
 
   void method19<X extends Contravariant<T>>() {}
-  //            ^
-  // [analyzer] unspecified
+  //            ^^^^^^^^^^^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   // [cfe] Can't use 'out' type variable 'T' in an 'inout' position.
 
   void method20({T x}) {}
+  //             ^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //               ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position.
 
   void method21({Cov<T> x}) {}
+  //             ^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                    ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position.
 
   void method22({Covariant<T> x}) {}
+  //             ^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                          ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position.
 
   void method23({Covariant<T> x, Contravariant<T> y}) {}
+  //             ^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                          ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position.
 
   void method24<X extends T>() {}
-  //            ^
-  // [analyzer] unspecified
+  //            ^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   // [cfe] Can't use 'out' type variable 'T' in an 'inout' position.
 
   void method25<X extends Contra<T>>() {}
-  //            ^
-  // [analyzer] unspecified
+  //            ^^^^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   // [cfe] Can't use 'out' type variable 'T' in an 'inout' position.
 
   void method26<X extends Contravariant<T>>() {}
-  //            ^
-  // [analyzer] unspecified
+  //            ^^^^^^^^^^^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   // [cfe] Can't use 'out' type variable 'T' in an 'inout' position.
 }
 
 mixin BMixin<out T> {
   void method1(T x) {}
+  //           ^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //             ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position.
 
   void method2(Cov<T> x) {}
+  //           ^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                  ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position.
 
   Contra<T> method3() => (T val) {};
+//^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //               ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position in the return type.
 
   void method4(Cov<Cov<T>> x) {}
+  //           ^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                       ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position.
 
   Contra<Cov<T>> method5() => (Cov<T> method) {};
+//^^^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                    ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position in the return type.
 
   Cov<Contra<T>> method6() {
+//^^^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                    ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position in the return type.
     return () {
       return (T x) {};
@@ -186,114 +213,131 @@
   }
 
   void method7(Contra<Contra<T>> x) {}
+  //           ^^^^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                             ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position.
 
   Inv<T> method8() => null;
+//^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //            ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'inout' position in the return type.
 
   void method9(Inv<T> x) {}
+  //           ^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                  ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'inout' position.
 
   Contravariant<T> method10() => null;
+//^^^^^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                       ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position in the return type.
 
   void method11(Covariant<T> x) {}
+  //            ^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                         ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position.
 
   Invariant<T> method12() => null;
+//^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                   ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'inout' position in the return type.
 
   void method13(Invariant<T> x) {}
+  //            ^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                         ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'inout' position.
 
   void method14(Covariant<Covariant<T>> x) {}
+  //            ^^^^^^^^^^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                                    ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position.
 
   void method15(Contravariant<Contravariant<T>> x) {}
+  //            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                                            ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position.
 
   Contravariant<Covariant<T>> method16() => Contravariant<Covariant<T>>();
+//^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                                  ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position in the return type.
 
   Covariant<Contravariant<T>> method17() => Covariant<Contravariant<T>>();
+//^^^^^^^^^^^^^^^^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                                  ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position in the return type.
 
   void method18<X extends Contra<T>>() {}
-  //            ^
-  // [analyzer] unspecified
+  //            ^^^^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   // [cfe] Can't use 'out' type variable 'T' in an 'inout' position.
 
   void method19<X extends Contravariant<T>>() {}
-  //            ^
-  // [analyzer] unspecified
+  //            ^^^^^^^^^^^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   // [cfe] Can't use 'out' type variable 'T' in an 'inout' position.
 
   void method20({T x}) {}
+  //             ^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //               ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position.
 
   void method21({Cov<T> x}) {}
+  //             ^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                    ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position.
 
   void method22({Covariant<T> x}) {}
+  //             ^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                          ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position.
 
   void method23({Covariant<T> x, Contravariant<T> y}) {}
+  //             ^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                          ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position.
 
   void method24<X extends T>() {}
-  //            ^
-  // [analyzer] unspecified
+  //            ^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   // [cfe] Can't use 'out' type variable 'T' in an 'inout' position.
 
   void method25<X extends Contra<T>>() {}
-  //            ^
-  // [analyzer] unspecified
+  //            ^^^^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   // [cfe] Can't use 'out' type variable 'T' in an 'inout' position.
 
   void method26<X extends Contravariant<T>>() {}
-  //            ^
-  // [analyzer] unspecified
+  //            ^^^^^^^^^^^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   // [cfe] Can't use 'out' type variable 'T' in an 'inout' position.
 }
 
 class B<out T> {
   void method1(Cov<A<T>> x) {}
+  //           ^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                     ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position.
   Contra<A<T>> method2() {
+//^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //                  ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position in the return type.
     return null;
   }
@@ -306,7 +350,8 @@
 class D<out T> extends C<T> {
   @override
   void method(T x) {}
+  //          ^^^
+  // [analyzer] COMPILE_TIME_ERROR.WRONG_TYPE_PARAMETER_VARIANCE_POSITION
   //            ^
-  // [analyzer] unspecified
   // [cfe] Can't use 'out' type variable 'T' in an 'in' position.
 }
diff --git a/tests/language_2/variance/variance_out_subclass_error_test.dart b/tests/language_2/variance/variance_out_subclass_error_test.dart
index a6d783a..046395c 100644
--- a/tests/language_2/variance/variance_out_subclass_error_test.dart
+++ b/tests/language_2/variance/variance_out_subclass_error_test.dart
@@ -19,88 +19,106 @@
 
 class A<out T> extends Contravariant<T> {}
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'out' type variable 'T' in an 'in' position in supertype 'Contravariant'.
+//          ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class B<out T> implements Contravariant<T> {}
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'out' type variable 'T' in an 'in' position in supertype 'Contravariant'.
+//          ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class C<out T> with MContravariant<T> {}
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'out' type variable 'T' in an 'in' position in supertype 'MContravariant'.
+//          ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class D<out T> extends Invariant<T> {}
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'out' type variable 'T' in an 'inout' position in supertype 'Invariant'.
+//          ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class E<out T> implements Invariant<T> {}
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'out' type variable 'T' in an 'inout' position in supertype 'Invariant'.
+//          ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class F<out T> with MInvariant<T> {}
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'out' type variable 'T' in an 'in' position in supertype 'MInvariant'.
+//          ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class G<out T> extends Covariant<Contravariant<T>> {}
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'out' type variable 'T' in an 'in' position in supertype 'Covariant'.
+//          ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class H<out T> extends Contravariant<Covariant<T>> {}
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'out' type variable 'T' in an 'in' position in supertype 'Contravariant'.
+//          ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class I<out T> extends Covariant<ContraFunction<T>> {}
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'out' type variable 'T' in an 'in' position in supertype 'Covariant'.
+//          ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class J<out T> extends Covariant<ContraFunction<CovFunction<T>>> {}
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'out' type variable 'T' in an 'in' position in supertype 'Covariant'.
+//          ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class K<out T> extends Covariant<CovFunction<ContraFunction<T>>> {}
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'out' type variable 'T' in an 'in' position in supertype 'Covariant'.
+//          ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class L<out T> extends Covariant<ContraFunction<Covariant<T>>> {}
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'out' type variable 'T' in an 'in' position in supertype 'Covariant'.
+//          ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class M<out T> extends Contravariant<Contravariant<Contravariant<T>>> {}
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'out' type variable 'T' in an 'in' position in supertype 'Contravariant'.
+//          ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class N<out T> extends Covariant<InvFunction<T>> {}
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'out' type variable 'T' in an 'inout' position in supertype 'Covariant'.
+//          ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class O<out T> = Covariant<T> with MContravariant<T>;
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'out' type variable 'T' in an 'in' position in supertype 'MContravariant'.
+//          ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class P<out T> = Contravariant<T> with MCovariant<T>;
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'out' type variable 'T' in an 'in' position in supertype 'Contravariant'.
+//          ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
 
 class Q<out T> = Invariant<T> with MInvariant<T>;
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'out' type variable 'T' in an 'in' position in supertype 'MInvariant'.
 //    ^
-// [analyzer] unspecified
 // [cfe] Can't use 'out' type variable 'T' in an 'inout' position in supertype 'Invariant'.
+//          ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
+//          ^
+// [analyzer] COMPILE_TIME_ERROR.WRONG_EXPLICIT_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE
diff --git a/tests/language_2/vm/causal_async_exception_stack2_test.dart b/tests/language_2/vm/causal_async_exception_stack2_test.dart
index 94dda4b..4efca8f 100644
--- a/tests/language_2/vm/causal_async_exception_stack2_test.dart
+++ b/tests/language_2/vm/causal_async_exception_stack2_test.dart
@@ -29,11 +29,8 @@
     expect(
         h.stringContainsInOrder(st.toString(), [
           'foo3',
-          '<asynchronous suspension>',
           'foo2',
-          '<asynchronous suspension>',
           'foo',
-          '<asynchronous suspension>',
           'test1',
         ]),
         isTrue);
@@ -47,11 +44,8 @@
     expect(
         h.stringContainsInOrder(st.toString(), [
           'bar3',
-          '<asynchronous suspension>',
           'bar2',
-          '<asynchronous suspension>',
           'bar',
-          '<asynchronous suspension>',
           'test1',
         ]),
         isTrue);
@@ -72,11 +66,8 @@
     expect(
         h.stringContainsInOrder(st.toString(), [
           'foo3',
-          '<asynchronous suspension>',
           'foo2',
-          '<asynchronous suspension>',
           'foo',
-          '<asynchronous suspension>',
           'test2',
         ]),
         isTrue);
@@ -90,11 +81,8 @@
     expect(
         h.stringContainsInOrder(st.toString(), [
           'bar3',
-          '<asynchronous suspension>',
           'bar2',
-          '<asynchronous suspension>',
           'bar',
-          '<asynchronous suspension>',
           'test2',
         ]),
         isTrue);
diff --git a/tests/language_2/vm/causal_async_exception_stack_test.dart b/tests/language_2/vm/causal_async_exception_stack_test.dart
index b4059e9..caba5d9 100644
--- a/tests/language_2/vm/causal_async_exception_stack_test.dart
+++ b/tests/language_2/vm/causal_async_exception_stack_test.dart
@@ -35,11 +35,9 @@
       expect(
           h.stringContainsInOrder(st.toString(), [
             'thrower', '.dart:10', //
-            '<asynchronous suspension>', //
             'generator', '.dart:19', //
             '<asynchronous suspension>', //
             'foo', '.dart:23', //
-            '<asynchronous suspension>', //
             'main', //
           ]),
           isTrue);
@@ -60,11 +58,8 @@
       expect(
           h.stringContainsInOrder(st.toString(), [
             'thrower',
-            '<asynchronous suspension>',
             'main.<anonymous closure>.inner.deep',
-            '<asynchronous suspension>',
             'main.<anonymous closure>.inner',
-            '<asynchronous suspension>',
             'main',
             '<asynchronous suspension>',
           ]),
@@ -78,8 +73,7 @@
       expect(
           h.stringContainsInOrder(st.toString(), [
             'thrower', '.dart:10', //
-            '<asynchronous suspension>', //
-            'main.<anonymous closure>', '.dart:76', //
+            'main.<anonymous closure>', '.dart:71', //
           ]),
           isTrue);
     }
diff --git a/tests/language_2/vm/deep_loop_test.dart b/tests/language_2/vm/deep_loop_test.dart
new file mode 100644
index 0000000..dea7d53
--- /dev/null
+++ b/tests/language_2/vm/deep_loop_test.dart
@@ -0,0 +1,363 @@
+// Copyright (c) 2019, 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';
+
+// Stress tests on loop nesting depth. Make sure loop and induction
+// analysis do not break down (excessive compile-time or otherwise)
+// when analyzing a deeply nested loop with dependent bounds.
+
+@pragma("vm:never-inline")
+foo(List<int> a) {
+  for (int i0 = 100; i0 <= a.length - 101; i0++)
+    for (int i1 = i0 - 1; i1 <= i0 + 1; i1++)
+      for (int i2 = i1 - 1; i2 <= i1 + 1; i2++)
+        for (int i3 = i2 - 1; i3 <= i2 + 1; i3++)
+          for (int i4 = i3 - 1; i4 <= i3 + 1; i4++)
+            for (int i5 = i4 - 1; i5 <= i4 + 1; i5++)
+              for (int i6 = i5 - 1; i6 <= i5 + 1; i6++)
+                for (int i7 = i6 - 1; i7 <= i6 + 1; i7++)
+                  for (int i8 = i7 - 1; i8 <= i7 + 1; i8++)
+                    for (int i9 = i8 - 1; i9 <= i8 + 1; i9++)
+                      for (int i10 = i9 - 1; i10 <= i9 + 1; i10++)
+                        for (int i11 = i10 - 1; i11 <= i10 + 1; i11++)
+                          for (int i12 = i11 - 1; i12 <= i11 + 1; i12++)
+                            for (int i13 = i12 - 1; i13 <= i12 + 1; i13++)
+                              for (int i14 = i13 - 1; i14 <= i13 + 1; i14++)
+                                for (int i15 = i14 - 1; i15 <= i14 + 1; i15++)
+                                  for (int i16 = i15 - 1; i16 <= i15 + 1; i16++)
+                                    for (int i17 = i16 - 1;
+                                        i17 <= i16 + 1;
+                                        i17++)
+                                      for (int i18 = i17 - 1;
+                                          i18 <= i17 + 1;
+                                          i18++)
+                                        for (int i19 = i18 - 1;
+                                            i19 <= i18 + 1;
+                                            i19++)
+                                          for (int i20 = i19 - 1;
+                                              i20 <= i19 + 1;
+                                              i20++)
+                                            for (int i21 = i20 - 1;
+                                                i21 <= i20 + 1;
+                                                i21++)
+                                              for (int i22 = i21 - 1;
+                                                  i22 <= i21 + 1;
+                                                  i22++)
+                                                for (int i23 = i22 - 1;
+                                                    i23 <= i22 + 1;
+                                                    i23++)
+                                                  for (int i24 = i23 - 1;
+                                                      i24 <= i23 + 1;
+                                                      i24++)
+                                                    for (int i25 = i24 - 1;
+                                                        i25 <= i24 + 1;
+                                                        i25++)
+                                                      for (int i26 = i25 - 1;
+                                                          i26 <= i25 + 1;
+                                                          i26++)
+                                                        for (int i27 = i26 - 1;
+                                                            i27 <= i26 + 1;
+                                                            i27++)
+                                                          for (int i28 =
+                                                                  i27 - 1;
+                                                              i28 <= i27 + 1;
+                                                              i28++)
+                                                            for (int i29 =
+                                                                    i28 - 1;
+                                                                i29 <= i28 + 1;
+                                                                i29++)
+                                                              for (int i30 =
+                                                                      i29 - 1;
+                                                                  i30 <=
+                                                                      i29 + 1;
+                                                                  i30++)
+                                                                for (int i31 =
+                                                                        i30 - 1;
+                                                                    i31 <=
+                                                                        i30 + 1;
+                                                                    i31++)
+                                                                  for (int i32 =
+                                                                          i31 -
+                                                                              1;
+                                                                      i32 <=
+                                                                          i31 +
+                                                                              1;
+                                                                      i32++)
+                                                                    for (int i33 =
+                                                                            i32 -
+                                                                                1;
+                                                                        i33 <=
+                                                                            i32 +
+                                                                                1;
+                                                                        i33++)
+                                                                      for (int i34 = i33 -
+                                                                              1;
+                                                                          i34 <=
+                                                                              i33 + 1;
+                                                                          i34++)
+                                                                        for (int i35 = i34 -
+                                                                                1;
+                                                                            i35 <=
+                                                                                i34 + 1;
+                                                                            i35++)
+                                                                          for (int i36 = i35 - 1;
+                                                                              i36 <= i35 + 1;
+                                                                              i36++)
+                                                                            for (int i37 = i36 - 1;
+                                                                                i37 <= i36 + 1;
+                                                                                i37++)
+                                                                              for (int i38 = i37 - 1; i38 <= i37 + 1; i38++)
+                                                                                for (int i39 = i38 - 1; i39 <= i38 + 1; i39++)
+                                                                                  for (int i40 = i39 - 1; i40 <= i39 + 1; i40++)
+                                                                                    for (int i41 = i40 - 1; i41 <= i40 + 1; i41++)
+                                                                                      for (int i42 = i41 - 1; i42 <= i41 + 1; i42++)
+                                                                                        for (int i43 = i42 - 1; i43 <= i42 + 1; i43++)
+                                                                                          for (int i44 = i43 - 1; i44 <= i43 + 1; i44++)
+                                                                                            for (int i45 = i44 - 1; i45 <= i44 + 1; i45++)
+                                                                                              for (int i46 = i45 - 1; i46 <= i45 + 1; i46++)
+                                                                                                for (int i47 = i46 - 1; i47 <= i46 + 1; i47++)
+                                                                                                  for (int i48 = i47 - 1; i48 <= i47 + 1; i48++)
+                                                                                                    for (int i49 = i48 - 1; i49 <= i48 + 1; i49++)
+                                                                                                      for (int i50 = i49 - 1; i50 <= i49 + 1; i50++)
+                                                                                                        for (int i51 = i50 - 1; i51 <= i50 + 1; i51++)
+                                                                                                          for (int i52 = i51 - 1; i52 <= i51 + 1; i52++)
+                                                                                                            for (int i53 = i52 - 1; i53 <= i52 + 1; i53++)
+                                                                                                              for (int i54 = i53 - 1; i54 <= i53 + 1; i54++)
+                                                                                                                for (int i55 = i54 - 1; i55 <= i54 + 1; i55++)
+                                                                                                                  for (int i56 = i55 - 1; i56 <= i55 + 1; i56++)
+                                                                                                                    for (int i57 = i56 - 1; i57 <= i56 + 1; i57++)
+                                                                                                                      for (int i58 = i57 - 1; i58 <= i57 + 1; i58++)
+                                                                                                                        for (int i59 = i58 - 1; i59 <= i58 + 1; i59++)
+                                                                                                                          for (int i60 = i59 - 1; i60 <= i59 + 1; i60++)
+                                                                                                                            for (int i61 = i60 - 1; i61 <= i60 + 1; i61++)
+                                                                                                                              for (int i62 = i61 - 1; i62 <= i61 + 1; i62++)
+                                                                                                                                for (int i63 = i62 - 1; i63 <= i62 + 1; i63++)
+                                                                                                                                  for (int i64 = i63 - 1; i64 <= i63 + 1; i64++)
+                                                                                                                                    for (int i65 = i64 - 1; i65 <= i64 + 1; i65++)
+                                                                                                                                      for (int i66 = i65 - 1; i66 <= i65 + 1; i66++)
+                                                                                                                                        for (int i67 = i66 - 1; i67 <= i66 + 1; i67++)
+                                                                                                                                          for (int i68 = i67 - 1; i68 <= i67 + 1; i68++)
+                                                                                                                                            for (int i69 = i68 - 1; i69 <= i68 + 1; i69++)
+                                                                                                                                              for (int i70 = i69 - 1; i70 <= i69 + 1; i70++)
+                                                                                                                                                for (int i71 = i70 - 1; i71 <= i70 + 1; i71++)
+                                                                                                                                                  for (int i72 = i71 - 1; i72 <= i71 + 1; i72++)
+                                                                                                                                                    for (int i73 = i72 - 1; i73 <= i72 + 1; i73++)
+                                                                                                                                                      for (int i74 = i73 - 1; i74 <= i73 + 1; i74++)
+                                                                                                                                                        for (int i75 = i74 - 1; i75 <= i74 + 1; i75++)
+                                                                                                                                                          for (int i76 = i75 - 1; i76 <= i75 + 1; i76++)
+                                                                                                                                                            for (int i77 = i76 - 1; i77 <= i76 + 1; i77++)
+                                                                                                                                                              for (int i78 = i77 - 1; i78 <= i77 + 1; i78++)
+                                                                                                                                                                for (int i79 = i78 - 1; i79 <= i78 + 1; i79++)
+                                                                                                                                                                  for (int i80 = i79 - 1; i80 <= i79 + 1; i80++)
+                                                                                                                                                                    for (int i81 = i80 - 1; i81 <= i80 + 1; i81++)
+                                                                                                                                                                      for (int i82 = i81 - 1; i82 <= i81 + 1; i82++)
+                                                                                                                                                                        for (int i83 = i82 - 1; i83 <= i82 + 1; i83++)
+                                                                                                                                                                          for (int i84 = i83 - 1; i84 <= i83 + 1; i84++)
+                                                                                                                                                                            for (int i85 = i84 - 1; i85 <= i84 + 1; i85++)
+                                                                                                                                                                              for (int i86 = i85 - 1; i86 <= i85 + 1; i86++)
+                                                                                                                                                                                for (int i87 = i86 - 1; i87 <= i86 + 1; i87++)
+                                                                                                                                                                                  for (int i88 = i87 - 1; i88 <= i87 + 1; i88++)
+                                                                                                                                                                                    for (int i89 = i88 - 1; i89 <= i88 + 1; i89++)
+                                                                                                                                                                                      for (int i90 = i89 - 1; i90 <= i89 + 1; i90++)
+                                                                                                                                                                                        for (int i91 = i90 - 1; i91 <= i90 + 1; i91++)
+                                                                                                                                                                                          for (int i92 = i91 - 1; i92 <= i91 + 1; i92++)
+                                                                                                                                                                                            for (int i93 = i92 - 1; i93 <= i92 + 1; i93++)
+                                                                                                                                                                                              for (int i94 = i93 - 1; i94 <= i93 + 1; i94++)
+                                                                                                                                                                                                for (int i95 = i94 - 1; i95 <= i94 + 1; i95++)
+                                                                                                                                                                                                  for (int i96 = i95 - 1; i96 <= i95 + 1; i96++)
+                                                                                                                                                                                                    for (int i97 = i96 - 1; i97 <= i96 + 1; i97++)
+                                                                                                                                                                                                      for (int i98 = i97 - 1; i98 <= i97 + 1; i98++)
+                                                                                                                                                                                                        for (int i99 = i98 - 1; i99 <= i98 + 1; i99++)
+                                                                                                                                                                                                          for (int i100 = i99 - 1; i100 <= i99 + 1; i100++) {
+                                                                                                                                                                                                            // Range [0,a.length).
+                                                                                                                                                                                                            a[i100] += 1;
+                                                                                                                                                                                                          }
+}
+
+@pragma("vm:never-inline")
+bar(List<int> a) {
+  for (int i0 = a.length - 101; i0 >= 100; i0--)
+    for (int i1 = i0 + 1; i1 >= i0 - 1; i1--)
+      for (int i2 = i1 + 1; i2 >= i1 - 1; i2--)
+        for (int i3 = i2 + 1; i3 >= i2 - 1; i3--)
+          for (int i4 = i3 + 1; i4 >= i3 - 1; i4--)
+            for (int i5 = i4 + 1; i5 >= i4 - 1; i5--)
+              for (int i6 = i5 + 1; i6 >= i5 - 1; i6--)
+                for (int i7 = i6 + 1; i7 >= i6 - 1; i7--)
+                  for (int i8 = i7 + 1; i8 >= i7 - 1; i8--)
+                    for (int i9 = i8 + 1; i9 >= i8 - 1; i9--)
+                      for (int i10 = i9 + 1; i10 >= i9 - 1; i10--)
+                        for (int i11 = i10 + 1; i11 >= i10 - 1; i11--)
+                          for (int i12 = i11 + 1; i12 >= i11 - 1; i12--)
+                            for (int i13 = i12 + 1; i13 >= i12 - 1; i13--)
+                              for (int i14 = i13 + 1; i14 >= i13 - 1; i14--)
+                                for (int i15 = i14 + 1; i15 >= i14 - 1; i15--)
+                                  for (int i16 = i15 + 1; i16 >= i15 - 1; i16--)
+                                    for (int i17 = i16 + 1;
+                                        i17 >= i16 - 1;
+                                        i17--)
+                                      for (int i18 = i17 + 1;
+                                          i18 >= i17 - 1;
+                                          i18--)
+                                        for (int i19 = i18 + 1;
+                                            i19 >= i18 - 1;
+                                            i19--)
+                                          for (int i20 = i19 + 1;
+                                              i20 >= i19 - 1;
+                                              i20--)
+                                            for (int i21 = i20 + 1;
+                                                i21 >= i20 - 1;
+                                                i21--)
+                                              for (int i22 = i21 + 1;
+                                                  i22 >= i21 - 1;
+                                                  i22--)
+                                                for (int i23 = i22 + 1;
+                                                    i23 >= i22 - 1;
+                                                    i23--)
+                                                  for (int i24 = i23 + 1;
+                                                      i24 >= i23 - 1;
+                                                      i24--)
+                                                    for (int i25 = i24 + 1;
+                                                        i25 >= i24 - 1;
+                                                        i25--)
+                                                      for (int i26 = i25 + 1;
+                                                          i26 >= i25 - 1;
+                                                          i26--)
+                                                        for (int i27 = i26 + 1;
+                                                            i27 >= i26 - 1;
+                                                            i27--)
+                                                          for (int i28 =
+                                                                  i27 + 1;
+                                                              i28 >= i27 - 1;
+                                                              i28--)
+                                                            for (int i29 =
+                                                                    i28 + 1;
+                                                                i29 >= i28 - 1;
+                                                                i29--)
+                                                              for (int i30 =
+                                                                      i29 + 1;
+                                                                  i30 >=
+                                                                      i29 - 1;
+                                                                  i30--)
+                                                                for (int i31 =
+                                                                        i30 + 1;
+                                                                    i31 >=
+                                                                        i30 - 1;
+                                                                    i31--)
+                                                                  for (int i32 =
+                                                                          i31 +
+                                                                              1;
+                                                                      i32 >=
+                                                                          i31 -
+                                                                              1;
+                                                                      i32--)
+                                                                    for (int i33 =
+                                                                            i32 +
+                                                                                1;
+                                                                        i33 >=
+                                                                            i32 -
+                                                                                1;
+                                                                        i33--)
+                                                                      for (int i34 = i33 +
+                                                                              1;
+                                                                          i34 >=
+                                                                              i33 - 1;
+                                                                          i34--)
+                                                                        for (int i35 = i34 +
+                                                                                1;
+                                                                            i35 >=
+                                                                                i34 - 1;
+                                                                            i35--)
+                                                                          for (int i36 = i35 + 1;
+                                                                              i36 >= i35 - 1;
+                                                                              i36--)
+                                                                            for (int i37 = i36 + 1;
+                                                                                i37 >= i36 - 1;
+                                                                                i37--)
+                                                                              for (int i38 = i37 + 1; i38 >= i37 - 1; i38--)
+                                                                                for (int i39 = i38 + 1; i39 >= i38 - 1; i39--)
+                                                                                  for (int i40 = i39 + 1; i40 >= i39 - 1; i40--)
+                                                                                    for (int i41 = i40 + 1; i41 >= i40 - 1; i41--)
+                                                                                      for (int i42 = i41 + 1; i42 >= i41 - 1; i42--)
+                                                                                        for (int i43 = i42 + 1; i43 >= i42 - 1; i43--)
+                                                                                          for (int i44 = i43 + 1; i44 >= i43 - 1; i44--)
+                                                                                            for (int i45 = i44 + 1; i45 >= i44 - 1; i45--)
+                                                                                              for (int i46 = i45 + 1; i46 >= i45 - 1; i46--)
+                                                                                                for (int i47 = i46 + 1; i47 >= i46 - 1; i47--)
+                                                                                                  for (int i48 = i47 + 1; i48 >= i47 - 1; i48--)
+                                                                                                    for (int i49 = i48 + 1; i49 >= i48 - 1; i49--)
+                                                                                                      for (int i50 = i49 + 1; i50 >= i49 - 1; i50--)
+                                                                                                        for (int i51 = i50 + 1; i51 >= i50 - 1; i51--)
+                                                                                                          for (int i52 = i51 + 1; i52 >= i51 - 1; i52--)
+                                                                                                            for (int i53 = i52 + 1; i53 >= i52 - 1; i53--)
+                                                                                                              for (int i54 = i53 + 1; i54 >= i53 - 1; i54--)
+                                                                                                                for (int i55 = i54 + 1; i55 >= i54 - 1; i55--)
+                                                                                                                  for (int i56 = i55 + 1; i56 >= i55 - 1; i56--)
+                                                                                                                    for (int i57 = i56 + 1; i57 >= i56 - 1; i57--)
+                                                                                                                      for (int i58 = i57 + 1; i58 >= i57 - 1; i58--)
+                                                                                                                        for (int i59 = i58 + 1; i59 >= i58 - 1; i59--)
+                                                                                                                          for (int i60 = i59 + 1; i60 >= i59 - 1; i60--)
+                                                                                                                            for (int i61 = i60 + 1; i61 >= i60 - 1; i61--)
+                                                                                                                              for (int i62 = i61 + 1; i62 >= i61 - 1; i62--)
+                                                                                                                                for (int i63 = i62 + 1; i63 >= i62 - 1; i63--)
+                                                                                                                                  for (int i64 = i63 + 1; i64 >= i63 - 1; i64--)
+                                                                                                                                    for (int i65 = i64 + 1; i65 >= i64 - 1; i65--)
+                                                                                                                                      for (int i66 = i65 + 1; i66 >= i65 - 1; i66--)
+                                                                                                                                        for (int i67 = i66 + 1; i67 >= i66 - 1; i67--)
+                                                                                                                                          for (int i68 = i67 + 1; i68 >= i67 - 1; i68--)
+                                                                                                                                            for (int i69 = i68 + 1; i69 >= i68 - 1; i69--)
+                                                                                                                                              for (int i70 = i69 + 1; i70 >= i69 - 1; i70--)
+                                                                                                                                                for (int i71 = i70 + 1; i71 >= i70 - 1; i71--)
+                                                                                                                                                  for (int i72 = i71 + 1; i72 >= i71 - 1; i72--)
+                                                                                                                                                    for (int i73 = i72 + 1; i73 >= i72 - 1; i73--)
+                                                                                                                                                      for (int i74 = i73 + 1; i74 >= i73 - 1; i74--)
+                                                                                                                                                        for (int i75 = i74 + 1; i75 >= i74 - 1; i75--)
+                                                                                                                                                          for (int i76 = i75 + 1; i76 >= i75 - 1; i76--)
+                                                                                                                                                            for (int i77 = i76 + 1; i77 >= i76 - 1; i77--)
+                                                                                                                                                              for (int i78 = i77 + 1; i78 >= i77 - 1; i78--)
+                                                                                                                                                                for (int i79 = i78 + 1; i79 >= i78 - 1; i79--)
+                                                                                                                                                                  for (int i80 = i79 + 1; i80 >= i79 - 1; i80--)
+                                                                                                                                                                    for (int i81 = i80 + 1; i81 >= i80 - 1; i81--)
+                                                                                                                                                                      for (int i82 = i81 + 1; i82 >= i81 - 1; i82--)
+                                                                                                                                                                        for (int i83 = i82 + 1; i83 >= i82 - 1; i83--)
+                                                                                                                                                                          for (int i84 = i83 + 1; i84 >= i83 - 1; i84--)
+                                                                                                                                                                            for (int i85 = i84 + 1; i85 >= i84 - 1; i85--)
+                                                                                                                                                                              for (int i86 = i85 + 1; i86 >= i85 - 1; i86--)
+                                                                                                                                                                                for (int i87 = i86 + 1; i87 >= i86 - 1; i87--)
+                                                                                                                                                                                  for (int i88 = i87 + 1; i88 >= i87 - 1; i88--)
+                                                                                                                                                                                    for (int i89 = i88 + 1; i89 >= i88 - 1; i89--)
+                                                                                                                                                                                      for (int i90 = i89 + 1; i90 >= i89 - 1; i90--)
+                                                                                                                                                                                        for (int i91 = i90 + 1; i91 >= i90 - 1; i91--)
+                                                                                                                                                                                          for (int i92 = i91 + 1; i92 >= i91 - 1; i92--)
+                                                                                                                                                                                            for (int i93 = i92 + 1; i93 >= i92 - 1; i93--)
+                                                                                                                                                                                              for (int i94 = i93 + 1; i94 >= i93 - 1; i94--)
+                                                                                                                                                                                                for (int i95 = i94 + 1; i95 >= i94 - 1; i95--)
+                                                                                                                                                                                                  for (int i96 = i95 + 1; i96 >= i95 - 1; i96--)
+                                                                                                                                                                                                    for (int i97 = i96 + 1; i97 >= i96 - 1; i97--)
+                                                                                                                                                                                                      for (int i98 = i97 + 1; i98 >= i97 - 1; i98--)
+                                                                                                                                                                                                        for (int i99 = i98 + 1; i99 >= i98 - 1; i99--)
+                                                                                                                                                                                                          for (int i100 = i99 + 1; i100 >= i99 - 1; i100--) {
+                                                                                                                                                                                                            // Range [0,a.length).
+                                                                                                                                                                                                            a[i100] += 1;
+                                                                                                                                                                                                          }
+}
+
+main() {
+  // To avoid executing the deep loops completely, we pass in a list
+  // with null values, so that each first iteration throws an exception.
+  List<int> a = new List<int>(300);
+  int tryCallingPlusOnNull = 0;
+  try {
+    foo(a);
+  } on NoSuchMethodError catch (e) {
+    ++tryCallingPlusOnNull;
+  }
+  try {
+    bar(a);
+  } on NoSuchMethodError catch (e) {
+    ++tryCallingPlusOnNull;
+  }
+  Expect.equals(2, tryCallingPlusOnNull);
+}
diff --git a/tests/language_2/vm/regression_39071.dart b/tests/language_2/vm/regression_39071_test.dart
similarity index 100%
rename from tests/language_2/vm/regression_39071.dart
rename to tests/language_2/vm/regression_39071_test.dart
diff --git a/tests/language_2/vm/regression_39193_test.dart b/tests/language_2/vm/regression_39193_test.dart
new file mode 100644
index 0000000..bf48765
--- /dev/null
+++ b/tests/language_2/vm/regression_39193_test.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// VMOptions=--optimization_counter_threshold=1
+
+// Found by DartFuzzing: would assert during OSR:
+// https://github.com/dart-lang/sdk/issues/39193
+
+Map<int, Set<int>> var75 = {};
+
+main() {
+  try {} catch (e, st) {} finally {
+    print('before');
+    var75[42] = (false
+        ? const {}
+        : {for (int loc1 = 0; loc1 < 1; loc1++) (-9223372034707292161 >> 165)});
+    print('after');
+  }
+}
diff --git a/tests/lib/analyzer/analyze_library.status b/tests/lib/analyzer/analyze_library.status
new file mode 100644
index 0000000..0dd8e28
--- /dev/null
+++ b/tests/lib/analyzer/analyze_library.status
@@ -0,0 +1,6 @@
+# Copyright (c) 2012, 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.
+
+[ $compiler == dart2analyzer ]
+*: Skip
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
new file mode 100644
index 0000000..a592e6a
--- /dev/null
+++ b/tests/lib/lib.status
@@ -0,0 +1,125 @@
+# Copyright (c) 2017, 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.
+html/cross_frame_test: Skip # Issue 32039, test reloads itself (not by design - investigate)
+wasm/*: Skip # dart:wasm is currently behind a Dart SDK build flag.
+
+[ $arch == simarm64 ]
+convert/utf85_test: Skip # Pass, Slow Issue 20111.
+
+[ $mode == product ]
+developer/timeline_test: Skip # Not supported
+isolate/issue_24243_parent_isolate_test: Skip # Requires checked mode
+
+[ $runtime == ff ]
+convert/streamed_conversion_utf8_decode_test: Slow # Issue 12029
+mirrors/mirrors_reader_test: Slow # Issue 16589
+
+[ $runtime == ie11 ]
+html/request_animation_frame_test: Skip # Times out. Issue 22167
+html/transition_event_test: Skip # Times out. Issue 22167
+
+[ $runtime == safari ]
+html/indexeddb_1_test/functional: Skip # Times out. Issue 21433
+html/indexeddb_3_test: Skip # Times out 1 out of 10.
+html/worker_api_test: Skip # Issue 13221
+
+[ $system == windows ]
+html/xhr_test/xhr: Skip # Times out.  Issue 21527
+
+[ $csp ]
+isolate/deferred_in_isolate2_test: Skip # Issue 16898. Deferred loading does not work from an isolate in CSP-mode
+
+[ $runtime == chrome && $system == linux ]
+mirrors/native_class_test: Slow
+
+[ $runtime == chrome && $system == macos ]
+convert/streamed_conversion_utf8_encode_test: SkipSlow # Times out. Issue 22050
+html/canvasrenderingcontext2d_test/drawImage_video_element: Skip # Times out. Please triage this failure.
+html/canvasrenderingcontext2d_test/drawImage_video_element_dataUrl: Skip # Times out. Please triage this failure.
+html/request_animation_frame_test: Skip # Times out. Issue 22167
+html/transition_event_test: Skip # Times out. Issue 22167
+
+[ $runtime != dart_precompiled && ($runtime != vm || $compiler != dartk && $compiler != none) ]
+isolate/vm_rehash_test: SkipByDesign
+
+[ $arch == simarm || $arch == simarmv6 ]
+convert/utf85_test: Skip # Pass, Slow Issue 12644.
+
+[ $arch != x64 || $compiler == dartkb || $runtime != vm ]
+isolate/int32_length_overflow_test: SkipSlow
+
+[ $compiler != none || $runtime != vm ]
+isolate/package_config_test: SkipByDesign # Uses Isolate.packageConfig
+isolate/package_resolve_test: SkipByDesign # Uses Isolate.resolvePackageUri
+isolate/package_root_test: SkipByDesign # Uses Isolate.packageRoot
+isolate/scenarios/*: SkipByDesign # Use automatic package resolution, spawnFunction and .dart URIs.
+isolate/spawn_uri_fail_test: SkipByDesign # Uses dart:io.
+
+[ $mode == product || $runtime != vm ]
+isolate/checked_test: Skip # Unsupported.
+
+[ $runtime == chrome || $runtime == ff ]
+async/slow_consumer2_test: SkipSlow # Times out. Issue 22050
+async/stream_timeout_test: SkipSlow # Times out. Issue 22050
+
+[ $runtime == dart_precompiled || $runtime == vm ]
+isolate/isolate_stress_test: Skip # Issue 12588: Uses dart:html. This should be able to pass when we have wrapper-less tests.
+
+# It makes no sense to run any test that uses spawnURI under the simulator
+# as that would involve running CFE (the front end) in simulator mode
+# to compile the URI file specified in spawnURI code.
+# These Isolate tests that use spawnURI are hence skipped on purpose.
+[ $runtime == dart_precompiled || $runtime == vm && ($arch == simarm || $arch == simarm64) ]
+isolate/count_test: Skip # Isolate.spawnUri
+isolate/cross_isolate_message_test: Skip # Isolate.spawnUri
+isolate/deferred_in_isolate2_test: Skip # Isolate.spawnUri
+isolate/deferred_in_isolate_test: Skip # Isolate.spawnUri
+isolate/error_at_spawnuri_test: Skip # Isolate.spawnUri
+isolate/error_exit_at_spawnuri_test: Skip # Isolate.spawnUri
+isolate/exit_at_spawnuri_test: Skip # Isolate.spawnUri
+isolate/illegal_msg_function_test: Skip # Isolate.spawnUri
+isolate/illegal_msg_mirror_test: Skip # Isolate.spawnUri
+isolate/isolate_complex_messages_test: Skip # Isolate.spawnUri
+isolate/issue_21398_parent_isolate1_test: Skip # Isolate.spawnUri
+isolate/issue_21398_parent_isolate_test: Skip # Isolate.spawnUri
+isolate/issue_24243_parent_isolate_test: Skip # Isolate.spawnUri
+isolate/issue_6610_test: Skip # Isolate.spawnUri
+isolate/mandel_isolate_test: Skip # Isolate.spawnUri
+isolate/message2_test: Skip # Isolate.spawnUri
+isolate/message_test: Skip # Isolate.spawnUri
+isolate/mint_maker_test: Skip # Isolate.spawnUri
+isolate/nested_spawn2_test: Skip # Isolate.spawnUri
+isolate/nested_spawn_test: Skip # Isolate.spawnUri
+isolate/raw_port_test: Skip # Isolate.spawnUri
+isolate/request_reply_test: Skip # Isolate.spawnUri
+isolate/spawn_function_custom_class_test: Skip # Isolate.spawnUri
+isolate/spawn_function_test: Skip # Isolate.spawnUri
+isolate/spawn_uri_exported_main_test: Skip # Isolate.spawnUri
+isolate/spawn_uri_missing_from_isolate_test: Skip # Isolate.spawnUri
+isolate/spawn_uri_missing_test: Skip # Isolate.spawnUri
+isolate/spawn_uri_multi_test: Skip # Isolate.spawnUri
+isolate/spawn_uri_nested_vm_test: Skip # Isolate.spawnUri
+isolate/spawn_uri_test: Skip # Isolate.spawnUri
+isolate/spawn_uri_vm_test: Skip # Isolate.spawnUri
+isolate/stacktrace_message_test: Skip # Isolate.spawnUri
+isolate/static_function_test: Skip # Isolate.spawnUri
+isolate/unresolved_ports_test: Skip # Isolate.spawnUri
+
+[ $hot_reload || $hot_reload_rollback ]
+convert/chunked_conversion_utf88_test: SkipSlow
+convert/utf85_test: SkipSlow
+isolate/deferred_in_isolate2_test: Crash # Requires deferred libraries
+isolate/deferred_in_isolate_test: Crash # Requires deferred libraries
+isolate/issue_21398_parent_isolate2_test: Crash # Requires deferred libraries
+isolate/spawn_uri_nested_vm_test: Crash # Issue 28192
+mirrors/closurization_equivalence_test: SkipByDesign # Method equality
+mirrors/deferred_constraints_constants_test: Crash # Requires deferred libraries
+mirrors/deferred_mirrors_metadata_test: Crash # Deferred loading
+mirrors/deferred_mirrors_metatarget_test: Crash # Deferred loading
+mirrors/deferred_mirrors_update_test: Crash # Deferred loading
+mirrors/library_enumeration_deferred_loading_test: Crash # Deferred loading
+mirrors/library_import_deferred_loading_test: Crash # Deferred loading
+mirrors/library_imports_deferred_test: Crash # Deferred loading
+mirrors/load_library_test: Crash # Deferred loading
+mirrors/typedef_deferred_library_test: Crash # Deferred loading
diff --git a/tests/lib/lib_analyzer.status b/tests/lib/lib_analyzer.status
new file mode 100644
index 0000000..113c571
--- /dev/null
+++ b/tests/lib/lib_analyzer.status
@@ -0,0 +1,6 @@
+# Copyright (c) 2017, 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.
+
+[ $compiler == dart2analyzer ]
+html/js_function_getter_trust_types_test: Skip # dart2js specific flags.
diff --git a/tests/lib/lib_app_jit.status b/tests/lib/lib_app_jit.status
new file mode 100644
index 0000000..cb39a57
--- /dev/null
+++ b/tests/lib/lib_app_jit.status
@@ -0,0 +1,6 @@
+# Copyright (c) 2017, 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.
+
+[ $compiler == app_jitk ]
+mirrors/*: Skip # Issue 27929: Triage
diff --git a/tests/lib/lib_dart2js.status b/tests/lib/lib_dart2js.status
new file mode 100644
index 0000000..cc91517
--- /dev/null
+++ b/tests/lib/lib_dart2js.status
@@ -0,0 +1,98 @@
+# Copyright (c) 2017, 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.
+
+[ $compiler == dart2js ]
+convert/chunked_conversion_utf88_test: Slow
+convert/utf85_test: Slow
+developer/timeline_test: Skip # Not supported
+html/async_test: SkipByDesign
+html/custom/document_register_basic_test: Slow
+html/custom/document_register_type_extensions_test/construction: Slow
+html/custom/document_register_type_extensions_test/registration: Slow
+html/custom/entered_left_view_test/shadow_dom: Slow
+html/custom/js_custom_test: Skip # mirrors not supported, delete this test.
+html/custom/mirrors_2_test: Skip # mirrors not supported, delete this test.
+html/custom/mirrors_test: Skip # mirrors not supported, delete this test.
+html/custom_elements_test: Slow # Issue 26789
+html/isolates_test: SkipByDesign
+html/mirrors_js_typed_interop_test: Skip # mirrors not supported, delete this test.
+html/worker_api_test: SkipByDesign
+html/wrapping_collections_test: SkipByDesign # Testing an issue that is only relevant to Dartium
+html/xhr_test: Slow
+isolate/*: SkipByDesign # No support for dart:isolate in dart4web (http://dartbug.com/30538)
+mirrors/*: SkipByDesign # Mirrors not supported on web in Dart 2.0.
+profiler/metrics_num_test: Skip # Because of an int / double type test.
+wasm/*: SkipByDesign # dart:wasm not currently supported on web.
+
+[ $compiler != dart2js ]
+async/dart2js_uncaught_error_test: Skip # JS-integration only test
+
+[ $compiler == dart2js && $runtime == chrome ]
+async/slow_consumer2_test: SkipSlow # Times out. Issue 22050
+convert/streamed_conversion_json_utf8_decode_test: SkipSlow # Times out. Issue 22050
+convert/streamed_conversion_json_utf8_encode_test: SkipSlow # Times out. Issue 22050
+convert/streamed_conversion_utf8_decode_test: SkipSlow # Times out. Issue 22050
+
+[ $compiler == dart2js && $runtime == chromeOnAndroid ]
+html/crypto_test/functional: Slow # TODO(dart2js-team): Please triage this failure.
+html/input_element_datetime_test: Slow # TODO(dart2js-team): Please triage this failure.
+
+[ $compiler == dart2js && $runtime == d8 ]
+html/event_callback_test: Skip # Browser test
+
+[ $compiler == dart2js && $runtime == ff ]
+async/slow_consumer2_test: SkipSlow # Times out. Issue 22050
+convert/streamed_conversion_json_utf8_decode_test: SkipSlow # Times out. Issue 22050
+convert/streamed_conversion_json_utf8_encode_test: SkipSlow # Times out. Issue 22050
+convert/streamed_conversion_utf8_decode_test: SkipSlow # Times out. Issue 22050
+convert/utf85_test: Slow
+html/callback_list_test: SkipByDesign # FileSystem not supported in FireFox.
+html/custom/attribute_changed_callback_test: Skip # Times out
+html/custom/created_callback_test: Skip # Times out
+html/custom/document_register_basic_test: Skip # Times out, or unittest times out
+html/dart_object_local_storage_test: Skip # sessionStorage NS_ERROR_DOM_NOT_SUPPORTED_ERR
+html/file_sample_test: Skip # FileSystem not supported on FireFox.
+html/fileapi_supported_test: Skip # FileSystem not supported on FireFox.
+html/fileapi_supported_throws_test: Skip # FileSystem not supported on FireFox.
+html/history_test/history: Skip # Issue 22050
+html/request_animation_frame_test: Skip # Async test hangs.
+
+[ $compiler == dart2js && $runtime == safari ]
+html/callback_list_test: SkipByDesign # FileSystem not supported in Safari.
+html/file_sample_test: Skip # FileSystem not supported on Safari.
+html/fileapi_supported_throws_test: Skip # FileSystem not supported on Safari
+html/interactive_media_test: SkipSlow
+
+[ $compiler == dart2js && $system == linux ]
+html/interactive_geolocation_test: Skip # Requires allowing geo location.
+
+[ $compiler == dart2js && $checked ]
+convert/utf85_test: Slow # Issue 12029.
+html/js_function_getter_trust_types_test: Skip # --trust-type-annotations incompatible with --checked
+
+[ $compiler == dart2js && $csp && ($runtime == chrome || $runtime == chromeOnAndroid || $runtime == ff || $runtime == safari) ]
+html/event_customevent_test: SkipByDesign
+html/js_array_test: SkipByDesign
+html/js_dart_to_string_test: SkipByDesign
+html/js_function_getter_test: SkipByDesign
+html/js_function_getter_trust_types_test: SkipByDesign
+html/js_interop_1_test: SkipByDesign
+html/js_typed_interop_bind_this_test: SkipByDesign
+html/js_typed_interop_callable_object_test: SkipByDesign
+html/js_typed_interop_default_arg_test: SkipByDesign
+html/js_typed_interop_test: SkipByDesign
+html/js_typed_interop_type1_test: SkipByDesign
+html/js_typed_interop_type3_test: SkipByDesign
+html/js_typed_interop_type_test: SkipByDesign
+html/js_typed_interop_window_property_test: SkipByDesign
+html/js_util_test: SkipByDesign
+html/mirrors_js_typed_interop_test: SkipByDesign
+html/postmessage_structured_test: SkipByDesign
+
+[ $compiler == dart2js && ($runtime == chrome || $runtime == ff) ]
+async/slow_consumer2_test: SkipSlow # Times out. Issue 22050
+convert/streamed_conversion_json_utf8_decode_test: SkipSlow # Times out. Issue 22050
+convert/streamed_conversion_json_utf8_encode_test: SkipSlow # Times out. Issue 22050
+convert/streamed_conversion_utf8_decode_test: SkipSlow # Times out. Issue 22050
+
diff --git a/tests/lib/lib_dartdevc.status b/tests/lib/lib_dartdevc.status
new file mode 100644
index 0000000..b3c2a53
--- /dev/null
+++ b/tests/lib/lib_dartdevc.status
@@ -0,0 +1,49 @@
+# Copyright (c) 2017, 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.
+
+[ $compiler == dartdevc ]
+html/xhr_test: Slow
+
+[ $runtime == chrome && ($compiler == dartdevc || $compiler == dartdevk) ]
+html/js_dispatch_property_test: Skip # Timeout Issue 31030
+
+[ $system == linux && ($compiler == dartdevc || $compiler == dartdevk) ]
+html/interactive_geolocation_test: Skip # Requires allowing geo location.
+
+[ $system == macos && ($compiler == dartdevc || $compiler == dartdevk) ]
+html/interactive_media_test: Skip # Requires interactive camera, microphone permissions.
+
+[ $system == windows && ($compiler == dartdevc || $compiler == dartdevk) ]
+html/xhr_test: Skip # Times out. Issue 21527
+
+[ $compiler == dartdevc || $compiler == dartdevk ]
+convert/chunked_conversion_utf88_test: Slow
+convert/json_utf8_chunk_test: Slow
+convert/streamed_conversion_utf8_decode_test: Slow # Issue 29922
+convert/utf85_test: Slow
+html/callback_list_test: Skip # Test requires user interaction to accept permissions.
+html/custom/attribute_changed_callback_test: Skip # Issue 31577
+html/custom/constructor_calls_created_synchronously_test: Skip # Issue 31577
+html/custom/created_callback_test: Skip # Issue 31577
+html/custom/document_register_basic_test: Skip # Issue 31577
+html/custom/document_register_template_test: Skip # Issue 31577
+html/custom/document_register_type_extensions_test/construction: Skip # Issue 31577
+html/custom/document_register_type_extensions_test/constructors: Skip # Issue 31577
+html/custom/document_register_type_extensions_test/createElement with type extension: Skip # Issue 31577
+html/custom/document_register_type_extensions_test/functional: Skip # Issue 31577
+html/custom/document_register_type_extensions_test/namespaces: Skip # Issue 31577
+html/custom/document_register_type_extensions_test/parsing: Skip # Issue 31577
+html/custom/document_register_type_extensions_test/registration: Skip # Issue 31577
+html/custom/document_register_type_extensions_test/single-parameter createElement: Skip # Issue 31577
+html/custom/element_upgrade_test: Skip # Issue 31577
+html/custom/entered_left_view_test: Skip # Issue 31577
+html/custom/mirrors_2_test: Skip # Issue 31577
+html/custom_element_method_clash_test: Skip # Issue 29922
+html/custom_element_name_clash_test: Skip # Issue 29922
+html/custom_elements_23127_test: Skip # Issue 29922
+html/custom_elements_test: Skip # Issue 29922
+html/notification_permission_test: Skip # Issue 32002
+isolate/*: SkipByDesign # No support for dart:isolate in dart4web (http://dartbug.com/30538)
+mirrors/*: SkipByDesign # Mirrors not supported on web in Dart 2.0.
+profiler/metrics_num_test: Skip # Because of an int / double type test.
diff --git a/tests/lib/lib_kernel.status b/tests/lib/lib_kernel.status
new file mode 100644
index 0000000..1c24f7b
--- /dev/null
+++ b/tests/lib/lib_kernel.status
@@ -0,0 +1,76 @@
+# Copyright (c) 2017, 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.
+# Sections in this file should contain "$compiler == dartk" or
+# "$compiler == dartkp".
+
+isolate/ping_pause_test: Skip # Issue https://dartbug.com/37787
+
+[ $compiler == dartkb ]
+isolate/isolate_complex_messages_test: Crash # runtime/vm/object.cc: 17395: error: expected: type_arguments.IsNull() || type_arguments.IsCanonical()
+
+[ $compiler == fasta ]
+html/*: Skip # TODO(ahe): Make dart:html available.
+js/*: Skip # TODO(ahe): Make dart:js available.
+
+[ $arch == x64 && $mode == debug && $runtime == vm && ($compiler == dartk || $compiler == dartkb) ]
+mirrors/invocation_fuzz_test: Skip # Because it times out, issue 29439.
+
+[ $arch == x64 && ($hot_reload || $hot_reload_rollback) ]
+convert/base64_test/01: Crash # http://dartbug.com/35948
+
+[ $builder_tag == optimization_counter_threshold && ($compiler == dartk || $compiler == dartkb) ]
+mirrors/invocation_fuzz_test/emptyarray: Crash # Flaky on vm-kernel-optcounter-threshold-linux-release-x64, bug #31838
+mirrors/invocation_fuzz_test/false: Crash # Flaky on vm-kernel-optcounter-threshold-linux-release-x64, bug #31838
+mirrors/invocation_fuzz_test/none: Crash # Flaky on vm-kernel-optcounter-threshold-linux-release-x64, bug #31838
+mirrors/invocation_fuzz_test/smi: Crash # Crashes on opt counter builder (#31838)
+mirrors/invocation_fuzz_test/string: Crash # Flaky on vm-kernel-optcounter-threshold-linux-release-x64, bug #31838
+
+[ $compiler == app_jitk && ($mode == product || $mode == release) ]
+isolate/spawn_uri_nested_vm_test: Skip # Timeout, Issue 33385
+
+[ $compiler == dartkp && $mode == debug && $runtime == dart_precompiled ]
+isolate/static_function_test: Skip # Flaky (https://github.com/dart-lang/sdk/issues/30063).
+
+# ===== dartkp + dart_precompiled status lines =====
+[ $compiler == dartkp && $runtime == dart_precompiled ]
+html/*: SkipByDesign # dart:html not supported on VM.
+isolate/deferred_in_isolate2_test: Skip # Times out. Deferred loading kernel issue 28335.
+isolate/deferred_in_isolate_test: Skip # Times out. Deferred loading kernel issue 28335.
+isolate/issue_21398_parent_isolate2_test/01: Skip # Times out. Deferred loading kernel issue 28335.
+mirrors/*: SkipByDesign # Mirrors are not supported in AOT mode.
+
+[ $mode == debug && $runtime == vm && ($compiler == dartk || $compiler == dartkb) ]
+mirrors/other_declarations_location_test: Crash # Issue 33325 (assertion error, TypeParameter not having position).
+
+[ $mode == debug && $hot_reload_rollback && ($compiler == dartk || $compiler == dartkb) ]
+isolate/message3_test/constList_identical: Skip # Timeout
+
+# ===== dartk + vm status lines =====
+[ $runtime == vm && ($compiler == dartk || $compiler == dartkb) ]
+html/*: SkipByDesign # dart:html not supported on VM.
+isolate/deferred_in_isolate2_test: Skip # Times out. Deferred loading kernel issue 28335.
+isolate/deferred_in_isolate_test: Skip # Times out. Deferred loading kernel issue 28335.
+isolate/issue_21398_parent_isolate2_test/01: Skip # Times out. Deferred loading kernel issue 28335.
+isolate/static_function_test: Skip # Times out. Issue 31855. CompileTimeError. Issue 31402
+mirrors/invocation_fuzz_test: Crash
+mirrors/metadata_allowed_values_test/16: Skip # Flaky, crashes.
+mirrors/mirrors_used*: SkipByDesign # Invalid tests. MirrorsUsed does not have a specification, and dart:mirrors is not required to hide declarations that are not covered by any MirrorsUsed annotation.
+mirrors/native_class_test: SkipByDesign # Imports dart:html
+
+[ $hot_reload_rollback && ($compiler == dartk || $compiler == dartkb) ]
+isolate/illegal_msg_function_test: Skip # Timeout
+isolate/pause_test: Skip # Timeout
+
+[ ($compiler == dartk || $compiler == dartkb) && ($hot_reload || $hot_reload_rollback) ]
+isolate/message4_test: Crash # Timeout and sporadic crash (issue 33824)
+mirrors/dynamic_load_test: Skip # Reload has an effect similar to deleting the dynamically loaded library
+mirrors/immutable_collections_test: Pass, Slow
+mirrors/mirrors_reader_test: Pass, Slow
+
+[ $compiler == app_jitk || $compiler == dartk || $compiler == dartkb || $compiler == dartkp ]
+html/*: SkipByDesign
+js/*: SkipByDesign
+
+[ $hot_reload || $hot_reload_rollback ]
+isolate/issue_6610_test: Skip # Sources are looked up on every reload request.
diff --git a/tests/lib/lib_precompiled.status b/tests/lib/lib_precompiled.status
new file mode 100644
index 0000000..5f9922d
--- /dev/null
+++ b/tests/lib/lib_precompiled.status
@@ -0,0 +1,9 @@
+# Copyright (c) 2017, 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.
+
+[ $compiler == none ]
+async/future_or_strong_test: RuntimeError
+isolate/compile_time_error_test/01: Skip # Issue 12587
+isolate/ping_test: Skip # Resolve test issues
+mirrors/symbol_validation_test: RuntimeError # Issue 13596
diff --git a/tests/lib/lib_vm.status b/tests/lib/lib_vm.status
new file mode 100644
index 0000000..aba92ff
--- /dev/null
+++ b/tests/lib/lib_vm.status
@@ -0,0 +1,86 @@
+# Copyright (c) 2017, 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.
+
+[ $runtime != vm ]
+isolate/native_wrapper_message_test: Skip # A VM specific test.
+
+[ $arch == arm64 && $runtime == vm ]
+mirrors/immutable_collections_test: Pass, Slow # http://dartbug.com/33057
+
+[ $arch == ia32 && $mode == debug && $runtime == vm && $system == windows ]
+convert/streamed_conversion_json_utf8_decode_test: Skip # Verification OOM.
+
+[ $arch != ia32 && $arch != simarm && $arch != simarmv6 && $arch != x64 && $mode == debug && $runtime == vm ]
+convert/streamed_conversion_json_utf8_decode_test: Skip # Verification not yet implemented.
+
+[ $arch == simarm64 && $runtime == vm ]
+convert/utf85_test: Skip # Pass, Slow Issue 20111.
+
+[ $compiler != app_jitk && $compiler != dartk && $compiler != dartkb && $runtime == vm ]
+async/future_or_only_in_async_test/00: MissingCompileTimeError
+convert/streamed_conversion_json_utf8_decode_test: Pass, Slow # Infrequent timeouts.
+html/*: SkipByDesign # dart:html not supported on VM.
+js/datetime_roundtrip_test: CompileTimeError
+js/null_test: CompileTimeError
+js/prototype_access_test: CompileTimeError
+mirrors/deferred_type_test: CompileTimeError
+mirrors/generic_bounded_by_type_parameter_test/02: MissingCompileTimeError
+mirrors/generic_bounded_test/01: MissingCompileTimeError
+mirrors/generic_bounded_test/02: MissingCompileTimeError
+mirrors/generic_interface_test/01: MissingCompileTimeError
+mirrors/generics_test/01: MissingCompileTimeError
+mirrors/initializing_formals_test/01: Fail # initializing formals are implicitly final as of Dart 1.21
+mirrors/metadata_nested_constructor_call_test/none: CompileTimeError
+mirrors/mirrors_used*: SkipByDesign # Invalid tests. MirrorsUsed does not have a specification, and dart:mirrors is not required to hide declarations that are not covered by any MirrorsUsed annotation.
+mirrors/native_class_test: SkipByDesign # Imports dart:html
+mirrors/redirecting_factory_different_type_test/01: MissingCompileTimeError
+mirrors/redirecting_factory_test/01: RuntimeError
+mirrors/redirecting_factory_test/none: RuntimeError
+
+[ $compiler != app_jitk && $compiler != dartk && $compiler != dartkb && $runtime == vm && !$checked ]
+mirrors/inference_and_no_such_method_test: RuntimeError
+
+[ $runtime == vm && $system == fuchsia ]
+async/first_regression_test: RuntimeError
+async/future_timeout_test: RuntimeError
+async/schedule_microtask2_test: RuntimeError
+async/schedule_microtask3_test: RuntimeError
+async/schedule_microtask5_test: RuntimeError
+async/stream_controller_async_test: RuntimeError
+async/stream_first_where_test: RuntimeError
+async/stream_iterator_test: RuntimeError
+async/stream_join_test: RuntimeError
+async/stream_last_where_test: RuntimeError
+async/stream_periodic2_test: RuntimeError
+async/stream_periodic3_test: RuntimeError
+async/stream_periodic4_test: RuntimeError
+async/stream_periodic5_test: RuntimeError
+async/stream_periodic6_test: RuntimeError
+async/stream_periodic_test: RuntimeError
+async/stream_single_test: RuntimeError
+async/stream_single_to_multi_subscriber_test: RuntimeError
+async/stream_state_nonzero_timer_test: RuntimeError
+async/stream_state_test: RuntimeError
+async/stream_subscription_as_future_test: RuntimeError
+async/stream_subscription_cancel_test: RuntimeError
+async/stream_transform_test: RuntimeError
+async/stream_transformation_broadcast_test: RuntimeError
+async/timer_cancel1_test: RuntimeError
+async/timer_cancel2_test: RuntimeError
+async/timer_cancel_test: RuntimeError
+async/timer_isActive_test: RuntimeError
+async/timer_repeat_test: RuntimeError
+async/timer_test: RuntimeError
+convert/json_lib_test: RuntimeError
+math/point_test: RuntimeError
+math/rectangle_test: RuntimeError
+mirrors/invocation_fuzz_test: Crash
+mirrors/library_uri_io_test: RuntimeError
+mirrors/library_uri_package_test: RuntimeError
+
+[ $runtime == vm && ($arch == simarm || $arch == simarmv6) ]
+convert/utf85_test: Skip # Pass, Slow Issue 12644.
+
+[ $arch == simarmv6 || $arch == simarm && $runtime == vm ]
+convert/chunked_conversion_utf88_test: Skip # Pass, Slow Issue 12644.
diff --git a/tests/lib/math/call_cmath_box_failure_path_test.dart b/tests/lib/math/call_cmath_box_failure_path_test.dart
new file mode 100644
index 0000000..bf63443
--- /dev/null
+++ b/tests/lib/math/call_cmath_box_failure_path_test.dart
@@ -0,0 +1,26 @@
+// 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.
+
+// VMOptions=--optimization-counter-threshold=-1 --new_gen_semi_max_size=2
+
+// TODO(rnystrom): This looks like a VM-specific test. Move out of
+// tests/language and into somewhere more appropriate.
+
+import 'dart:math';
+
+main() {
+  // 2MB / 16 bytes = 125000 allocations
+
+  for (var i = 0; i < 500000; i++) {
+    sin(i);
+  }
+
+  for (var i = 0; i < 500000; i++) {
+    cos(i);
+  }
+
+  for (var i = 0; i < 500000; i++) {
+    i.toDouble().truncateToDouble();
+  }
+}
diff --git a/tests/lib/math/coin_test.dart b/tests/lib/math/coin_test.dart
new file mode 100644
index 0000000..58b4d16
--- /dev/null
+++ b/tests/lib/math/coin_test.dart
@@ -0,0 +1,59 @@
+// Copyright (c) 2012, 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 that a coin toss with Random.nextBool() is fair.
+
+import "package:expect/expect.dart";
+import 'dart:math';
+
+main() {
+  var seed = new Random().nextInt(1 << 16);
+  print("coin_test seed: $seed");
+  var rnd = new Random(seed);
+  var heads = 0;
+  var tails = 0;
+  for (var i = 0; i < 10000; i++) {
+    if (rnd.nextBool()) {
+      heads++;
+    } else {
+      tails++;
+    }
+  }
+  print("Heads: $heads\n"
+      "Tails: $tails\n"
+      "Ratio: ${heads / tails}\n");
+  Expect.approxEquals(1.0, heads / tails, 0.1);
+
+  heads = 0;
+  tails = 0;
+  for (var i = 0; i < 10000; i++) {
+    rnd = new Random(i);
+    if (rnd.nextBool()) {
+      heads++;
+    } else {
+      tails++;
+    }
+  }
+  print("Heads: $heads\n"
+      "Tails: $tails\n"
+      "Ratio: ${heads / tails}\n");
+  Expect.approxEquals(1.0, heads / tails, 0.1);
+
+  // A sequence of newly allocated Random number generators should have fair
+  // initial tosses.
+  heads = 0;
+  tails = 0;
+  for (var i = 0; i < 10000; i++) {
+    rnd = new Random();
+    if (rnd.nextBool()) {
+      heads++;
+    } else {
+      tails++;
+    }
+  }
+  print("Heads: $heads\n"
+      "Tails: $tails\n"
+      "Ratio: ${heads / tails}\n");
+  Expect.approxEquals(1.0, heads / tails, 0.1);
+}
diff --git a/tests/lib/math/double_pow_test.dart b/tests/lib/math/double_pow_test.dart
new file mode 100644
index 0000000..c3e7969
--- /dev/null
+++ b/tests/lib/math/double_pow_test.dart
@@ -0,0 +1,174 @@
+// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--optimization-counter-threshold=5 --no-background-compilation
+
+library math_test;
+
+import "package:expect/expect.dart";
+import 'dart:math';
+
+void checkVeryClose(double a, num b) {
+  // We find a ulp (unit in the last place) by shifting the original number
+  // to the right. This only works if we are not too close to infinity or if
+  // we work with denormals.
+  // We special case for 0.0, but not for infinity.
+  if (a == 0.0) {
+    final minimalDouble = 4.9406564584124654e-324;
+    Expect.equals(true, b.abs() <= minimalDouble);
+    return;
+  }
+  if (b == 0.0) {
+    // No need to look if they are close. Otherwise the check for 'a' above
+    // would have triggered.
+    Expect.equals(a, b);
+  }
+  final double shiftRightBy52 = 2.220446049250313080847263336181640625e-16;
+  final double shiftedA = (a * shiftRightBy52).abs();
+  // Compared to 'a', 'shiftedA' is now ~1-2 ulp.
+
+  final double limitLow = a - shiftedA;
+  final double limitHigh = a + shiftedA;
+  Expect.equals(false, a == limitLow);
+  Expect.equals(false, a == limitHigh);
+  Expect.equals(true, limitLow <= b);
+  Expect.equals(true, b <= limitHigh);
+}
+
+const NaN = double.nan;
+const Infinity = double.infinity;
+
+var samples = [
+  NaN,
+  -Infinity,
+  -3.0, // Odd integer
+  -2.0, // Even integer
+  -1.5, // Non-integer, magnitude > 1
+  -1.0, // Unit
+  -0.5, // Non-integer, magnitude < 1.
+  -0.0,
+  0.5, // Non-integer, magnitude < 1.
+  1.0, // Unit
+  1.5, // Non-integer, magnitude > 1
+  2.0, // Even integer
+  3.0, // Odd integer
+  Infinity
+];
+
+test() {
+  // Tests of pow(x, y):
+  for (var d in samples) {
+    // if `y` is zero (0.0 or -0.0), the result is always 1.0.
+    Expect.identical(1.0, pow(d, 0.0), "$d");
+    Expect.identical(1.0, pow(d, -0.0), "$d");
+  }
+  for (var d in samples) {
+    // if `x` is 1.0, the result is always 1.0.
+    Expect.identical(1.0, pow(1.0, d), "$d");
+  }
+  for (var d in samples) {
+    // otherwise, if either `x` or `y` is NaN then the result is NaN.
+    if (d != 0.0) Expect.isTrue(pow(NaN, d).isNaN, "$d");
+    if (d != 1.0) Expect.isTrue(pow(d, NaN).isNaN, "$d");
+  }
+
+  for (var d in samples) {
+    // if `x` is a finite and strictly negative and `y` is a finite non-integer,
+    // the result is NaN.
+    if (d < 0 && !d.isInfinite) {
+      Expect.isTrue(pow(d, 0.5).isNaN, "$d");
+      Expect.isTrue(pow(d, -0.5).isNaN, "$d");
+      Expect.isTrue(pow(d, 1.5).isNaN, "$d");
+      Expect.isTrue(pow(d, -1.5).isNaN, "$d");
+    }
+  }
+
+  for (var d in samples) {
+    if (d < 0) {
+      // if `x` is Infinity and `y` is strictly negative, the result is 0.0.
+      Expect.identical(0.0, pow(Infinity, d), "$d");
+    }
+    if (d > 0) {
+      // if `x` is Infinity and `y` is strictly positive, the result is Infinity.
+      Expect.identical(Infinity, pow(Infinity, d), "$d");
+    }
+  }
+
+  for (var d in samples) {
+    if (d < 0) {
+      // if `x` is 0.0 and `y` is strictly negative, the result is Infinity.
+      Expect.identical(Infinity, pow(0.0, d), "$d");
+    }
+    if (d > 0) {
+      // if `x` is 0.0 and `y` is strictly positive, the result is 0.0.
+      Expect.identical(0.0, pow(0.0, d), "$d");
+    }
+  }
+
+  for (var d in samples) {
+    if (!d.isInfinite && !d.isNaN) {
+      var dint = d.toInt();
+      if (d == dint && dint.isOdd) {
+        // if `x` is -Infinity or -0.0 and `y` is an odd integer, then the
+        // result is`-pow(-x ,y)`.
+        Expect.identical(-pow(Infinity, d), pow(-Infinity, d));
+        Expect.identical(-pow(0.0, d), pow(-0.0, d));
+        continue;
+      }
+    }
+    // if `x` is -Infinity or -0.0 and `y` is not an odd integer, then the
+    // result is the same as `pow(-x , y)`.
+    if (d.isNaN) {
+      Expect.isTrue(pow(Infinity, d).isNaN);
+      Expect.isTrue(pow(-Infinity, d).isNaN);
+      Expect.isTrue(pow(0.0, d).isNaN);
+      Expect.isTrue(pow(-0.0, d).isNaN);
+      continue;
+    }
+    Expect.identical(pow(Infinity, d), pow(-Infinity, d));
+    Expect.identical(pow(0.0, d), pow(-0.0, d));
+  }
+
+  for (var d in samples) {
+    if (d.abs() < 1) {
+      // if `y` is Infinity and the absolute value of `x` is less than 1, the
+      // result is 0.0.
+      Expect.identical(0.0, pow(d, Infinity));
+    } else if (d.abs() > 1) {
+      // if `y` is Infinity and the absolute value of `x` is greater than 1,
+      // the result is Infinity.
+      Expect.identical(Infinity, pow(d, Infinity));
+    } else if (d == -1) {
+      // if `y` is Infinity and `x` is -1, the result is 1.0.
+      Expect.identical(1.0, pow(d, Infinity));
+    }
+    // if `y` is -Infinity, the result is `1/pow(x, Infinity)`.
+    if (d.isNaN) {
+      Expect.isTrue((1 / pow(d, Infinity)).isNaN);
+      Expect.isTrue(pow(d, -Infinity).isNaN);
+    } else {
+      Expect.identical(1 / pow(d, Infinity), pow(d, -Infinity));
+    }
+  }
+
+  // Some non-exceptional values.
+  checkVeryClose(16.0, pow(4.0, 2.0));
+  checkVeryClose(sqrt2, pow(2.0, 0.5));
+  checkVeryClose(sqrt1_2, pow(0.5, 0.5));
+  // Denormal result.
+  Expect.identical(5e-324, pow(2.0, -1074.0));
+  // Overflow.
+  Expect.identical(Infinity, pow(10.0, 309.0));
+  // Underflow.
+  Expect.identical(0.0, pow(10.0, -325.0));
+
+  // Conversion to double.
+
+  // The second argument is an odd integer as int, but not when converted
+  // to double.
+  Expect.identical(Infinity, pow(-0.0, -9223372036854775807));
+}
+
+main() {
+  for (int i = 0; i < 10; i++) test();
+}
diff --git a/tests/lib/math/implement_rectangle_test.dart b/tests/lib/math/implement_rectangle_test.dart
new file mode 100644
index 0000000..3a31ed8
--- /dev/null
+++ b/tests/lib/math/implement_rectangle_test.dart
@@ -0,0 +1,80 @@
+// 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.
+
+import 'dart:math' hide Rectangle;
+import 'dart:math' as math show Point, Rectangle, MutableRectangle;
+import 'package:expect/expect.dart' show Expect;
+
+void main() {
+  verifyRectable(new Rectangle(1, 2, 3, 4));
+}
+
+void verifyRectable(math.Rectangle rect) {
+  Expect.equals(1.0, rect.left.toDouble());
+  Expect.equals(2.0, rect.top.toDouble());
+  Expect.equals(4.0, rect.right.toDouble());
+  Expect.equals(6.0, rect.bottom.toDouble());
+}
+
+class Rectangle<T extends num> implements math.MutableRectangle<T> {
+  T left;
+  T top;
+  T width;
+  T height;
+
+  Rectangle(this.left, this.top, this.width, this.height);
+
+  T get right => left + width;
+
+  T get bottom => top + height;
+
+  Point<T> get topLeft => new Point<T>(left, top);
+
+  Point<T> get topRight => new Point<T>(right, top);
+
+  Point<T> get bottomLeft => new Point<T>(left, bottom);
+
+  Point<T> get bottomRight => new Point<T>(right, bottom);
+
+  //---------------------------------------------------------------------------
+
+  bool contains(num px, num py) {
+    return left <= px && top <= py && right > px && bottom > py;
+  }
+
+  bool containsPoint(math.Point<num> p) {
+    return contains(p.x, p.y);
+  }
+
+  bool intersects(math.Rectangle<num> r) {
+    return left < r.right && right > r.left && top < r.bottom && bottom > r.top;
+  }
+
+  /// Returns a new rectangle which completely contains `this` and [other].
+
+  Rectangle<T> boundingBox(math.Rectangle<T> other) {
+    T rLeft = min(left, other.left);
+    T rTop = min(top, other.top);
+    T rRight = max(right, other.right);
+    T rBottom = max(bottom, other.bottom);
+    return new Rectangle<T>(rLeft, rTop, rRight - rLeft, rBottom - rTop);
+  }
+
+  /// Tests whether `this` entirely contains [another].
+
+  bool containsRectangle(math.Rectangle<num> r) {
+    return left <= r.left &&
+        top <= r.top &&
+        right >= r.right &&
+        bottom >= r.bottom;
+  }
+
+  Rectangle<T> intersection(math.Rectangle<T> rect) {
+    T rLeft = max(left, rect.left);
+    T rTop = max(top, rect.top);
+    T rRight = min(right, rect.right);
+    T rBottom = min(bottom, rect.bottom);
+    return new Rectangle<T>(rLeft, rTop, rRight - rLeft, rBottom - rTop);
+  }
+}
diff --git a/tests/lib/math/low_test.dart b/tests/lib/math/low_test.dart
new file mode 100644
index 0000000..f7e9060
--- /dev/null
+++ b/tests/lib/math/low_test.dart
@@ -0,0 +1,31 @@
+// Copyright (c) 2012, 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 that the default PRNG does uniformly distribute values when not using
+// a power of 2.
+
+import "package:expect/expect.dart";
+import 'dart:math';
+
+void main() {
+  var n = (2 * 0x100000000) ~/ 3;
+  var n2 = n ~/ 2;
+
+  var iterations = 200000;
+
+  var seed = new Random().nextInt(1 << 16);
+  print("low_test seed: $seed");
+  var prng = new Random(seed);
+
+  var low = 0;
+  for (var i = 0; i < iterations; i++) {
+    if (prng.nextInt(n) < n2) {
+      low++;
+    }
+  }
+
+  var diff = (low - (iterations ~/ 2)).abs();
+  print("$low, $diff");
+  Expect.isTrue(diff < (iterations ~/ 20));
+}
diff --git a/tests/lib/math/math2_test.dart b/tests/lib/math/math2_test.dart
new file mode 100644
index 0000000..6802723
--- /dev/null
+++ b/tests/lib/math/math2_test.dart
@@ -0,0 +1,265 @@
+// Copyright (c) 2012, 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.
+
+// We temporarily test both the new math library and the old Math
+// class. This can easily be simplified once we get rid of the Math
+// class entirely.
+library math_test;
+
+import "package:expect/expect.dart";
+import 'dart:math' as math;
+
+class MathLibraryTest {
+  static void testConstants() {
+    // Source for mathematical constants is Wolfram Alpha.
+    Expect.equals(
+        2.7182818284590452353602874713526624977572470936999595749669, math.e);
+    Expect.equals(2.3025850929940456840179914546843642076011014886287729760333,
+        math.ln10);
+    Expect.equals(
+        0.6931471805599453094172321214581765680755001343602552541206, math.ln2);
+    Expect.equals(1.4426950408889634073599246810018921374266459541529859341354,
+        math.log2e);
+    Expect.equals(0.4342944819032518276511289189166050822943970058036665661144,
+        math.log10e);
+    Expect.equals(
+        3.1415926535897932384626433832795028841971693993751058209749, math.pi);
+    Expect.equals(0.7071067811865475244008443621048490392848359376884740365883,
+        math.sqrt1_2);
+    Expect.equals(1.4142135623730950488016887242096980785696718753769480731766,
+        math.sqrt2);
+  }
+
+  static checkClose(double a, double b, EPSILON) {
+    Expect.equals(true, a - EPSILON <= b);
+    Expect.equals(true, b <= a + EPSILON);
+  }
+
+  static void testSin() {
+    // Given the imprecision of pi we can't expect better results than this.
+    final double EPSILON = 1e-15;
+    checkClose(0.0, math.sin(0.0), EPSILON);
+    checkClose(0.0, math.sin(math.pi), EPSILON);
+    checkClose(0.0, math.sin(2.0 * math.pi), EPSILON);
+    checkClose(1.0, math.sin(math.pi / 2.0), EPSILON);
+    checkClose(-1.0, math.sin(math.pi * (3.0 / 2.0)), EPSILON);
+  }
+
+  static void testCos() {
+    // Given the imprecision of pi we can't expect better results than this.
+    final double EPSILON = 1e-15;
+    checkClose(1.0, math.cos(0.0), EPSILON);
+    checkClose(-1.0, math.cos(math.pi), EPSILON);
+    checkClose(1.0, math.cos(2.0 * math.pi), EPSILON);
+    checkClose(0.0, math.cos(math.pi / 2.0), EPSILON);
+    checkClose(0.0, math.cos(math.pi * (3.0 / 2.0)), EPSILON);
+  }
+
+  static void testTan() {
+    // Given the imprecision of pi we can't expect better results than this.
+    final double EPSILON = 1e-15;
+    checkClose(0.0, math.tan(0.0), EPSILON);
+    checkClose(0.0, math.tan(math.pi), EPSILON);
+    checkClose(0.0, math.tan(2.0 * math.pi), EPSILON);
+    checkClose(1.0, math.tan(math.pi / 4.0), EPSILON);
+  }
+
+  static void testAsin() {
+    // Given the imprecision of pi we can't expect better results than this.
+    final double EPSILON = 1e-15;
+    checkClose(0.0, math.asin(0.0), EPSILON);
+    checkClose(math.pi / 2.0, math.asin(1.0), EPSILON);
+    checkClose(-math.pi / 2.0, math.asin(-1.0), EPSILON);
+  }
+
+  static void testAcos() {
+    // Given the imprecision of pi we can't expect better results than this.
+    final double EPSILON = 1e-15;
+    checkClose(0.0, math.acos(1.0), EPSILON);
+    checkClose(math.pi, math.acos(-1.0), EPSILON);
+    checkClose(math.pi / 2.0, math.acos(0.0), EPSILON);
+  }
+
+  static void testAtan() {
+    // Given the imprecision of pi we can't expect better results than this.
+    final double EPSILON = 1e-15;
+    checkClose(0.0, math.atan(0.0), EPSILON);
+    checkClose(math.pi / 4.0, math.atan(1.0), EPSILON);
+    checkClose(-math.pi / 4.0, math.atan(-1.0), EPSILON);
+  }
+
+  static void testAtan2() {
+    // Given the imprecision of pi we can't expect better results than this.
+    final double EPSILON = 1e-15;
+    checkClose(0.0, math.atan2(0.0, 5.0), EPSILON);
+    checkClose(math.pi / 4.0, math.atan2(2.0, 2.0), EPSILON);
+    checkClose(3 * math.pi / 4.0, math.atan2(0.5, -0.5), EPSILON);
+    checkClose(-3 * math.pi / 4.0, math.atan2(-2.5, -2.5), EPSILON);
+  }
+
+  static checkVeryClose(double a, num b) {
+    // We find a ulp (unit in the last place) by shifting the original number
+    // to the right. This only works if we are not too close to infinity or if
+    // we work with denormals.
+    // We special case or 0.0, but not for infinity.
+    if (a == 0.0) {
+      final minimalDouble = 4.9406564584124654e-324;
+      Expect.equals(true, b.abs() <= minimalDouble);
+      return;
+    }
+    if (b == 0.0) {
+      // No need to look if they are close. Otherwise the check for 'a' above
+      // whould have triggered.
+      Expect.equals(a, b);
+    }
+    final double shiftRightBy52 = 2.220446049250313080847263336181640625e-16;
+    final double shiftedA = (a * shiftRightBy52).abs();
+    // Compared to 'a', 'shiftedA' is now ~1-2 ulp.
+
+    final double limitLow = a - shiftedA;
+    final double limitHigh = a + shiftedA;
+    Expect.equals(false, a == limitLow);
+    Expect.equals(false, a == limitHigh);
+    Expect.equals(true, limitLow <= b);
+    Expect.equals(true, b <= limitHigh);
+  }
+
+  static void testSqrt() {
+    checkVeryClose(2.0, math.sqrt(4.0));
+    checkVeryClose(math.sqrt2, math.sqrt(2.0));
+    checkVeryClose(math.sqrt1_2, math.sqrt(0.5));
+    checkVeryClose(1e50, math.sqrt(1e100));
+    checkVeryClose(1.1111111061110855443054405046358901279277111935183977e56,
+        math.sqrt(12345678901234e99));
+  }
+
+  static void testExp() {
+    checkVeryClose(math.e, math.exp(1.0));
+    final EPSILON = 1e-15;
+    checkClose(10.0, math.exp(math.ln10), EPSILON);
+    checkClose(2.0, math.exp(math.ln2), EPSILON);
+  }
+
+  static void testLog() {
+    // Even though E is imprecise, it is good enough to get really close to 1.
+    // We still provide an epsilon.
+    checkClose(1.0, math.log(math.e), 1e-16);
+    checkVeryClose(math.ln10, math.log(10.0));
+    checkVeryClose(math.ln2, math.log(2.0));
+  }
+
+  static void testPow() {
+    checkVeryClose(16.0, math.pow(4.0, 2.0));
+    checkVeryClose(math.sqrt2, math.pow(2.0, 0.5));
+    checkVeryClose(math.sqrt1_2, math.pow(0.5, 0.5));
+  }
+
+  static bool parseIntThrowsFormatException(str) {
+    try {
+      int.parse(str);
+      return false;
+    } on FormatException catch (e) {
+      return true;
+    }
+  }
+
+  static void testParseInt() {
+    Expect.equals(499, int.parse("499"));
+    Expect.equals(499, int.parse("+499"));
+    Expect.equals(-499, int.parse("-499"));
+    Expect.equals(499, int.parse("   499   "));
+    Expect.equals(499, int.parse("   +499   "));
+    Expect.equals(-499, int.parse("   -499   "));
+    Expect.equals(0, int.parse("0"));
+    Expect.equals(0, int.parse("+0"));
+    Expect.equals(0, int.parse("-0"));
+    Expect.equals(0, int.parse("   0   "));
+    Expect.equals(0, int.parse("   +0   "));
+    Expect.equals(0, int.parse("   -0   "));
+    Expect.equals(0x1234567890, int.parse("0x1234567890"));
+    Expect.equals(-0x1234567890, int.parse("-0x1234567890"));
+    Expect.equals(0x1234567890, int.parse("   0x1234567890   "));
+    Expect.equals(-0x1234567890, int.parse("   -0x1234567890   "));
+    Expect.equals(256, int.parse("0x100"));
+    Expect.equals(-256, int.parse("-0x100"));
+    Expect.equals(256, int.parse("   0x100   "));
+    Expect.equals(-256, int.parse("   -0x100   "));
+    Expect.equals(0xabcdef, int.parse("0xabcdef"));
+    Expect.equals(0xABCDEF, int.parse("0xABCDEF"));
+    Expect.equals(0xabcdef, int.parse("0xabCDEf"));
+    Expect.equals(-0xabcdef, int.parse("-0xabcdef"));
+    Expect.equals(-0xABCDEF, int.parse("-0xABCDEF"));
+    Expect.equals(0xabcdef, int.parse("   0xabcdef   "));
+    Expect.equals(0xABCDEF, int.parse("   0xABCDEF   "));
+    Expect.equals(-0xabcdef, int.parse("   -0xabcdef   "));
+    Expect.equals(-0xABCDEF, int.parse("   -0xABCDEF   "));
+    Expect.equals(0xabcdef, int.parse("0x00000abcdef"));
+    Expect.equals(0xABCDEF, int.parse("0x00000ABCDEF"));
+    Expect.equals(-0xabcdef, int.parse("-0x00000abcdef"));
+    Expect.equals(-0xABCDEF, int.parse("-0x00000ABCDEF"));
+    Expect.equals(0xabcdef, int.parse("   0x00000abcdef   "));
+    Expect.equals(0xABCDEF, int.parse("   0x00000ABCDEF   "));
+    Expect.equals(-0xabcdef, int.parse("   -0x00000abcdef   "));
+    Expect.equals(-0xABCDEF, int.parse("   -0x00000ABCDEF   "));
+    Expect.equals(10, int.parse("010"));
+    Expect.equals(-10, int.parse("-010"));
+    Expect.equals(10, int.parse("   010   "));
+    Expect.equals(-10, int.parse("   -010   "));
+    Expect.equals(9, int.parse("09"));
+    Expect.equals(9, int.parse(" 09 "));
+    Expect.equals(-9, int.parse("-09"));
+    Expect.equals(0x1234567890, int.parse("+0x1234567890"));
+    Expect.equals(0x1234567890, int.parse("   +0x1234567890   "));
+    Expect.equals(0x100, int.parse("+0x100"));
+    Expect.equals(0x100, int.parse("   +0x100   "));
+
+    Expect.equals(true, parseIntThrowsFormatException("1b"));
+    Expect.equals(true, parseIntThrowsFormatException(" 1b "));
+    Expect.equals(true, parseIntThrowsFormatException(" 1 b "));
+    Expect.equals(true, parseIntThrowsFormatException("1e2"));
+    Expect.equals(true, parseIntThrowsFormatException(" 1e2 "));
+    Expect.equals(true, parseIntThrowsFormatException("00x12"));
+    Expect.equals(true, parseIntThrowsFormatException(" 00x12 "));
+    Expect.equals(true, parseIntThrowsFormatException("-1b"));
+    Expect.equals(true, parseIntThrowsFormatException(" -1b "));
+    Expect.equals(true, parseIntThrowsFormatException(" -1 b "));
+    Expect.equals(true, parseIntThrowsFormatException("-1e2"));
+    Expect.equals(true, parseIntThrowsFormatException(" -1e2 "));
+    Expect.equals(true, parseIntThrowsFormatException("-00x12"));
+    Expect.equals(true, parseIntThrowsFormatException(" -00x12 "));
+    Expect.equals(true, parseIntThrowsFormatException("  -00x12 "));
+    Expect.equals(true, parseIntThrowsFormatException("0x0x12"));
+    Expect.equals(true, parseIntThrowsFormatException("0.1"));
+    Expect.equals(true, parseIntThrowsFormatException("0x3.1"));
+    Expect.equals(true, parseIntThrowsFormatException("5."));
+    Expect.equals(true, parseIntThrowsFormatException("+-5"));
+    Expect.equals(true, parseIntThrowsFormatException("-+5"));
+    Expect.equals(true, parseIntThrowsFormatException("--5"));
+    Expect.equals(true, parseIntThrowsFormatException("++5"));
+    Expect.equals(true, parseIntThrowsFormatException("+ 5"));
+    Expect.equals(true, parseIntThrowsFormatException("- 5"));
+    Expect.equals(true, parseIntThrowsFormatException(""));
+    Expect.equals(true, parseIntThrowsFormatException("  "));
+  }
+
+  static testMain() {
+    testConstants();
+    testSin();
+    testCos();
+    testTan();
+    testAsin();
+    testAcos();
+    testAtan();
+    testAtan2();
+    testSqrt();
+    testLog();
+    testExp();
+    testPow();
+    testParseInt();
+  }
+}
+
+main() {
+  MathLibraryTest.testMain();
+}
diff --git a/tests/lib/math/math_parse_double_test.dart b/tests/lib/math/math_parse_double_test.dart
new file mode 100644
index 0000000..4aedf50
--- /dev/null
+++ b/tests/lib/math/math_parse_double_test.dart
@@ -0,0 +1,170 @@
+// Copyright (c) 2012, 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.
+
+// We temporarily test both the new math library and the old Math
+// class. This can easily be simplified once we get rid of the Math
+// class entirely.
+library math_parse_double_test;
+
+import "package:expect/expect.dart";
+
+void parseDoubleThrowsFormatException(str) {
+  Expect.throwsFormatException(() => double.parse(str));
+}
+
+void runTest(double expected, String input) {
+  Expect.equals(expected, double.parse(input));
+  Expect.equals(expected, double.parse(" $input "));
+  Expect.equals(expected, double.parse(" $input"));
+  Expect.equals(expected, double.parse("$input "));
+  Expect.equals(expected, double.parse("+$input"));
+  Expect.equals(expected, double.parse(" +$input "));
+  Expect.equals(expected, double.parse("+$input "));
+  Expect.equals(expected, double.parse("\xA0 $input\xA0 "));
+  Expect.equals(expected, double.parse(" \xA0$input"));
+  Expect.equals(expected, double.parse("$input \xA0"));
+  Expect.equals(expected, double.parse("\xA0 +$input\xA0 "));
+  Expect.equals(expected, double.parse("+$input\xA0 "));
+  Expect.equals(expected, double.parse("\u205F $input\u205F "));
+  Expect.equals(expected, double.parse("$input \u2006"));
+  Expect.equals(expected, double.parse("\u1680 +$input\u1680 "));
+  Expect.equals(-expected, double.parse("-$input"));
+  Expect.equals(-expected, double.parse(" -$input "));
+  Expect.equals(-expected, double.parse("-$input "));
+  Expect.equals(-expected, double.parse("\xA0 -$input\xA0 "));
+  Expect.equals(-expected, double.parse("-$input\xA0 "));
+  Expect.equals(-expected, double.parse("\u1680 -$input\u1680 "));
+}
+
+final TESTS = [
+  [499.0, "499"],
+  [499.0, "499."],
+  [499.0, "499.0"],
+  [0.0, "0"],
+  [0.0, ".0"],
+  [0.0, "0."],
+  [0.1, "0.1"],
+  [0.1, ".1"],
+  [10.0, "010"],
+  [1.5, "1.5"],
+  [1.5, "001.5"],
+  [1.5, "1.500"],
+  [1234567.89, "1234567.89"],
+  [1234567e89, "1234567e89"],
+  [1234567.89e2, "1234567.89e2"],
+  [1234567.89e2, "1234567.89e+2"],
+  [1234567.89e-2, "1234567.89e-2"],
+  [5.0, "5"],
+  [123456700.0, "1234567.e2"],
+  [123456700.0, "1234567.e+2"],
+  [double.infinity, "Infinity"],
+  [5e-324, "5e-324"], // min-pos.
+  // Same, without exponential.
+  [
+    0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004940656458412465441765687928682213723650598026143247644255856825006755072702087518652998363616359923797965646954457177309266567103559397963987747960107818781263007131903114045278458171678489821036887186360569987307230500063874091535649843873124733972731696151400317153853980741262385655911710266585566867681870395603106249319452715914924553293054565444011274801297099995419319894090804165633245247571478690147267801593552386115501348035264934720193790268107107491703332226844753335720832431936092382893458368060106011506169809753078342277318329247904982524730776375927247874656084778203734469699533647017972677717585125660551199131504891101451037862738167250955837389733598993664809941164205702637090279242767544565229087538682506419718265533447265625,
+    "0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004940656458412465441765687928682213723650598026143247644255856825006755072702087518652998363616359923797965646954457177309266567103559397963987747960107818781263007131903114045278458171678489821036887186360569987307230500063874091535649843873124733972731696151400317153853980741262385655911710266585566867681870395603106249319452715914924553293054565444011274801297099995419319894090804165633245247571478690147267801593552386115501348035264934720193790268107107491703332226844753335720832431936092382893458368060106011506169809753078342277318329247904982524730776375927247874656084778203734469699533647017972677717585125660551199131504891101451037862738167250955837389733598993664809941164205702637090279242767544565229087538682506419718265533447265625"
+  ],
+  [0.0, "2e-324"], // underflow 0.0
+  [0.9999999999999999, "0.9999999999999999"], // max below 1
+  [1.0, "1.00000000000000005"], // 1.0
+  [1.0000000000000002, "1.0000000000000002"], // min above 1
+  [2147483647.0, "2147483647"], // max int32
+  [2147483647.0000002, "2147483647.0000002"], // min not int32
+  [2147483648.0, "2147483648"], // min int not int32
+  [4295967295.0, "4295967295"], // max uint32
+  [4295967295.000001, "4295967295.000001"], // min not uint-32
+  [4295967296.0, "4295967296"], // min int not-uint32
+  [1.7976931348623157e+308, "1.7976931348623157e+308"], // Max finite
+  [1.7976931348623157e+308, "1.7976931348623158e+308"], // Max finite
+  [double.infinity, "1.7976931348623159e+308"], // Infinity
+  [.049999999999999994, ".049999999999999994"], // not 0.5
+  [.05, ".04999999999999999935"],
+  [4503599627370498.0, "4503599627370497.5"],
+  [1.2345678901234568e+39, "1234567890123456898981341324213421342134"],
+  [9.87291183742987e+24, "9872911837429871193379121"],
+  [1e21, "1e+21"],
+];
+
+void main() {
+  for (var test in TESTS) {
+    runTest(test[0] as double, test[1] as String);
+  }
+
+  Expect.equals(true, double.parse("-0").isNegative);
+  Expect.equals(true, double.parse("   -0   ").isNegative);
+  Expect.equals(true, double.parse("\xA0   -0   \xA0").isNegative);
+  Expect.isTrue(double.parse("NaN").isNaN);
+  Expect.isTrue(double.parse("-NaN").isNaN);
+  Expect.isTrue(double.parse("+NaN").isNaN);
+  Expect.isTrue(double.parse("NaN ").isNaN);
+  Expect.isTrue(double.parse("-NaN ").isNaN);
+  Expect.isTrue(double.parse("+NaN ").isNaN);
+  Expect.isTrue(double.parse(" NaN ").isNaN);
+  Expect.isTrue(double.parse(" -NaN ").isNaN);
+  Expect.isTrue(double.parse(" +NaN ").isNaN);
+  Expect.isTrue(double.parse(" NaN").isNaN);
+  Expect.isTrue(double.parse(" -NaN").isNaN);
+  Expect.isTrue(double.parse(" +NaN").isNaN);
+  Expect.isTrue(double.parse("NaN\xA0").isNaN);
+  Expect.isTrue(double.parse("-NaN\xA0").isNaN);
+  Expect.isTrue(double.parse("+NaN\xA0").isNaN);
+  Expect.isTrue(double.parse(" \xA0NaN\xA0").isNaN);
+  Expect.isTrue(double.parse(" \xA0-NaN\xA0").isNaN);
+  Expect.isTrue(double.parse(" \xA0+NaN\xA0").isNaN);
+  Expect.isTrue(double.parse(" \xA0NaN").isNaN);
+  Expect.isTrue(double.parse(" \xA0-NaN").isNaN);
+  Expect.isTrue(double.parse(" \xA0+NaN").isNaN);
+
+  parseDoubleThrowsFormatException("1b");
+  parseDoubleThrowsFormatException(" 1b ");
+  parseDoubleThrowsFormatException(" 1 b ");
+  parseDoubleThrowsFormatException(" e3 ");
+  parseDoubleThrowsFormatException(" .e3 ");
+  parseDoubleThrowsFormatException("00x12");
+  parseDoubleThrowsFormatException(" 00x12 ");
+  parseDoubleThrowsFormatException("-1b");
+  parseDoubleThrowsFormatException(" -1b ");
+  parseDoubleThrowsFormatException(" -1 b ");
+  parseDoubleThrowsFormatException("-00x12");
+  parseDoubleThrowsFormatException(" -00x12 ");
+  parseDoubleThrowsFormatException("  -00x12 ");
+  parseDoubleThrowsFormatException("0x0x12");
+  parseDoubleThrowsFormatException("+ 1.5");
+  parseDoubleThrowsFormatException("- 1.5");
+  parseDoubleThrowsFormatException("");
+  parseDoubleThrowsFormatException("   ");
+  parseDoubleThrowsFormatException("+0x1234567890");
+  parseDoubleThrowsFormatException("   +0x1234567890   ");
+  parseDoubleThrowsFormatException("   +0x100   ");
+  parseDoubleThrowsFormatException("+0x100");
+  parseDoubleThrowsFormatException("0x1234567890");
+  parseDoubleThrowsFormatException("-0x1234567890");
+  parseDoubleThrowsFormatException("   0x1234567890   ");
+  parseDoubleThrowsFormatException("   -0x1234567890   ");
+  parseDoubleThrowsFormatException("0x100");
+  parseDoubleThrowsFormatException("-0x100");
+  parseDoubleThrowsFormatException("   0x100   ");
+  parseDoubleThrowsFormatException("   -0x100   ");
+  parseDoubleThrowsFormatException("0xabcdef");
+  parseDoubleThrowsFormatException("0xABCDEF");
+  parseDoubleThrowsFormatException("0xabCDEf");
+  parseDoubleThrowsFormatException("-0xabcdef");
+  parseDoubleThrowsFormatException("-0xABCDEF");
+  parseDoubleThrowsFormatException("   0xabcdef   ");
+  parseDoubleThrowsFormatException("   0xABCDEF   ");
+  parseDoubleThrowsFormatException("   -0xabcdef   ");
+  parseDoubleThrowsFormatException("   -0xABCDEF   ");
+  parseDoubleThrowsFormatException("0x00000abcdef");
+  parseDoubleThrowsFormatException("0x00000ABCDEF");
+  parseDoubleThrowsFormatException("-0x00000abcdef");
+  parseDoubleThrowsFormatException("-0x00000ABCDEF");
+  parseDoubleThrowsFormatException("   0x00000abcdef   ");
+  parseDoubleThrowsFormatException("   0x00000ABCDEF   ");
+  parseDoubleThrowsFormatException("   -0x00000abcdef   ");
+  parseDoubleThrowsFormatException("   -0x00000ABCDEF   ");
+  parseDoubleThrowsFormatException("   -INFINITY   ");
+  parseDoubleThrowsFormatException("   NAN   ");
+  parseDoubleThrowsFormatException("   inf   ");
+  parseDoubleThrowsFormatException("   nan   ");
+}
diff --git a/tests/lib/math/math_test.dart b/tests/lib/math/math_test.dart
new file mode 100644
index 0000000..ca32951
--- /dev/null
+++ b/tests/lib/math/math_test.dart
@@ -0,0 +1,254 @@
+// Copyright (c) 2011, 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.
+
+library math_test;
+
+import "package:expect/expect.dart";
+import 'dart:math';
+
+class MathTest {
+  static void testConstants() {
+    // Source for mathematical constants is Wolfram Alpha.
+    Expect.equals(
+        2.7182818284590452353602874713526624977572470936999595749669, e);
+    Expect.equals(
+        2.3025850929940456840179914546843642076011014886287729760333, ln10);
+    Expect.equals(
+        0.6931471805599453094172321214581765680755001343602552541206, ln2);
+    Expect.equals(
+        1.4426950408889634073599246810018921374266459541529859341354, log2e);
+    Expect.equals(
+        0.4342944819032518276511289189166050822943970058036665661144, log10e);
+    Expect.equals(
+        3.1415926535897932384626433832795028841971693993751058209749, pi);
+    Expect.equals(
+        0.7071067811865475244008443621048490392848359376884740365883, sqrt1_2);
+    Expect.equals(
+        1.4142135623730950488016887242096980785696718753769480731766, sqrt2);
+  }
+
+  static checkClose(double a, double b, EPSILON) {
+    Expect.equals(true, a - EPSILON <= b);
+    Expect.equals(true, b <= a + EPSILON);
+  }
+
+  static void testSin() {
+    // Given the imprecision of pi we can't expect better results than this.
+    final double EPSILON = 1e-15;
+    checkClose(0.0, sin(0.0), EPSILON);
+    checkClose(0.0, sin(pi), EPSILON);
+    checkClose(0.0, sin(2.0 * pi), EPSILON);
+    checkClose(1.0, sin(pi / 2.0), EPSILON);
+    checkClose(-1.0, sin(pi * (3.0 / 2.0)), EPSILON);
+  }
+
+  static void testCos() {
+    // Given the imprecision of pi we can't expect better results than this.
+    final double EPSILON = 1e-15;
+    checkClose(1.0, cos(0.0), EPSILON);
+    checkClose(-1.0, cos(pi), EPSILON);
+    checkClose(1.0, cos(2.0 * pi), EPSILON);
+    checkClose(0.0, cos(pi / 2.0), EPSILON);
+    checkClose(0.0, cos(pi * (3.0 / 2.0)), EPSILON);
+  }
+
+  static void testTan() {
+    // Given the imprecision of pi we can't expect better results than this.
+    final double EPSILON = 1e-15;
+    checkClose(0.0, tan(0.0), EPSILON);
+    checkClose(0.0, tan(pi), EPSILON);
+    checkClose(0.0, tan(2.0 * pi), EPSILON);
+    checkClose(1.0, tan(pi / 4.0), EPSILON);
+  }
+
+  static void testAsin() {
+    // Given the imprecision of pi we can't expect better results than this.
+    final double EPSILON = 1e-15;
+    checkClose(0.0, asin(0.0), EPSILON);
+    checkClose(pi / 2.0, asin(1.0), EPSILON);
+    checkClose(-pi / 2.0, asin(-1.0), EPSILON);
+  }
+
+  static void testAcos() {
+    // Given the imprecision of pi we can't expect better results than this.
+    final double EPSILON = 1e-15;
+    checkClose(0.0, acos(1.0), EPSILON);
+    checkClose(pi, acos(-1.0), EPSILON);
+    checkClose(pi / 2.0, acos(0.0), EPSILON);
+  }
+
+  static void testAtan() {
+    // Given the imprecision of pi we can't expect better results than this.
+    final double EPSILON = 1e-15;
+    checkClose(0.0, atan(0.0), EPSILON);
+    checkClose(pi / 4.0, atan(1.0), EPSILON);
+    checkClose(-pi / 4.0, atan(-1.0), EPSILON);
+  }
+
+  static void testAtan2() {
+    // Given the imprecision of pi we can't expect better results than this.
+    final double EPSILON = 1e-15;
+    checkClose(0.0, atan2(0.0, 5.0), EPSILON);
+    checkClose(pi / 4.0, atan2(2.0, 2.0), EPSILON);
+    checkClose(3 * pi / 4.0, atan2(0.5, -0.5), EPSILON);
+    checkClose(-3 * pi / 4.0, atan2(-2.5, -2.5), EPSILON);
+  }
+
+  static checkVeryClose(double a, double b) {
+    // We find a ulp (unit in the last place) by shifting the original number
+    // to the right. This only works if we are not too close to infinity or if
+    // we work with denormals.
+    // We special case or 0.0, but not for infinity.
+    if (a == 0.0) {
+      final minimalDouble = 4.9406564584124654e-324;
+      Expect.equals(true, b.abs() <= minimalDouble);
+      return;
+    }
+    if (b == 0.0) {
+      // No need to look if they are close. Otherwise the check for 'a' above
+      // whould have triggered.
+      Expect.equals(a, b);
+    }
+    final double shiftRightBy52 = 2.220446049250313080847263336181640625e-16;
+    final double shiftedA = (a * shiftRightBy52).abs();
+    // Compared to 'a', 'shiftedA' is now ~1-2 ulp.
+
+    final double limitLow = a - shiftedA;
+    final double limitHigh = a + shiftedA;
+    Expect.equals(false, a == limitLow);
+    Expect.equals(false, a == limitHigh);
+    Expect.equals(true, limitLow <= b);
+    Expect.equals(true, b <= limitHigh);
+  }
+
+  static void testSqrt() {
+    checkVeryClose(2.0, sqrt(4.0));
+    checkVeryClose(sqrt2, sqrt(2.0));
+    checkVeryClose(sqrt1_2, sqrt(0.5));
+    checkVeryClose(1e50, sqrt(1e100));
+    checkVeryClose(1.1111111061110855443054405046358901279277111935183977e56,
+        sqrt(12345678901234e99));
+  }
+
+  static void testExp() {
+    checkVeryClose(e, exp(1.0));
+    final EPSILON = 1e-15;
+    checkClose(10.0, exp(ln10), EPSILON);
+    checkClose(2.0, exp(ln2), EPSILON);
+  }
+
+  static void testLog() {
+    // Even though E is imprecise, it is good enough to get really close to 1.
+    // We still provide an epsilon.
+    checkClose(1.0, log(e), 1e-16);
+    checkVeryClose(ln10, log(10.0));
+    checkVeryClose(ln2, log(2.0));
+  }
+
+  static bool parseIntThrowsFormatException(str) {
+    try {
+      int.parse(str);
+      return false;
+    } on FormatException catch (e) {
+      return true;
+    }
+  }
+
+  static void testParseInt() {
+    Expect.equals(499, int.parse("499"));
+    Expect.equals(499, int.parse("+499"));
+    Expect.equals(-499, int.parse("-499"));
+    Expect.equals(499, int.parse("   499   "));
+    Expect.equals(499, int.parse("   +499   "));
+    Expect.equals(-499, int.parse("   -499   "));
+    Expect.equals(0, int.parse("0"));
+    Expect.equals(0, int.parse("+0"));
+    Expect.equals(0, int.parse("-0"));
+    Expect.equals(0, int.parse("   0   "));
+    Expect.equals(0, int.parse("   +0   "));
+    Expect.equals(0, int.parse("   -0   "));
+    Expect.equals(0x1234567890, int.parse("0x1234567890"));
+    Expect.equals(-0x1234567890, int.parse("-0x1234567890"));
+    Expect.equals(0x1234567890, int.parse("   0x1234567890   "));
+    Expect.equals(-0x1234567890, int.parse("   -0x1234567890   "));
+    Expect.equals(256, int.parse("0x100"));
+    Expect.equals(-256, int.parse("-0x100"));
+    Expect.equals(256, int.parse("   0x100   "));
+    Expect.equals(-256, int.parse("   -0x100   "));
+    Expect.equals(0xabcdef, int.parse("0xabcdef"));
+    Expect.equals(0xABCDEF, int.parse("0xABCDEF"));
+    Expect.equals(0xabcdef, int.parse("0xabCDEf"));
+    Expect.equals(-0xabcdef, int.parse("-0xabcdef"));
+    Expect.equals(-0xABCDEF, int.parse("-0xABCDEF"));
+    Expect.equals(0xabcdef, int.parse("   0xabcdef   "));
+    Expect.equals(0xABCDEF, int.parse("   0xABCDEF   "));
+    Expect.equals(-0xabcdef, int.parse("   -0xabcdef   "));
+    Expect.equals(-0xABCDEF, int.parse("   -0xABCDEF   "));
+    Expect.equals(0xabcdef, int.parse("0x00000abcdef"));
+    Expect.equals(0xABCDEF, int.parse("0x00000ABCDEF"));
+    Expect.equals(-0xabcdef, int.parse("-0x00000abcdef"));
+    Expect.equals(-0xABCDEF, int.parse("-0x00000ABCDEF"));
+    Expect.equals(0xabcdef, int.parse("   0x00000abcdef   "));
+    Expect.equals(0xABCDEF, int.parse("   0x00000ABCDEF   "));
+    Expect.equals(-0xabcdef, int.parse("   -0x00000abcdef   "));
+    Expect.equals(-0xABCDEF, int.parse("   -0x00000ABCDEF   "));
+    Expect.equals(10, int.parse("010"));
+    Expect.equals(-10, int.parse("-010"));
+    Expect.equals(10, int.parse("   010   "));
+    Expect.equals(-10, int.parse("   -010   "));
+    Expect.equals(9, int.parse("09"));
+    Expect.equals(9, int.parse(" 09 "));
+    Expect.equals(-9, int.parse("-09"));
+    Expect.equals(0x1234567890, int.parse("+0x1234567890"));
+    Expect.equals(0x1234567890, int.parse("   +0x1234567890   "));
+    Expect.equals(0x100, int.parse("+0x100"));
+    Expect.equals(0x100, int.parse("   +0x100   "));
+    Expect.equals(true, parseIntThrowsFormatException("1b"));
+    Expect.equals(true, parseIntThrowsFormatException(" 1b "));
+    Expect.equals(true, parseIntThrowsFormatException(" 1 b "));
+    Expect.equals(true, parseIntThrowsFormatException("1e2"));
+    Expect.equals(true, parseIntThrowsFormatException(" 1e2 "));
+    Expect.equals(true, parseIntThrowsFormatException("00x12"));
+    Expect.equals(true, parseIntThrowsFormatException(" 00x12 "));
+    Expect.equals(true, parseIntThrowsFormatException("-1b"));
+    Expect.equals(true, parseIntThrowsFormatException(" -1b "));
+    Expect.equals(true, parseIntThrowsFormatException(" -1 b "));
+    Expect.equals(true, parseIntThrowsFormatException("-1e2"));
+    Expect.equals(true, parseIntThrowsFormatException(" -1e2 "));
+    Expect.equals(true, parseIntThrowsFormatException("-00x12"));
+    Expect.equals(true, parseIntThrowsFormatException(" -00x12 "));
+    Expect.equals(true, parseIntThrowsFormatException("  -00x12 "));
+    Expect.equals(true, parseIntThrowsFormatException("0x0x12"));
+    Expect.equals(true, parseIntThrowsFormatException("0.1"));
+    Expect.equals(true, parseIntThrowsFormatException("0x3.1"));
+    Expect.equals(true, parseIntThrowsFormatException("5."));
+    Expect.equals(true, parseIntThrowsFormatException("+-5"));
+    Expect.equals(true, parseIntThrowsFormatException("-+5"));
+    Expect.equals(true, parseIntThrowsFormatException("--5"));
+    Expect.equals(true, parseIntThrowsFormatException("++5"));
+    Expect.equals(true, parseIntThrowsFormatException("+ 5"));
+    Expect.equals(true, parseIntThrowsFormatException("- 5"));
+    Expect.equals(true, parseIntThrowsFormatException(""));
+    Expect.equals(true, parseIntThrowsFormatException("  "));
+  }
+
+  static testMain() {
+    testConstants();
+    testSin();
+    testCos();
+    testTan();
+    testAsin();
+    testAcos();
+    testAtan();
+    testAtan2();
+    testSqrt();
+    testLog();
+    testExp();
+    testParseInt();
+  }
+}
+
+main() {
+  MathTest.testMain();
+}
diff --git a/tests/lib/math/min_max_test.dart b/tests/lib/math/min_max_test.dart
new file mode 100644
index 0000000..4fb4317
--- /dev/null
+++ b/tests/lib/math/min_max_test.dart
@@ -0,0 +1,563 @@
+// Copyright (c) 2012, 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 test for testing Math.min and Math.max.
+// VMOptions=--optimization-counter-threshold=10 --no-background-compilation
+
+library min_max_test;
+
+import "package:expect/expect.dart";
+import 'dart:math';
+
+var inf = double.infinity;
+var nan = double.nan;
+
+// A class that might work if [min] and [max] worked for non-numbers.
+class Wrap implements Comparable<dynamic> {
+  final num value;
+  Wrap(this.value);
+  int compareTo(dynamic other) => value.compareTo(other.value);
+  bool operator <(Wrap other) => compareTo(other) < 0;
+  bool operator <=(Wrap other) => compareTo(other) <= 0;
+  bool operator >(Wrap other) => compareTo(other) > 0;
+  bool operator >=(Wrap other) => compareTo(other) >= 0;
+  bool operator ==(other) => other is Wrap && compareTo(other) == 0;
+  String toString() => 'Wrap($value)';
+  int get hashCode => value.hashCode;
+}
+
+var wrap1 = new Wrap(1);
+var wrap2 = new Wrap(2);
+
+testMin() {
+  testMin1();
+  testMin2();
+  testMin3();
+}
+
+testMin1() {
+  Expect.equals(0, min(0, 2));
+  Expect.equals(0, min(2, 0));
+
+  Expect.equals(-10, min(-10, -9));
+  Expect.equals(-10, min(-10, 9));
+  Expect.equals(-10, min(-10, 0));
+  Expect.equals(-10, min(-9, -10));
+  Expect.equals(-10, min(9, -10));
+  Expect.equals(-10, min(0, -10));
+
+  Expect.equals(0.5, min(0.5, 2.5));
+  Expect.equals(0.5, min(2.5, 0.5));
+
+  Expect.equals(-10.5, min(-10.5, -9.5));
+  Expect.equals(-10.5, min(-10.5, 9.5));
+  Expect.equals(-10.5, min(-10.5, 0.5));
+  Expect.equals(-10.5, min(-9.5, -10.5));
+  Expect.equals(-10.5, min(9.5, -10.5));
+  Expect.equals(-10.5, min(0.5, -10.5));
+  // Test matrix:
+  // NaN, -infinity, -499.0, -499, -0.0, 0.0, 0, 499.0, 499, +infinity.
+
+  Expect.isTrue(min(nan, nan).isNaN);
+  Expect.isTrue(min(nan, -inf).isNaN);
+  Expect.isTrue(min(nan, -499.0).isNaN);
+  Expect.isTrue(min(nan, -499).isNaN);
+  Expect.isTrue(min(nan, -0.0).isNaN);
+  Expect.isTrue(min(nan, 0.0).isNaN);
+  Expect.isTrue(min(nan, 499.0).isNaN);
+  Expect.isTrue(min(nan, 499).isNaN);
+  Expect.isTrue(min(nan, inf).isNaN);
+
+  Expect.equals(-inf, min(-inf, -inf));
+  Expect.equals(-inf, min(-inf, -499.0));
+  Expect.equals(-inf, min(-inf, -499));
+  Expect.equals(-inf, min(-inf, -0.0));
+  Expect.equals(-inf, min(-inf, 0.0));
+  Expect.equals(-inf, min(-inf, 0));
+  Expect.equals(-inf, min(-inf, 499));
+  Expect.equals(-inf, min(-inf, 499.0));
+  Expect.equals(-inf, min(-inf, inf));
+  Expect.isTrue(min(-inf, nan).isNaN);
+
+  Expect.equals(-inf, min(-499.0, -inf));
+  Expect.equals(-499.0, min(-499.0, -499.0));
+  Expect.equals(-499.0, min(-499.0, -499));
+  Expect.equals(-499.0, min(-499.0, -0.0));
+  Expect.equals(-499.0, min(-499.0, 0.0));
+  Expect.equals(-499.0, min(-499.0, 0));
+  Expect.equals(-499.0, min(-499.0, 499.0));
+  Expect.equals(-499.0, min(-499.0, 499));
+  Expect.equals(-499.0, min(-499.0, inf));
+  Expect.isTrue(min(-499.0, nan).isNaN);
+
+  Expect.isTrue(min(-499.0, -499.0) is double);
+  Expect.isTrue(min(-499.0, -499) is double);
+  Expect.isTrue(min(-499.0, -0.0) is double);
+  Expect.isTrue(min(-499.0, 0.0) is double);
+  Expect.isTrue(min(-499.0, 0) is double);
+  Expect.isTrue(min(-499.0, 499.0) is double);
+  Expect.isTrue(min(-499.0, 499) is double);
+  Expect.isTrue(min(-499.0, inf) is double);
+
+  Expect.equals(-inf, min(-499, -inf));
+  Expect.equals(-499, min(-499, -499.0));
+  Expect.equals(-499, min(-499, -499));
+  Expect.equals(-499, min(-499, -0.0));
+  Expect.equals(-499, min(-499, 0.0));
+  Expect.equals(-499, min(-499, 0));
+  Expect.equals(-499, min(-499, 499.0));
+  Expect.equals(-499, min(-499, 499));
+  Expect.equals(-499, min(-499, inf));
+  Expect.isTrue(min(-499, nan).isNaN);
+
+  Expect.isTrue(min(-499, -499.0) is int);
+  Expect.isTrue(min(-499, -499) is int);
+  Expect.isTrue(min(-499, -0.0) is int);
+  Expect.isTrue(min(-499, 0.0) is int);
+  Expect.isTrue(min(-499, 0) is int);
+  Expect.isTrue(min(-499, 499.0) is int);
+  Expect.isTrue(min(-499, 499) is int);
+  Expect.isTrue(min(-499, inf) is int);
+
+  Expect.equals(-inf, min(-0.0, -inf));
+  Expect.equals(-499.0, min(-0.0, -499.0));
+  Expect.equals(-499, min(-0.0, -499));
+  Expect.equals(-0.0, min(-0.0, -0.0));
+  Expect.equals(-0.0, min(-0.0, 0.0));
+  Expect.equals(-0.0, min(-0.0, 0));
+  Expect.equals(-0.0, min(-0.0, 499.0));
+  Expect.equals(-0.0, min(-0.0, 499));
+  Expect.equals(-0.0, min(-0.0, inf));
+  Expect.isTrue(min(-0.0, nan).isNaN);
+}
+
+testMin2() {
+  Expect.isTrue(min(-0.0, -499.0) is double);
+  Expect.isTrue(min(-0.0, -499) is int);
+  Expect.isTrue(min(-0.0, -0.0) is double);
+  Expect.isTrue(min(-0.0, 0.0) is double);
+  Expect.isTrue(min(-0.0, 0) is double);
+  Expect.isTrue(min(-0.0, 499.0) is double);
+  Expect.isTrue(min(-0.0, 499) is double);
+  Expect.isTrue(min(-0.0, inf) is double);
+
+  Expect.isTrue(min(-0.0, -499.0).isNegative);
+  Expect.isTrue(min(-0.0, -499).isNegative);
+  Expect.isTrue(min(-0.0, -0.0).isNegative);
+  Expect.isTrue(min(-0.0, 0.0).isNegative);
+  Expect.isTrue(min(-0.0, 0).isNegative);
+  Expect.isTrue(min(-0.0, 499.0).isNegative);
+  Expect.isTrue(min(-0.0, 499).isNegative);
+  Expect.isTrue(min(-0.0, inf).isNegative);
+
+  Expect.equals(-inf, min(0.0, -inf));
+  Expect.equals(-499.0, min(0.0, -499.0));
+  Expect.equals(-499, min(0.0, -499));
+  Expect.equals(-0.0, min(0.0, -0.0));
+  Expect.equals(0.0, min(0.0, 0.0));
+  Expect.equals(0.0, min(0.0, 0));
+  Expect.equals(0.0, min(0.0, 499.0));
+  Expect.equals(0.0, min(0.0, 499));
+  Expect.equals(0.0, min(0.0, inf));
+  Expect.isTrue(min(0.0, nan).isNaN);
+
+  Expect.isTrue(min(0.0, -499.0) is double);
+  Expect.isTrue(min(0.0, -499) is int);
+  Expect.isTrue(min(0.0, -0.0) is double);
+  Expect.isTrue(min(0.0, 0.0) is double);
+  Expect.isTrue(min(0.0, 0) is double);
+  Expect.isTrue(min(0.0, 499.0) is double);
+  Expect.isTrue(min(0.0, 499) is double);
+  Expect.isTrue(min(0.0, inf) is double);
+
+  Expect.isTrue(min(0.0, -499.0).isNegative);
+  Expect.isTrue(min(0.0, -499).isNegative);
+  Expect.isTrue(min(0.0, -0.0).isNegative);
+  Expect.isFalse(min(0.0, 0.0).isNegative);
+  Expect.isFalse(min(0.0, 0).isNegative);
+  Expect.isFalse(min(0.0, 499.0).isNegative);
+  Expect.isFalse(min(0.0, 499).isNegative);
+  Expect.isFalse(min(0.0, inf).isNegative);
+
+  Expect.equals(-inf, min(0, -inf));
+  Expect.equals(-499.0, min(0, -499.0));
+  Expect.equals(-499, min(0, -499));
+  Expect.equals(-0.0, min(0, -0.0));
+  Expect.equals(0, min(0, 0.0));
+  Expect.equals(0, min(0, 0));
+  Expect.equals(0, min(0, 499.0));
+  Expect.equals(0, min(0, 499));
+  Expect.equals(0, min(0, inf));
+  Expect.isTrue(min(0, nan).isNaN);
+
+  Expect.isTrue(min(0, -499.0) is double);
+  Expect.isTrue(min(0, -499) is int);
+  Expect.isTrue(min(0, -0.0) is double);
+  Expect.isTrue(min(0, 0.0) is int);
+  Expect.isTrue(min(0, 0) is int);
+  Expect.isTrue(min(0, 499.0) is int);
+  Expect.isTrue(min(0, 499) is int);
+  Expect.isTrue(min(0, inf) is int);
+  Expect.isTrue(min(0, -499.0).isNegative);
+  Expect.isTrue(min(0, -499).isNegative);
+  Expect.isTrue(min(0, -0.0).isNegative);
+  Expect.isFalse(min(0, 0.0).isNegative);
+  Expect.isFalse(min(0, 0).isNegative);
+  Expect.isFalse(min(0, 499.0).isNegative);
+  Expect.isFalse(min(0, 499).isNegative);
+  Expect.isFalse(min(0, inf).isNegative);
+}
+
+testMin3() {
+  Expect.equals(-inf, min(499.0, -inf));
+  Expect.equals(-499.0, min(499.0, -499.0));
+  Expect.equals(-499, min(499.0, -499));
+  Expect.equals(-0.0, min(499.0, -0.0));
+  Expect.equals(0.0, min(499.0, 0.0));
+  Expect.equals(0, min(499.0, 0));
+  Expect.equals(499.0, min(499.0, 499.0));
+  Expect.equals(499.0, min(499.0, 499));
+  Expect.equals(499.0, min(499.0, inf));
+  Expect.isTrue(min(499.0, nan).isNaN);
+
+  Expect.isTrue(min(499.0, -499.0) is double);
+  Expect.isTrue(min(499.0, -499) is int);
+  Expect.isTrue(min(499.0, -0.0) is double);
+  Expect.isTrue(min(499.0, 0.0) is double);
+  Expect.isTrue(min(499.0, 0) is int);
+  Expect.isTrue(min(499.0, 499) is double);
+  Expect.isTrue(min(499.0, 499.0) is double);
+  Expect.isTrue(min(499.0, inf) is double);
+
+  Expect.isTrue(min(499.0, -499.0).isNegative);
+  Expect.isTrue(min(499.0, -499).isNegative);
+  Expect.isTrue(min(499.0, -0.0).isNegative);
+  Expect.isFalse(min(499.0, 0.0).isNegative);
+  Expect.isFalse(min(499.0, 0).isNegative);
+  Expect.isFalse(min(499.0, 499).isNegative);
+  Expect.isFalse(min(499.0, 499.0).isNegative);
+  Expect.isFalse(min(499.0, inf).isNegative);
+
+  Expect.equals(-inf, min(499, -inf));
+  Expect.equals(-499.0, min(499, -499.0));
+  Expect.equals(-499, min(499, -499));
+  Expect.equals(-0.0, min(499, -0.0));
+  Expect.equals(0.0, min(499, 0.0));
+  Expect.equals(0, min(499, 0));
+  Expect.equals(499, min(499, 499.0));
+  Expect.equals(499, min(499, 499));
+  Expect.equals(499, min(499, inf));
+  Expect.isTrue(min(499, nan).isNaN);
+
+  Expect.isTrue(min(499, -499.0) is double);
+  Expect.isTrue(min(499, -499) is int);
+  Expect.isTrue(min(499, -0.0) is double);
+  Expect.isTrue(min(499, 0.0) is double);
+  Expect.isTrue(min(499, 0) is int);
+  Expect.isTrue(min(499, 499.0) is int);
+  Expect.isTrue(min(499, 499) is int);
+  Expect.isTrue(min(499, inf) is int);
+
+  Expect.isTrue(min(499, -499.0).isNegative);
+  Expect.isTrue(min(499, -499).isNegative);
+  Expect.isTrue(min(499, -0.0).isNegative);
+  Expect.isFalse(min(499, 0.0).isNegative);
+  Expect.isFalse(min(499, 0).isNegative);
+  Expect.isFalse(min(499, 499.0).isNegative);
+  Expect.isFalse(min(499, 499).isNegative);
+  Expect.isFalse(min(499, inf).isNegative);
+
+  Expect.equals(-inf, min(inf, -inf));
+  Expect.equals(-499.0, min(inf, -499.0));
+  Expect.equals(-499, min(inf, -499));
+  Expect.equals(-0.0, min(inf, -0.0));
+  Expect.equals(0.0, min(inf, 0.0));
+  Expect.equals(0, min(inf, 0));
+  Expect.equals(499.0, min(inf, 499.0));
+  Expect.equals(499, min(inf, 499));
+  Expect.equals(inf, min(inf, inf));
+  Expect.isTrue(min(inf, nan).isNaN);
+
+  Expect.isTrue(min(inf, -499.0) is double);
+  Expect.isTrue(min(inf, -499) is int);
+  Expect.isTrue(min(inf, -0.0) is double);
+  Expect.isTrue(min(inf, 0.0) is double);
+  Expect.isTrue(min(inf, 0) is int);
+  Expect.isTrue(min(inf, 499) is int);
+  Expect.isTrue(min(inf, 499.0) is double);
+  Expect.isTrue(min(inf, inf) is double);
+
+  Expect.isTrue(min(inf, -499.0).isNegative);
+  Expect.isTrue(min(inf, -499).isNegative);
+  Expect.isTrue(min(inf, -0.0).isNegative);
+  Expect.isFalse(min(inf, 0.0).isNegative);
+  Expect.isFalse(min(inf, 0).isNegative);
+  Expect.isFalse(min(inf, 499).isNegative);
+  Expect.isFalse(min(inf, 499.0).isNegative);
+  Expect.isFalse(min(inf, inf).isNegative);
+}
+
+testMax() {
+  testMax1();
+  testMax2();
+  testMax3();
+}
+
+testMax1() {
+  Expect.equals(2, max(0, 2));
+  Expect.equals(2, max(2, 0));
+
+  Expect.equals(-9, max(-10, -9));
+  Expect.equals(9, max(-10, 9));
+  Expect.equals(0, max(-10, 0));
+  Expect.equals(-9, max(-9, -10));
+  Expect.equals(9, max(9, -10));
+  Expect.equals(0, max(0, -10));
+
+  Expect.equals(2.5, max(0.5, 2.5));
+  Expect.equals(2.5, max(2.5, 0.5));
+
+  Expect.equals(-9.5, max(-10.5, -9.5));
+  Expect.equals(9.5, max(-10.5, 9.5));
+  Expect.equals(0.5, max(-10.5, 0.5));
+  Expect.equals(-9.5, max(-9.5, -10.5));
+  Expect.equals(9.5, max(9.5, -10.5));
+  Expect.equals(0.5, max(0.5, -10.5));
+
+  // Test matrix:
+  // NaN, infinity, 499.0, 499, 0.0, 0, -0.0, -499.0, -499, -infinity.
+
+  Expect.isTrue(max(nan, nan).isNaN);
+  Expect.isTrue(max(nan, -inf).isNaN);
+  Expect.isTrue(max(nan, -499.0).isNaN);
+  Expect.isTrue(max(nan, -499).isNaN);
+  Expect.isTrue(max(nan, -0.0).isNaN);
+  Expect.isTrue(max(nan, 0.0).isNaN);
+  Expect.isTrue(max(nan, 499.0).isNaN);
+  Expect.isTrue(max(nan, 499).isNaN);
+  Expect.isTrue(max(nan, inf).isNaN);
+
+  Expect.equals(inf, max(inf, inf));
+  Expect.equals(inf, max(inf, 499.0));
+  Expect.equals(inf, max(inf, 499));
+  Expect.equals(inf, max(inf, 0.0));
+  Expect.equals(inf, max(inf, 0));
+  Expect.equals(inf, max(inf, -0.0));
+  Expect.equals(inf, max(inf, -499));
+  Expect.equals(inf, max(inf, -499.0));
+  Expect.equals(inf, max(inf, -inf));
+  Expect.isTrue(max(inf, nan).isNaN);
+
+  Expect.equals(inf, max(499.0, inf));
+  Expect.equals(499.0, max(499.0, 499.0));
+  Expect.equals(499.0, max(499.0, 499));
+  Expect.equals(499.0, max(499.0, 0.0));
+  Expect.equals(499.0, max(499.0, 0));
+  Expect.equals(499.0, max(499.0, -0.0));
+  Expect.equals(499.0, max(499.0, -499));
+  Expect.equals(499.0, max(499.0, -499.0));
+  Expect.equals(499.0, max(499.0, -inf));
+  Expect.isTrue(max(499.0, nan).isNaN);
+
+  Expect.isTrue(max(499.0, 499.0) is double);
+  Expect.isTrue(max(499.0, 499) is double);
+  Expect.isTrue(max(499.0, 0.0) is double);
+  Expect.isTrue(max(499.0, 0) is double);
+  Expect.isTrue(max(499.0, -0.0) is double);
+  Expect.isTrue(max(499.0, -499) is double);
+  Expect.isTrue(max(499.0, -499.0) is double);
+  Expect.isTrue(max(499.0, -inf) is double);
+
+  Expect.equals(inf, max(499, inf));
+  Expect.equals(499, max(499, 499.0));
+  Expect.equals(499, max(499, 499));
+  Expect.equals(499, max(499, 0.0));
+  Expect.equals(499, max(499, 0));
+  Expect.equals(499, max(499, -0.0));
+  Expect.equals(499, max(499, -499));
+  Expect.equals(499, max(499, -499.0));
+  Expect.equals(499, max(499, -inf));
+  Expect.isTrue(max(499, nan).isNaN);
+
+  Expect.isTrue(max(499, 499.0) is int);
+  Expect.isTrue(max(499, 499) is int);
+  Expect.isTrue(max(499, 0.0) is int);
+  Expect.isTrue(max(499, 0) is int);
+  Expect.isTrue(max(499, -0.0) is int);
+  Expect.isTrue(max(499, -499) is int);
+  Expect.isTrue(max(499, -499.0) is int);
+  Expect.isTrue(max(499, -inf) is int);
+
+  Expect.equals(inf, max(0.0, inf));
+  Expect.equals(499.0, max(0.0, 499.0));
+  Expect.equals(499, max(0.0, 499));
+  Expect.equals(0.0, max(0.0, 0.0));
+  Expect.equals(0.0, max(0.0, 0));
+  Expect.equals(0.0, max(0.0, -0.0));
+  Expect.equals(0.0, max(0.0, -499));
+  Expect.equals(0.0, max(0.0, -499.0));
+  Expect.equals(0.0, max(0.0, -inf));
+  Expect.isTrue(max(0.0, nan).isNaN);
+
+  Expect.isTrue(max(0.0, 499.0) is double);
+  Expect.isTrue(max(0.0, 499) is int);
+  Expect.isTrue(max(0.0, 0.0) is double);
+  Expect.isTrue(max(0.0, 0) is double);
+  Expect.isTrue(max(0.0, -0.0) is double);
+  Expect.isTrue(max(0.0, -499) is double);
+  Expect.isTrue(max(0.0, -499.0) is double);
+  Expect.isTrue(max(0.0, -inf) is double);
+}
+
+testMax2() {
+  Expect.isFalse(max(0.0, 0.0).isNegative);
+  Expect.isFalse(max(0.0, 0).isNegative);
+  Expect.isFalse(max(0.0, -0.0).isNegative);
+  Expect.isFalse(max(0.0, -499).isNegative);
+  Expect.isFalse(max(0.0, -499.0).isNegative);
+  Expect.isFalse(max(0.0, -inf).isNegative);
+
+  Expect.equals(inf, max(0, inf));
+  Expect.equals(499.0, max(0, 499.0));
+  Expect.equals(499, max(0, 499));
+  Expect.equals(0, max(0, 0.0));
+  Expect.equals(0, max(0, 0));
+  Expect.equals(0, max(0, -0.0));
+  Expect.equals(0, max(0, -499));
+  Expect.equals(0, max(0, -499.0));
+  Expect.equals(0, max(0, -inf));
+  Expect.isTrue(max(0, nan).isNaN);
+
+  Expect.isTrue(max(0, 499.0) is double);
+  Expect.isTrue(max(0, 499) is int);
+  Expect.isTrue(max(0, 0.0) is int);
+  Expect.isTrue(max(0, 0) is int);
+  Expect.isTrue(max(0, -0.0) is int);
+  Expect.isTrue(max(0, -499) is int);
+  Expect.isTrue(max(0, -499.0) is int);
+  Expect.isTrue(max(0, -inf) is int);
+
+  Expect.isFalse(max(0, 0.0).isNegative);
+  Expect.isFalse(max(0, 0).isNegative);
+  Expect.isFalse(max(0, -0.0).isNegative);
+  Expect.isFalse(max(0, -499).isNegative);
+  Expect.isFalse(max(0, -499.0).isNegative);
+  Expect.isFalse(max(0, -inf).isNegative);
+
+  Expect.equals(inf, max(-0.0, inf));
+  Expect.equals(499.0, max(-0.0, 499.0));
+  Expect.equals(499, max(-0.0, 499));
+  Expect.equals(0.0, max(-0.0, 0.0));
+  Expect.equals(0.0, max(-0.0, 0));
+  Expect.equals(-0.0, max(-0.0, -0.0));
+  Expect.equals(-0.0, max(-0.0, -499));
+  Expect.equals(-0.0, max(-0.0, -499.0));
+  Expect.equals(-0.0, max(-0.0, -inf));
+  Expect.isTrue(max(-0.0, nan).isNaN);
+
+  Expect.isTrue(max(-0.0, 499.0) is double);
+  Expect.isTrue(max(-0.0, 499) is int);
+  Expect.isTrue(max(-0.0, 0.0) is double);
+  Expect.isTrue(max(-0.0, 0) is int);
+  Expect.isTrue(max(-0.0, -0.0) is double);
+  Expect.isTrue(max(-0.0, -499) is double);
+  Expect.isTrue(max(-0.0, -499.0) is double);
+  Expect.isTrue(max(-0.0, -inf) is double);
+}
+
+testMax3() {
+  Expect.isFalse(max(-0.0, 0.0).isNegative);
+  Expect.isFalse(max(-0.0, 0).isNegative);
+  Expect.isTrue(max(-0.0, -0.0).isNegative);
+  Expect.isTrue(max(-0.0, -499).isNegative);
+  Expect.isTrue(max(-0.0, -499.0).isNegative);
+  Expect.isTrue(max(-0.0, -inf).isNegative);
+
+  Expect.equals(inf, max(-499, inf));
+  Expect.equals(499.0, max(-499, 499.0));
+  Expect.equals(499, max(-499, 499));
+  Expect.equals(0.0, max(-499, 0.0));
+  Expect.equals(0.0, max(-499, 0));
+  Expect.equals(-0.0, max(-499, -0.0));
+  Expect.equals(-499, max(-499, -499));
+  Expect.equals(-499, max(-499, -499.0));
+  Expect.equals(-499, max(-499, -inf));
+  Expect.isTrue(max(-499, nan).isNaN);
+
+  Expect.isTrue(max(-499, 499.0) is double);
+  Expect.isTrue(max(-499, 499) is int);
+  Expect.isTrue(max(-499, 0.0) is double);
+  Expect.isTrue(max(-499, 0) is int);
+  Expect.isTrue(max(-499, -0.0) is double);
+  Expect.isTrue(max(-499, -499) is int);
+  Expect.isTrue(max(-499, -499.0) is int);
+  Expect.isTrue(max(-499, -inf) is int);
+
+  Expect.isFalse(max(-499, 0.0).isNegative);
+  Expect.isFalse(max(-499, 0).isNegative);
+  Expect.isTrue(max(-499, -0.0).isNegative);
+  Expect.isTrue(max(-499, -499).isNegative);
+  Expect.isTrue(max(-499, -499.0).isNegative);
+  Expect.isTrue(max(-499, -inf).isNegative);
+
+  Expect.equals(inf, max(-499.0, inf));
+  Expect.equals(499.0, max(-499.0, 499.0));
+  Expect.equals(499, max(-499.0, 499));
+  Expect.equals(0.0, max(-499.0, 0.0));
+  Expect.equals(0.0, max(-499.0, 0));
+  Expect.equals(-0.0, max(-499.0, -0.0));
+  Expect.equals(-499.0, max(-499.0, -499));
+  Expect.equals(-499.0, max(-499.0, -499.0));
+  Expect.equals(-499.0, max(-499.0, -inf));
+  Expect.isTrue(max(-499.0, nan).isNaN);
+
+  Expect.isTrue(max(-499.0, 499.0) is double);
+  Expect.isTrue(max(-499.0, 499) is int);
+  Expect.isTrue(max(-499.0, 0.0) is double);
+  Expect.isTrue(max(-499.0, 0) is int);
+  Expect.isTrue(max(-499.0, -0.0) is double);
+  Expect.isTrue(max(-499.0, -499) is double);
+  Expect.isTrue(max(-499.0, -499.0) is double);
+  Expect.isTrue(max(-499.0, -inf) is double);
+
+  Expect.isFalse(max(-499.0, 0.0).isNegative);
+  Expect.isFalse(max(-499.0, 0).isNegative);
+  Expect.isTrue(max(-499.0, -0.0).isNegative);
+  Expect.isTrue(max(-499.0, -499).isNegative);
+  Expect.isTrue(max(-499.0, -499.0).isNegative);
+  Expect.isTrue(max(-499.0, -inf).isNegative);
+
+  Expect.equals(inf, max(-inf, inf));
+  Expect.equals(499.0, max(-inf, 499.0));
+  Expect.equals(499, max(-inf, 499));
+  Expect.equals(0.0, max(-inf, 0.0));
+  Expect.equals(0.0, max(-inf, 0));
+  Expect.equals(-0.0, max(-inf, -0.0));
+  Expect.equals(-499, max(-inf, -499));
+  Expect.equals(-499.0, max(-inf, -499.0));
+  Expect.equals(-inf, max(-inf, -inf));
+  Expect.isTrue(max(-inf, nan).isNaN);
+
+  Expect.isTrue(max(-inf, 499.0) is double);
+  Expect.isTrue(max(-inf, 499) is int);
+  Expect.isTrue(max(-inf, 0.0) is double);
+  Expect.isTrue(max(-inf, 0) is int);
+  Expect.isTrue(max(-inf, -0.0) is double);
+  Expect.isTrue(max(-inf, -499) is int);
+  Expect.isTrue(max(-inf, -499.0) is double);
+  Expect.isTrue(max(-inf, -inf) is double);
+
+  Expect.isFalse(max(-inf, 0.0).isNegative);
+  Expect.isFalse(max(-inf, 0).isNegative);
+  Expect.isTrue(max(-inf, -0.0).isNegative);
+  Expect.isTrue(max(-inf, -499).isNegative);
+  Expect.isTrue(max(-inf, -499.0).isNegative);
+  Expect.isTrue(max(-inf, -inf).isNegative);
+}
+
+main() {
+  testMin();
+  testMin();
+  testMax();
+  testMax();
+}
diff --git a/tests/lib/math/pi_test.dart b/tests/lib/math/pi_test.dart
new file mode 100644
index 0000000..b867132
--- /dev/null
+++ b/tests/lib/math/pi_test.dart
@@ -0,0 +1,49 @@
+// Copyright (c) 2012, 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 that the default PRNG does converge towards Pi when doing a Monte Carlo
+// simulation.
+
+import "package:expect/expect.dart";
+import 'dart:math';
+
+var known_bad_seeds = const [50051, 55597, 59208];
+
+void main([args]) {
+  // Select a seed either from the argument passed in or
+  // otherwise a random seed.
+  var seed = -1;
+  if ((args != null) && (args.length > 0)) {
+    seed = int.parse(args[0]);
+  } else {
+    var seed_prng = new Random();
+    while (seed == -1) {
+      seed = seed_prng.nextInt(1 << 16);
+      if (known_bad_seeds.contains(seed)) {
+        // Reset seed and try again.
+        seed = -1;
+      }
+    }
+  }
+
+  // Setup the PRNG for the Monte Carlo simulation.
+  print("pi_test seed: $seed");
+  var prng = new Random(seed);
+
+  var outside = 0;
+  var inside = 0;
+  for (var i = 0; i < 600000; i++) {
+    var x = prng.nextDouble();
+    var y = prng.nextDouble();
+    if ((x * x) + (y * y) < 1.0) {
+      inside++;
+    } else {
+      outside++;
+    }
+  }
+  // Mmmmh, Pie!
+  var pie = 4.0 * (inside / (inside + outside));
+  print("$pie");
+  Expect.isTrue(((pi - 0.009) < pie) && (pie < (pi + 0.009)));
+}
diff --git a/tests/lib/math/point_test.dart b/tests/lib/math/point_test.dart
new file mode 100644
index 0000000..7e6979a
--- /dev/null
+++ b/tests/lib/math/point_test.dart
@@ -0,0 +1,99 @@
+// Copyright (c) 2013, 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:math';
+import 'package:expect/expect.dart';
+
+main() {
+  // constructor
+  {
+    var point = new Point(0, 0);
+    Expect.equals(0, point.x);
+    Expect.equals(0, point.y);
+    Expect.equals('Point(0, 0)', '$point');
+  }
+
+  // constructor X
+  {
+    var point = new Point<int>(10, 0);
+    Expect.equals(10, point.x);
+    Expect.equals(0, point.y);
+    Expect.equals('Point(10, 0)', '$point');
+  }
+
+  // constructor X Y
+  {
+    var point = new Point<int>(10, 20);
+    Expect.equals(10, point.x);
+    Expect.equals(20, point.y);
+    Expect.equals('Point(10, 20)', '$point');
+  }
+
+  // constructor X Y double
+  {
+    var point = new Point<double>(10.5, 20.897);
+    Expect.equals(10.5, point.x);
+    Expect.equals(20.897, point.y);
+    Expect.equals('Point(10.5, 20.897)', '$point');
+  }
+
+  // constructor X Y NaN
+  {
+    var point = new Point(double.nan, 1000);
+    Expect.isTrue(point.x.isNaN);
+    Expect.equals(1000, point.y);
+    Expect.equals('Point(NaN, 1000)', '$point');
+  }
+
+  // squaredDistanceTo
+  {
+    var a = new Point(7, 11);
+    var b = new Point(3, -1);
+    Expect.equals(160, a.squaredDistanceTo(b));
+    Expect.equals(160, b.squaredDistanceTo(a));
+  }
+
+  // distanceTo
+  {
+    var a = new Point(-2, -3);
+    var b = new Point(2, 0);
+    Expect.equals(5, a.distanceTo(b));
+    Expect.equals(5, b.distanceTo(a));
+  }
+
+  // subtract
+  {
+    var a = new Point(5, 10);
+    var b = new Point(2, 50);
+    Expect.equals(new Point(3, -40), a - b);
+  }
+
+  // add
+  {
+    var a = new Point(5, 10);
+    var b = new Point(2, 50);
+    Expect.equals(new Point(7, 60), a + b);
+  }
+
+  // hashCode
+  {
+    var a = new Point(0, 1);
+    var b = new Point(0, 1);
+    Expect.equals(b.hashCode, a.hashCode);
+
+    var c = new Point(1, 0);
+    Expect.isFalse(a.hashCode == c.hashCode);
+  }
+
+  // magnitude
+  {
+    var a = new Point(5, 10);
+    var b = new Point(0, 0);
+    Expect.equals(a.distanceTo(b), a.magnitude);
+    Expect.equals(0, b.magnitude);
+
+    var c = new Point(-5, -10);
+    Expect.equals(a.distanceTo(b), c.magnitude);
+  }
+}
diff --git a/tests/lib/math/random_big_test.dart b/tests/lib/math/random_big_test.dart
new file mode 100644
index 0000000..41a5651
--- /dev/null
+++ b/tests/lib/math/random_big_test.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2014, 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 that Random can deal with a seed outside 64-bit range.
+
+import "package:expect/expect.dart";
+import 'dart:math';
+
+main() {
+  var results = [];
+  for (var i = 60; i < 64; i++) {
+    var rng = new Random(1 << i);
+    var val = rng.nextInt(100000);
+    print("$i: $val");
+    Expect.isFalse(results.contains(val));
+    results.add(val);
+  }
+}
diff --git a/tests/lib/math/random_secure_test.dart b/tests/lib/math/random_secure_test.dart
new file mode 100644
index 0000000..a28a215
--- /dev/null
+++ b/tests/lib/math/random_secure_test.dart
@@ -0,0 +1,58 @@
+// Copyright (c) 2015, 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 that the secure random generator does not systematically generates
+// duplicates. Note that this test is flaky by definition, since duplicates
+// can occur. They should be extremely rare, though.
+
+import "package:expect/expect.dart";
+import 'dart:math';
+
+main() {
+  var results;
+  var rng0;
+  var rng1;
+  var checkInt = (max) {
+    var intVal0 = rng0.nextInt(max);
+    var intVal1 = rng1.nextInt(max);
+    if (max > (1 << 28)) {
+      Expect.isFalse(results.contains(intVal0));
+      results.add(intVal0);
+      Expect.isFalse(results.contains(intVal1));
+      results.add(intVal1);
+    }
+  };
+  results = [];
+  rng0 = new Random.secure();
+  for (var i = 0; i <= 32; i++) {
+    rng1 = new Random.secure();
+    checkInt(pow(2, 32));
+    checkInt(pow(2, 32 - i));
+    checkInt(1000000000);
+  }
+  var checkDouble = () {
+    var doubleVal0 = rng0.nextDouble();
+    var doubleVal1 = rng1.nextDouble();
+    Expect.isFalse(results.contains(doubleVal0));
+    results.add(doubleVal0);
+    Expect.isFalse(results.contains(doubleVal1));
+    results.add(doubleVal1);
+  };
+  results = [];
+  rng0 = new Random.secure();
+  for (var i = 0; i < 32; i++) {
+    rng1 = new Random.secure();
+    checkDouble();
+  }
+  var cnt0 = 0;
+  var cnt1 = 0;
+  rng0 = new Random.secure();
+  for (var i = 0; i < 32; i++) {
+    rng1 = new Random.secure();
+    cnt0 += rng0.nextBool() ? 1 : 0;
+    cnt1 += rng1.nextBool() ? 1 : 0;
+  }
+  Expect.isTrue((cnt0 > 0) && (cnt0 < 32));
+  Expect.isTrue((cnt1 > 0) && (cnt1 < 32));
+}
diff --git a/tests/lib/math/random_secure_unsupported_test.dart b/tests/lib/math/random_secure_unsupported_test.dart
new file mode 100644
index 0000000..7e8744c
--- /dev/null
+++ b/tests/lib/math/random_secure_unsupported_test.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2019, 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 that `Random.secure()` throws `UnsupportedError` each time it fails.
+
+import "package:expect/expect.dart";
+import 'dart:math';
+
+main() {
+  var result1 = getRandom();
+  var result2 = getRandom();
+
+  Expect.isNotNull(result1);
+  Expect.isNotNull(result2); // This fired for http://dartbug.com/36206
+
+  Expect.equals(result1 is Random, result2 is Random);
+  Expect.equals(result1 is UnsupportedError, result2 is UnsupportedError);
+}
+
+dynamic getRandom() {
+  try {
+    return Random.secure();
+  } catch (e) {
+    return e;
+  }
+}
diff --git a/tests/lib/math/random_test.dart b/tests/lib/math/random_test.dart
new file mode 100644
index 0000000..9e66365
--- /dev/null
+++ b/tests/lib/math/random_test.dart
@@ -0,0 +1,239 @@
+// Copyright (c) 2013, 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 that rnd.nextInt with a seed generates the same sequence each time.
+
+// Library tag to allow Dartium to run the test.
+library random_test;
+
+import "package:expect/expect.dart";
+import 'dart:math';
+
+main() {
+  checkSequence();
+  checkSeed();
+}
+
+void checkSequence() {
+  // Check the sequence of numbers generated by the random generator for a seed
+  // doesn't change unintendedly, and it agrees between implementations.
+  var rnd = new Random(20130307);
+  // Make sure we do not break the random number generation.
+  // If the random algorithm changes, make sure both the VM and dart2js
+  // generate the same new sequence.
+  var i = 1;
+  Expect.equals(0, rnd.nextInt(i *= 2));
+  Expect.equals(3, rnd.nextInt(i *= 2));
+  Expect.equals(7, rnd.nextInt(i *= 2));
+  Expect.equals(5, rnd.nextInt(i *= 2));
+  Expect.equals(29, rnd.nextInt(i *= 2));
+  Expect.equals(17, rnd.nextInt(i *= 2));
+  Expect.equals(104, rnd.nextInt(i *= 2));
+  Expect.equals(199, rnd.nextInt(i *= 2));
+  Expect.equals(408, rnd.nextInt(i *= 2));
+  Expect.equals(362, rnd.nextInt(i *= 2));
+  Expect.equals(995, rnd.nextInt(i *= 2));
+  Expect.equals(2561, rnd.nextInt(i *= 2));
+  Expect.equals(2548, rnd.nextInt(i *= 2));
+  Expect.equals(9553, rnd.nextInt(i *= 2));
+  Expect.equals(2628, rnd.nextInt(i *= 2));
+  Expect.equals(42376, rnd.nextInt(i *= 2));
+  Expect.equals(101848, rnd.nextInt(i *= 2));
+  Expect.equals(85153, rnd.nextInt(i *= 2));
+  Expect.equals(495595, rnd.nextInt(i *= 2));
+  Expect.equals(647122, rnd.nextInt(i *= 2));
+  Expect.equals(793546, rnd.nextInt(i *= 2));
+  Expect.equals(1073343, rnd.nextInt(i *= 2));
+  Expect.equals(4479969, rnd.nextInt(i *= 2));
+  Expect.equals(9680425, rnd.nextInt(i *= 2));
+  Expect.equals(28460171, rnd.nextInt(i *= 2));
+  Expect.equals(49481738, rnd.nextInt(i *= 2));
+  Expect.equals(9878974, rnd.nextInt(i *= 2));
+  Expect.equals(132552472, rnd.nextInt(i *= 2));
+  Expect.equals(210267283, rnd.nextInt(i *= 2));
+  Expect.equals(125422442, rnd.nextInt(i *= 2));
+  Expect.equals(226275094, rnd.nextInt(i *= 2));
+  Expect.equals(1639629168, rnd.nextInt(i *= 2));
+  Expect.equals(0x100000000, i);
+  // If max is too large expect an ArgumentError.
+  Expect.throwsArgumentError(() => rnd.nextInt(i + 1));
+
+  rnd = new Random(6790);
+  Expect.approxEquals(0.1202733131, rnd.nextDouble());
+  Expect.approxEquals(0.5554054805, rnd.nextDouble());
+  Expect.approxEquals(0.0385160727, rnd.nextDouble());
+  Expect.approxEquals(0.2836345217, rnd.nextDouble());
+}
+
+void checkSeed() {
+  // Check that various seeds generate the expected first values.
+  // 53 significant bits, so the number is representable in JS.
+  var rawSeed = 0x19a32c640e1d71;
+  var expectations = [
+    26007,
+    43006,
+    46458,
+    18610,
+    16413,
+    50455,
+    2164,
+    47399,
+    8859,
+    9732,
+    20367,
+    33935,
+    54549,
+    54913,
+    4819,
+    24198,
+    49353,
+    22277,
+    51852,
+    35959,
+    45347,
+    12100,
+    10136,
+    22372,
+    15293,
+    20066,
+    1351,
+    49030,
+    64845,
+    12793,
+    50916,
+    55784,
+    43170,
+    27653,
+    34696,
+    1492,
+    50255,
+    9597,
+    45929,
+    2874,
+    27629,
+    53084,
+    36064,
+    42140,
+    32016,
+    41751,
+    13967,
+    20516,
+    578,
+    16773,
+    53064,
+    14814,
+    22737,
+    48846,
+    45147,
+    10205,
+    56584,
+    63711,
+    44128,
+    21099,
+    47966,
+    35471,
+    39576,
+    1141,
+    45716,
+    54940,
+    57406,
+    15437,
+    31721,
+    35044,
+    28136,
+    39797,
+    50801,
+    22184,
+    58686
+  ];
+  var negative_seed_expectations = [
+    12170,
+    42844,
+    39228,
+    64032,
+    29046,
+    57572,
+    8453,
+    52224,
+    27060,
+    28454,
+    20510,
+    28804,
+    59221,
+    53422,
+    11047,
+    50864,
+    33997,
+    19611,
+    1250,
+    65088,
+    19690,
+    11396,
+    20,
+    48867,
+    44862,
+    47129,
+    58724,
+    13325,
+    50005,
+    33320,
+    16523,
+    4740,
+    63721,
+    63272,
+    30545,
+    51403,
+    35845,
+    3943,
+    31850,
+    23148,
+    26307,
+    1724,
+    29281,
+    39988,
+    43653,
+    48012,
+    43810,
+    16755,
+    13105,
+    25325,
+    32648,
+    19958,
+    38838,
+    8322,
+    3421,
+    28624,
+    17269,
+    45385,
+    50680,
+    1696,
+    26088,
+    2787,
+    48566,
+    34357,
+    27731,
+    51764,
+    8455,
+    16498,
+    59721,
+    59568,
+    46333,
+    7935,
+    51459,
+    36766,
+    50711
+  ];
+  for (var i = 0, m = 1; i < 75; i++) {
+    if (rawSeed * m < 0) {
+      // Overflow.
+      break;
+    }
+    Expect.equals(expectations[i], new Random(rawSeed * m).nextInt(65536));
+    Expect.equals(
+        negative_seed_expectations[i], new Random(rawSeed * -m).nextInt(65536));
+    m *= 2;
+  }
+  // And test zero seed too.
+  Expect.equals(21391, new Random(0).nextInt(65536));
+}
diff --git a/tests/lib/math/rectangle_test.dart b/tests/lib/math/rectangle_test.dart
new file mode 100644
index 0000000..f6b5ed2
--- /dev/null
+++ b/tests/lib/math/rectangle_test.dart
@@ -0,0 +1,288 @@
+// Copyright (c) 2013, 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:math';
+import 'package:expect/expect.dart';
+
+main() {
+  testConstruction();
+  testIntersection();
+  testIntersects();
+  testBoundingBox();
+  testContainsRectangle();
+  testContainsPoint();
+  testHashCode();
+  testEdgeCases();
+  testEquality();
+  testNegativeLengths();
+  testNaNLeft();
+  testNaNTop();
+  testNaNWidth();
+  testNaNHeight();
+}
+
+Rectangle? createRectangle(List<num>? a) {
+  return a != null ? new Rectangle(a[0], a[1], a[2] - a[0], a[3] - a[1]) : null;
+}
+
+testConstruction() {
+  var r0 = new Rectangle(10, 20, 30, 40);
+  Expect.equals('Rectangle (10, 20) 30 x 40', r0.toString());
+  Expect.equals(40, r0.right);
+  Expect.equals(60, r0.bottom);
+
+  var r1 = new Rectangle.fromPoints(r0.topLeft, r0.bottomRight);
+  Expect.equals(r0, r1);
+
+  var r2 = new Rectangle.fromPoints(r0.bottomRight, r0.topLeft);
+  Expect.equals(r0, r2);
+}
+
+testIntersection() {
+  var tests = <List<List<num>?>>[
+    [
+      [10, 10, 20, 20],
+      [15, 15, 25, 25],
+      [15, 15, 20, 20]
+    ],
+    [
+      [10, 10, 20, 20],
+      [20, 0, 30, 10],
+      [20, 10, 20, 10]
+    ],
+    [
+      [0, 0, 1, 1],
+      [10, 11, 12, 13],
+      null
+    ],
+    [
+      [11, 12, 98, 99],
+      [22, 23, 34, 35],
+      [22, 23, 34, 35]
+    ]
+  ];
+
+  for (var test in tests) {
+    var r0 = createRectangle(test[0]);
+    var r1 = createRectangle(test[1]);
+    var expected = createRectangle(test[2]);
+
+    Expect.equals(expected, r0.intersection(r1));
+    Expect.equals(expected, r1.intersection(r0));
+  }
+}
+
+testIntersects() {
+  var r0 = new Rectangle(10, 10, 20, 20);
+  var r1 = new Rectangle(15, 15, 25, 25);
+  var r2 = new Rectangle(0, 0, 1, 1);
+
+  Expect.isTrue(r0.intersects(r1));
+  Expect.isTrue(r1.intersects(r0));
+
+  Expect.isFalse(r0.intersects(r2));
+  Expect.isFalse(r2.intersects(r0));
+}
+
+testBoundingBox() {
+  var tests = [
+    [
+      [10, 10, 20, 20],
+      [15, 15, 25, 25],
+      [10, 10, 25, 25]
+    ],
+    [
+      [10, 10, 20, 20],
+      [20, 0, 30, 10],
+      [10, 0, 30, 20]
+    ],
+    [
+      [0, 0, 1, 1],
+      [10, 11, 12, 13],
+      [0, 0, 12, 13]
+    ],
+    [
+      [11, 12, 98, 99],
+      [22, 23, 34, 35],
+      [11, 12, 98, 99]
+    ]
+  ];
+
+  for (var test in tests) {
+    var r0 = createRectangle(test[0]);
+    var r1 = createRectangle(test[1]);
+    var expected = createRectangle(test[2]);
+
+    Expect.equals(expected, r0.boundingBox(r1));
+    Expect.equals(expected, r1.boundingBox(r0));
+  }
+}
+
+testContainsRectangle() {
+  var r = new Rectangle(-10, 0, 20, 10);
+  Expect.isTrue(r.containsRectangle(r));
+
+  Expect.isFalse(r.containsRectangle(
+      new Rectangle(double.nan, double.nan, double.nan, double.nan)));
+
+  var r2 = new Rectangle(0, 2, 5, 5);
+  Expect.isTrue(r.containsRectangle(r2));
+  Expect.isFalse(r2.containsRectangle(r));
+
+  r2 = new Rectangle(-11, 2, 5, 5);
+  Expect.isFalse(r.containsRectangle(r2));
+  r2 = new Rectangle(0, 2, 15, 5);
+  Expect.isFalse(r.containsRectangle(r2));
+  r2 = new Rectangle(0, 2, 5, 10);
+  Expect.isFalse(r.containsRectangle(r2));
+  r2 = new Rectangle(0, 0, 5, 10);
+  Expect.isTrue(r.containsRectangle(r2));
+}
+
+testContainsPoint() {
+  var r = new Rectangle(20, 40, 60, 80);
+
+  // Test middle.
+  Expect.isTrue(r.containsPoint(new Point(50, 80)));
+
+  // Test edges.
+  Expect.isTrue(r.containsPoint(new Point(20, 40)));
+  Expect.isTrue(r.containsPoint(new Point(50, 40)));
+  Expect.isTrue(r.containsPoint(new Point(80, 40)));
+  Expect.isTrue(r.containsPoint(new Point(80, 80)));
+  Expect.isTrue(r.containsPoint(new Point(80, 120)));
+  Expect.isTrue(r.containsPoint(new Point(50, 120)));
+  Expect.isTrue(r.containsPoint(new Point(20, 120)));
+  Expect.isTrue(r.containsPoint(new Point(20, 80)));
+
+  // Test outside.
+  Expect.isFalse(r.containsPoint(new Point(0, 0)));
+  Expect.isFalse(r.containsPoint(new Point(50, 0)));
+  Expect.isFalse(r.containsPoint(new Point(100, 0)));
+  Expect.isFalse(r.containsPoint(new Point(100, 80)));
+  Expect.isFalse(r.containsPoint(new Point(100, 160)));
+  Expect.isFalse(r.containsPoint(new Point(50, 160)));
+  Expect.isFalse(r.containsPoint(new Point(0, 160)));
+  Expect.isFalse(r.containsPoint(new Point(0, 80)));
+}
+
+testHashCode() {
+  var a = new Rectangle(0, 1, 2, 3);
+  var b = new Rectangle(0, 1, 2, 3);
+  Expect.equals(b.hashCode, a.hashCode);
+
+  var c = new Rectangle(1, 0, 2, 3);
+  Expect.isFalse(a.hashCode == c.hashCode);
+}
+
+testEdgeCases() {
+  edgeTest(double a, double l) {
+    var r = new Rectangle(a, a, l, l);
+    Expect.equals(r, r.boundingBox(r));
+    Expect.equals(r, r.intersection(r));
+  }
+
+  var bignum1 = 0x20000000000000 + 0.0;
+  var bignum2 = 0x20000000000002 + 0.0;
+  var bignum3 = 0x20000000000004 + 0.0;
+  edgeTest(1.0, bignum1);
+  edgeTest(1.0, bignum2);
+  edgeTest(1.0, bignum3);
+  edgeTest(bignum1, 1.0);
+  edgeTest(bignum2, 1.0);
+  edgeTest(bignum3, 1.0);
+}
+
+testEquality() {
+  var bignum = 0x80000000000008 + 0.0;
+  var r1 = new Rectangle(bignum, bignum, 1.0, 1.0);
+  var r2 = new Rectangle(bignum, bignum, 2.0, 2.0);
+  Expect.equals(r2, r1);
+  Expect.equals(r2.hashCode, r1.hashCode);
+  Expect.equals(r2.right, r1.right);
+  Expect.equals(r2.bottom, r1.bottom);
+  Expect.equals(1.0, r1.width);
+  Expect.equals(2.0, r2.width);
+}
+
+testNegativeLengths() {
+  // Constructor allows negative lengths, but clamps them to zero.
+  Expect.equals(new Rectangle(4, 4, 0, 0), new Rectangle(4, 4, -2, -2));
+  Expect.equals(new Rectangle(4, 4, 0, 0), new MutableRectangle(4, 4, -2, -2));
+
+  // Setters clamp negative lengths to zero.
+  var mutable = new MutableRectangle(0, 0, 1, 1);
+  mutable.width = -1;
+  mutable.height = -1;
+  Expect.equals(new Rectangle(0, 0, 0, 0), mutable);
+
+  // Test that doubles are clamped to double zero.
+  var rectangle = new Rectangle(1.5, 1.5, -2.5, -2.5);
+  Expect.isTrue(identical(rectangle.width, 0.0));
+  Expect.isTrue(identical(rectangle.height, 0.0));
+}
+
+testNaNLeft() {
+  var rectangles = [
+    const Rectangle(double.nan, 1, 2, 3),
+    new MutableRectangle(double.nan, 1, 2, 3),
+    new Rectangle.fromPoints(new Point(double.nan, 1), new Point(2, 4)),
+    new MutableRectangle.fromPoints(new Point(double.nan, 1), new Point(2, 4)),
+  ];
+  for (var r in rectangles) {
+    Expect.isFalse(r.containsPoint(new Point(0, 1)));
+    Expect.isFalse(r.containsRectangle(new Rectangle(0, 1, 2, 3)));
+    Expect.isFalse(r.intersects(new Rectangle(0, 1, 2, 3)));
+    Expect.isTrue(r.left.isNaN);
+    Expect.isTrue(r.right.isNaN);
+  }
+}
+
+testNaNTop() {
+  var rectangles = [
+    const Rectangle(0, double.nan, 2, 3),
+    new MutableRectangle(0, double.nan, 2, 3),
+    new Rectangle.fromPoints(new Point(0, double.nan), new Point(2, 4)),
+    new MutableRectangle.fromPoints(new Point(0, double.nan), new Point(2, 4)),
+  ];
+  for (var r in rectangles) {
+    Expect.isFalse(r.containsPoint(new Point(0, 1)));
+    Expect.isFalse(r.containsRectangle(new Rectangle(0, 1, 2, 3)));
+    Expect.isFalse(r.intersects(new Rectangle(0, 1, 2, 3)));
+    Expect.isTrue(r.top.isNaN);
+    Expect.isTrue(r.bottom.isNaN);
+  }
+}
+
+testNaNWidth() {
+  var rectangles = [
+    const Rectangle(0, 1, double.nan, 3),
+    new MutableRectangle(0, 1, double.nan, 3),
+    new Rectangle.fromPoints(new Point(0, 1), new Point(double.nan, 4)),
+    new MutableRectangle.fromPoints(new Point(0, 1), new Point(double.nan, 4)),
+  ];
+  for (var r in rectangles) {
+    Expect.isFalse(r.containsPoint(new Point(0, 1)));
+    Expect.isFalse(r.containsRectangle(new Rectangle(0, 1, 2, 3)));
+    Expect.isFalse(r.intersects(new Rectangle(0, 1, 2, 3)));
+    Expect.isTrue(r.right.isNaN);
+    Expect.isTrue(r.width.isNaN);
+  }
+}
+
+testNaNHeight() {
+  var rectangles = [
+    const Rectangle(0, 1, 2, double.nan),
+    new MutableRectangle(0, 1, 2, double.nan),
+    new Rectangle.fromPoints(new Point(0, 1), new Point(2, double.nan)),
+    new MutableRectangle.fromPoints(new Point(0, 1), new Point(2, double.nan)),
+  ];
+  for (var r in rectangles) {
+    Expect.isFalse(r.containsPoint(new Point(0, 1)));
+    Expect.isFalse(r.containsRectangle(new Rectangle(0, 1, 2, 3)));
+    Expect.isFalse(r.intersects(new Rectangle(0, 1, 2, 3)));
+    Expect.isTrue(r.bottom.isNaN);
+    Expect.isTrue(r.height.isNaN);
+  }
+}
diff --git a/tests/lib_2/lib_2_vm.status b/tests/lib_2/lib_2_vm.status
index aba92ff..864f1a9 100644
--- a/tests/lib_2/lib_2_vm.status
+++ b/tests/lib_2/lib_2_vm.status
@@ -8,15 +8,6 @@
 [ $arch == arm64 && $runtime == vm ]
 mirrors/immutable_collections_test: Pass, Slow # http://dartbug.com/33057
 
-[ $arch == ia32 && $mode == debug && $runtime == vm && $system == windows ]
-convert/streamed_conversion_json_utf8_decode_test: Skip # Verification OOM.
-
-[ $arch != ia32 && $arch != simarm && $arch != simarmv6 && $arch != x64 && $mode == debug && $runtime == vm ]
-convert/streamed_conversion_json_utf8_decode_test: Skip # Verification not yet implemented.
-
-[ $arch == simarm64 && $runtime == vm ]
-convert/utf85_test: Skip # Pass, Slow Issue 20111.
-
 [ $compiler != app_jitk && $compiler != dartk && $compiler != dartkb && $runtime == vm ]
 async/future_or_only_in_async_test/00: MissingCompileTimeError
 convert/streamed_conversion_json_utf8_decode_test: Pass, Slow # Infrequent timeouts.
@@ -79,8 +70,7 @@
 mirrors/library_uri_io_test: RuntimeError
 mirrors/library_uri_package_test: RuntimeError
 
-[ $runtime == vm && ($arch == simarm || $arch == simarmv6) ]
-convert/utf85_test: Skip # Pass, Slow Issue 12644.
-
-[ $arch == simarmv6 || $arch == simarm && $runtime == vm ]
-convert/chunked_conversion_utf88_test: Skip # Pass, Slow Issue 12644.
+[ $arch == simarm || $arch == simarm64 || $hot_reload || $hot_reload_rollback ]
+convert/chunked_conversion_utf88_test: SkipSlow
+convert/streamed_conversion_json_utf8_decode_test: SkipSlow
+convert/utf85_test: SkipSlow
diff --git a/tests/standalone/array_bounds_check_generalization_test.dart b/tests/standalone/array_bounds_check_generalization_test.dart
new file mode 100644
index 0000000..96b5946
--- /dev/null
+++ b/tests/standalone/array_bounds_check_generalization_test.dart
@@ -0,0 +1,89 @@
+// Copyright (c) 2012, 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.
+//
+// We are using --complete-timeline below to ensure that we get timeline events
+// generated during all phases of compilation and deoptimization.
+// VMOptions=--optimization_counter_threshold=10 --no-use-osr --complete-timeline --no-background_compilation
+
+import "package:expect/expect.dart";
+
+test1(a, start, step, N) {
+  var e;
+  for (var i = 0; i < N; i++) {
+    e = a[start + i * step];
+  }
+  return e;
+}
+
+test2(a, b) {
+  var e;
+  for (var i = 0, j = 0, k = 0; i < a.length; i++, j++, k++) {
+    e = b[k] = a[j];
+  }
+  return e;
+}
+
+test3(a, b) {
+  var e;
+  for (var i = 0, j = 1, k = 0; i < a.length - 1; i++, j++, k++) {
+    e = b[k] = a[j - 1];
+  }
+  return e;
+}
+
+test4(a, b) {
+  var e;
+  if (a.length < 2) {
+    return null;
+  }
+
+  for (var i = 0, j = 1, k = 0; i < a.length - 1; i++, j++, k++) {
+    e = b[k] = a[j - 1];
+  }
+  return e;
+}
+
+test5(a, b, k0) {
+  var e;
+  if (a.length < 2) {
+    return null;
+  }
+
+  if (k0 > 1) {
+    return null;
+  }
+
+  for (var i = 0, j = 1, k = 0; i < a.length - 1; i++, j++, k++) {
+    e = b[k - k0] = a[j - 1];
+  }
+  return e;
+}
+
+test6(List<int> a, int M, int N) {
+  var e = 0;
+  for (var i = 0; i < N; i++) {
+    for (var j = 0; j < M; j++) {
+      e += a[i * M + j];
+    }
+  }
+  return e;
+}
+
+main() {
+  var a = const [0, 1, 2, 3, 4, 5, 6, 7];
+  var b = new List(a.length);
+  for (var i = 0; i < 10000; i++) {
+    Expect.equals(a.last, test1(a, 0, 1, a.length));
+    Expect.equals(a.last, test2(a, b));
+    Expect.equals(a[a.length - 2], test3(a, b));
+    Expect.equals(a[a.length - 2], test4(a, b));
+    Expect.equals(a[a.length - 2], test5(a, b, 0));
+    Expect.equals(6, test6(a, 2, 2));
+  }
+
+  test1(a, 0, 2, a.length ~/ 2);
+  Expect.throws(() => test1(a, 1, 1, a.length));
+  Expect.throws(() => test2(a, new List(a.length - 1)));
+  Expect.throws(() => test6(a, 4, 3));
+}
diff --git a/tests/standalone/assert_assignable_canon_test.dart b/tests/standalone/assert_assignable_canon_test.dart
new file mode 100644
index 0000000..f32f5c8
--- /dev/null
+++ b/tests/standalone/assert_assignable_canon_test.dart
@@ -0,0 +1,34 @@
+// 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.
+//
+// VMOptions=--optimization-counter-threshold=10 --no-background-compilation
+
+abstract class A<T extends A<T>> {
+  @pragma('vm:prefer-inline')
+  f(x) => new R<T>(x);
+}
+
+class B extends A<B> {}
+
+class R<T> {
+  @pragma('vm:prefer-inline')
+  R(T field);
+}
+
+class C extends B {}
+
+class D extends C {}
+
+// f will be inlined and T=B will be forwarded to AssertAssignable in the
+// R. However B will be wrapped in the TypeRef which breaks runtime TypeCheck
+// function (Instance::IsInstanceOf does not work for TypeRefs).
+@pragma('vm:never-inline')
+f(o) => new B().f(o);
+
+main() {
+  final o = new D();
+  for (var i = 0; i < 10; i++) {
+    f(o);
+  }
+}
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
new file mode 100644
index 0000000..2518819
--- /dev/null
+++ b/tests/standalone/standalone.status
@@ -0,0 +1,100 @@
+# Copyright (c) 2017, 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.
+# WARNING:
+# Tests using the multitest feature where failure is expected should *also* be
+# listed in tests/lib/analyzer/analyze_tests.status without the "standalone"
+# prefix.
+io/http_linklocal_ipv6_test: SkipByDesign # This needs manual test.
+io/non_utf8_directory_test: Skip # Issue 33519. Temp files causing bots to go purple.
+io/non_utf8_file_test: Skip # Issue 33519. Temp files causing bots to go purple.
+io/non_utf8_link_test: Skip # Issue 33519. Temp files causing bots to go purple.
+packages_file_test: Skip # Issue 26715
+packages_file_test/none: Skip # contains no tests.
+
+[ $builder_tag == asan ]
+io/process_detached_test: Slow
+
+[ $builder_tag == no_ipv6 ]
+io/http_ipv6_test: SkipByDesign
+io/http_loopback_test: SkipByDesign
+io/http_proxy_advanced_test: SkipByDesign
+io/socket_bind_test: SkipByDesign
+io/socket_info_ipv6_test: SkipByDesign
+io/socket_ipv6_test: SkipByDesign
+io/socket_source_address_test: SkipByDesign
+
+[ $compiler == dart2analyzer ]
+deferred_transitive_import_error_test: Skip
+
+[ $compiler == dartkp ]
+causal_async_stack_test: Skip # Flaky.
+
+[ $mode == product ]
+dart_developer_env_test: SkipByDesign
+io/stdio_implicit_close_test: Skip # SkipByDesign
+no_profiler_test: SkipByDesign
+no_support_coverage_test: SkipByDesign
+no_support_debugger_test: SkipByDesign
+no_support_disassembler_test: SkipByDesign
+no_support_il_printer_test: SkipByDesign
+no_support_service_test: SkipByDesign
+no_support_timeline_test: SkipByDesign
+verbose_gc_to_bmu_test: SkipByDesign # No verbose_gc in product mode
+
+[ $runtime == dart_precompiled ]
+http_launch_test: Skip
+io/addlatexhash_test: Skip
+io/wait_for_event_isolate_test: SkipByDesign # Uses mirrors.
+io/wait_for_event_microtask_test: SkipByDesign # Uses mirrors.
+io/wait_for_event_nested_microtask_test: SkipByDesign # Uses mirrors.
+io/wait_for_event_nested_timer_microtask_test: SkipByDesign # Uses mirrors.
+io/wait_for_event_nested_timer_test: SkipByDesign # Uses mirrors.
+io/wait_for_event_nested_waits_test: SkipByDesign # Uses mirrors.
+io/wait_for_event_timer_test: SkipByDesign # Uses mirrors.
+io/wait_for_event_zone_caught_error_test: SkipByDesign # Uses mirrors.
+io/wait_for_event_zone_test: SkipByDesign # Uses mirrors.
+io/wait_for_test: SkipByDesign # Uses mirrors.
+verbose_gc_to_bmu_test: Skip # Attempts to spawn dart using Platform.executable
+
+[ $builder_tag == swarming && $system == macos ]
+io/*: Skip # Issue 30618
+
+[ $compiler == none && $runtime == vm && $system == fuchsia ]
+*: Skip # Not yet triaged.
+
+[ $compiler != none && $runtime != dart_precompiled && $runtime != vm ]
+env_test: Skip # This is testing a vm command line parsing scenario.
+
+[ $mode == product && $runtime == dart_precompiled ]
+dwarf_stack_trace_test: SkipByDesign # Due to instruction canonicalization we can end up having the wrong names in stack traces.
+
+[ $runtime == vm && $system == linux ]
+io/http_basic_test: Slow # Issue 28046, These tests might be slow on an opt counter threshold bot. They also time out on the bot occasionally => flaky test issue 28046
+io/http_launch_test: Slow # Issue 28046, These tests might be slow on an opt counter threshold bot. They also time out on the bot occasionally => flaky test issue 28046
+
+[ $system == macos && ($runtime == dart_precompiled || $runtime == vm) ]
+io/raw_secure_server_socket_test: Crash
+io/raw_server_socket_cancel_test: Skip # Issue 28182 # This test sometimes hangs on Mac.
+io/secure_server_client_certificate_test: Skip # Re-enable once the bots have been updated. Issue #26057
+io/socket_many_connections_test: Skip # This test fails with "Too many open files" on the Mac OS buildbot. This is expected as MacOS by default runs with a very low number of allowed open files ('ulimit -n' says something like 256).
+
+[ $arch == arm || $arch == arm64 || $runtime != vm || $system == android ]
+fragmentation_test: SkipSlow
+fragmentation_typed_data_test: SkipSlow
+
+[ $compiler == dart2js || $compiler == dartdevc || $compiler == dartdevk ]
+*: SkipByDesign
+
+[ $mode == product || $runtime == dart_precompiled ]
+no_assert_test: SkipByDesign
+
+[ $runtime == dart_precompiled || $runtime == vm ]
+deferred_transitive_import_error_test: Skip
+
+[ $hot_reload || $hot_reload_rollback ]
+io/addlatexhash_test: Crash # Issue 31252
+io/many_directory_operations_test: SkipSlow
+io/many_file_operations_test: SkipSlow
+package/*: SkipByDesign # Launches VMs in interesting ways.
+typed_data_isolate_test: SkipSlow
diff --git a/tests/standalone/standalone_analyzer.status b/tests/standalone/standalone_analyzer.status
new file mode 100644
index 0000000..170e2de
--- /dev/null
+++ b/tests/standalone/standalone_analyzer.status
@@ -0,0 +1,6 @@
+# Copyright (c) 2017, 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.
+
+[ $compiler == dart2analyzer ]
+deferred_transitive_import_error_test: Skip # Contains intentional errors.
diff --git a/tests/standalone/standalone_kernel.status b/tests/standalone/standalone_kernel.status
new file mode 100644
index 0000000..b967e9f
--- /dev/null
+++ b/tests/standalone/standalone_kernel.status
@@ -0,0 +1,111 @@
+# Copyright (c) 2017, 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.
+# Sections in this file should contain "$compiler == dartk" or
+# "$compiler == dartkp".
+
+fragmentation_test: Pass, Slow # GC heavy
+fragmentation_typed_data_test: Pass, Slow # GC heavy
+io/process_sync_test: Pass, Slow # Spawns synchronously subprocesses in sequence.
+
+[ $compiler == dartkb ]
+no_lazy_dispatchers_test: SkipByDesign # KBC interpreter doesn't support --no_lazy_dispatchers
+
+[ $system == android ]
+entrypoints_verification_test: Skip # Requires shared objects which the test script doesn't "adb push".
+
+[ $arch == ia32 && $builder_tag == optimization_counter_threshold ]
+io/file_lock_test: SkipSlow # Timeout
+
+[ $arch == simarm64 && ($compiler == dartk || $compiler == dartkb) ]
+io/http_bind_test: Slow
+
+[ $builder_tag == optimization_counter_threshold && ($compiler == dartk || $compiler == dartkb) ]
+map_insert_remove_oom_test: Skip # Heap limit too low.
+
+[ $compiler == dartkp && $mode == debug && $runtime == dart_precompiled ]
+io/raw_socket_test: Crash
+io/socket_exception_test: Crash
+io/socket_finalizer_test: Crash
+io/socket_info_ipv4_test: Crash
+io/socket_info_ipv6_test: Crash
+io/socket_port_test: Crash
+
+[ $compiler == dartkp && $runtime == dart_precompiled ]
+io/compile_all_test: Skip # We do not support --compile-all for precompilation
+io/http_client_connect_test: Skip # Flaky.
+io/http_content_length_test: Skip # Flaky.
+io/http_proxy_advanced_test: Skip # Flaky
+io/http_proxy_test: Skip # Flaky.
+io/http_response_deadline_test: Skip # Flaky.
+io/http_reuse_server_port_test: Skip # Flaky.
+io/http_server_close_response_after_error_test: Skip # Flaky.
+io/http_shutdown_test: Skip # Flaky.
+io/https_client_certificate_test: Crash
+io/platform_test: Crash
+io/raw_datagram_socket_test: Skip # Flaky.
+io/raw_secure_server_closing_test: Skip # Flaky
+io/raw_socket_test: Crash
+io/secure_multiple_client_server_test: Skip # Flaky.
+io/secure_server_closing_test: Skip # Flaky.
+io/secure_server_socket_test: Skip # Flaky.
+io/secure_socket_renegotiate_test: Crash
+io/socket_many_connections_test: Skip # Flaky
+io/web_socket_error_test: Skip # Flaky
+io/web_socket_ping_test: Skip # Flaky.
+io/web_socket_test: Skip # Flaky.
+map_insert_remove_oom_test: Skip # Heap limit too low.
+no_support_debugger_test: Skip # kernel-service snapshot not compatible with flag disabled
+
+[ $mode == debug && $runtime == vm && ($compiler == dartk || $compiler == dartkb) ]
+io/file_lock_test: Slow
+io/raw_socket_test: Crash
+io/socket_exception_test: Crash
+io/socket_finalizer_test: Crash
+io/socket_info_ipv4_test: Crash
+io/socket_info_ipv6_test: Crash
+io/socket_port_test: Crash
+
+[ $mode == debug && $hot_reload && ($compiler == dartk || $compiler == dartkb) ]
+io/web_socket_ping_test: Crash
+
+[ $runtime == vm && ($compiler == dartk || $compiler == dartkb) ]
+no_support_debugger_test: Skip # kernel-service snapshot not compatible with flag disabled
+
+[ $system == windows && ($compiler == dartk || $compiler == dartkb) ]
+io/dart_std_io_pipe_test: Slow
+io/secure_builtin_roots_test: Skip # Issues 32137 and 32138.
+io/wait_for_event_isolate_test: Skip # Issues 32137 and 32138.
+map_insert_remove_oom_test: Skip # Heap limit too low.
+
+[ $hot_reload && ($compiler == dartk || $compiler == dartkb) ]
+io/http_no_reason_phrase_test: Crash
+io/http_outgoing_size_test: Crash
+
+[ $hot_reload_rollback && ($compiler == dartk || $compiler == dartkb) ]
+io/directory_chdir_test: Skip # Timeout
+io/echo_server_stream_test: Slow
+
+# Enabling of dartk for sim{arm,arm64} revealed these test failures, which
+# are to be triaged.  Isolate tests are skipped on purpose due to the usage of
+# batch mode.
+[ ($arch == simarm || $arch == simarm64) && ($compiler == dartk || $compiler == dartkb) ]
+io/file_blocking_lock_test: Crash # Please triage.
+io/file_lock_test: Slow
+map_insert_remove_oom_test: Skip # Heap limit too low.
+
+[ ($compiler == dartk || $compiler == dartkb) && ($hot_reload || $hot_reload_rollback) ]
+io/addlatexhash_test: Skip # Timeout
+io/http_advanced_test: Skip # Timeout
+io/http_auth_digest_test: Crash
+io/http_auth_test: Skip # Timeout
+io/http_proxy_advanced_test: Skip # Timeout
+io/http_read_test: Skip # Timeout
+io/pipe_server_test: Skip # Timeout
+io/socket_close_test: Skip # Timeout
+io/socket_many_connections_test: Skip # Timeout
+io/web_socket_compression_test: Skip # Timeout
+io/web_socket_test: Skip # Timeout
+
+[ $compiler != dartk && $compiler != dartkb && $compiler != dartkp || $compiler == dartkp && $system == windows ]
+entrypoints_verification_test: SkipByDesign # Requires VM to run. Cannot run in precompiled Windows because the DLL is linked against dart.exe instead of dart_precompiled_runtime.exe.
diff --git a/tests/standalone/standalone_precompiled.status b/tests/standalone/standalone_precompiled.status
new file mode 100644
index 0000000..672a30e
--- /dev/null
+++ b/tests/standalone/standalone_precompiled.status
@@ -0,0 +1,68 @@
+# Copyright (c) 2017, 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.
+
+[ $builder_tag == obfuscated ]
+dwarf_stack_trace_test: Pass, RuntimeError # Issue 35563
+
+[ $runtime == dart_precompiled ]
+http_launch_test: Skip
+io/addlatexhash_test: Skip
+io/dart_std_io_pipe_test: Skip
+io/directory_list_sync_test: Timeout, Skip # Expects to find the test directory relative to the script.
+io/file_blocking_lock_test: Skip
+io/file_lock_test: Skip
+io/file_read_special_device_test: Skip
+io/http_client_stays_alive_test: Skip
+io/http_response_deadline_test: Skip
+io/http_server_close_response_after_error_test: Skip
+io/https_unauthorized_test: Skip
+io/named_pipe_script_test: Skip
+io/namespace_test: Skip # Issue 33168
+io/platform_resolved_executable_test: Skip
+io/platform_test: RuntimeError # Expects to be running from 'dart' instead of 'dart_precompiled_runtime'
+io/print_sync_test: Skip
+io/process_check_arguments_test: Skip
+io/process_detached_test: Skip
+io/process_environment_test: Skip
+io/process_inherit_stdio_test: Skip
+io/process_non_ascii_test: Skip
+io/process_run_output_test: Skip
+io/process_set_exit_code_test: Skip
+io/process_shell_test: Skip
+io/process_stderr_test: Skip
+io/process_stdin_transform_unsubscribe_test: Skip
+io/process_stdout_test: Skip
+io/process_sync_test: Skip
+io/raw_datagram_socket_test: Skip
+io/regress_7191_test: Skip
+io/regress_7679_test: Skip
+io/secure_unauthorized_test: Skip
+io/signals_test: Skip
+io/stdin_sync_test: Skip
+io/stdio_implicit_close_test: Skip
+io/stdio_nonblocking_test: Skip
+io/test_extension_fail_test: Skip
+io/test_extension_test: Skip
+io/windows_environment_test: Skip
+package/scenarios/empty_packages_file/empty_packages_file_noimports_test: Skip
+package/scenarios/invalid/invalid_utf8_test: Skip
+package/scenarios/invalid/non_existent_packages_file_test: Skip
+package/scenarios/invalid/same_package_twice_test: Skip
+package/scenarios/packages_file_strange_formatting/empty_lines_test: Skip
+package/scenarios/packages_file_strange_formatting/mixed_line_ends_test: Skip
+package/scenarios/packages_option_only/packages_option_only_noimports_test: Skip
+package/scenarios/packages_option_only/packages_option_only_test: Skip
+
+[ $arch == arm && $mode == release && $runtime == dart_precompiled && $system == android ]
+io/socket_cancel_connect_test: RuntimeError # Issue 34142
+io/stdout_stderr_non_blocking_test: Pass, Timeout # Issue 28426
+
+[ $mode == product && $runtime == dart_precompiled ]
+dwarf_stack_trace_test: Pass, RuntimeError # Results will flake due to identical code folding
+
+[ $runtime == dart_precompiled && $checked ]
+io/namespace_test: RuntimeError
+
+[ $mode == product || $runtime == dart_precompiled ]
+no_assert_test: SkipByDesign # Requires checked mode.
diff --git a/tests/standalone/standalone_vm.status b/tests/standalone/standalone_vm.status
new file mode 100644
index 0000000..93e314f
--- /dev/null
+++ b/tests/standalone/standalone_vm.status
@@ -0,0 +1,79 @@
+# Copyright (c) 2017, 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.
+
+[ $arch == ia32 ]
+link_natives_lazily_test: SkipByDesign # Not supported.
+no_allow_absolute_addresses_test: SkipByDesign # Not supported.
+
+[ $system == android ]
+io/file_stat_test: Skip # Issue 26376
+io/file_system_watcher_test: Skip # Issue 26376
+io/file_test: Skip # Issue 26376
+io/http_proxy_advanced_test: Skip # Issue 27638
+io/http_proxy_test: Skip # Issue 27638
+io/https_bad_certificate_test: Skip # Issue 27638
+io/https_server_test: Skip # Issue 27638
+io/non_utf8_output_test: Skip # The Android command runner doesn't correctly handle non-UTF8 formatted output. https://github.com/dart-lang/sdk/issues/28872
+io/process_exit_test: Skip # Issue 29578
+io/process_path_environment_test: Skip # Issue 26376
+io/process_path_test: Skip # Issue 26376
+io/process_segfault_test: Skip # Issue 26376
+io/raw_datagram_socket_test: Skip # Issue 27638
+io/raw_secure_server_closing_test: Skip # Issue 27638
+io/raw_secure_server_socket_test: Skip # Issue 27638
+io/raw_secure_socket_pause_test: Skip # Issue 27638
+io/raw_secure_socket_test: Skip # Issue 27638
+io/regress_21160_test: Skip # Issue 27638
+io/resolve_symbolic_links_test: Skip # Issue 26376
+io/secure_bad_certificate_test: Skip # Issue 27638
+io/secure_client_raw_server_test: Skip # Issue 27638
+io/secure_client_server_test: Skip # Issue 27638
+io/secure_multiple_client_server_test: Skip # Issue 27638
+io/secure_server_client_certificate_test: Skip # Issue 27638
+io/secure_server_closing_test: Skip # Issue 27638
+io/secure_server_socket_test: Skip # Issue 27638
+io/secure_session_resume_test: Skip # Issue 27638
+io/secure_socket_alpn_test: Skip # Issue 27638
+io/secure_socket_test: Skip # Issue 27638
+io/socket_upgrade_to_secure_test: Skip # Issue 27638
+
+[ $system == windows ]
+io/process_sync_test: Pass, Timeout # Issue 24596
+io/sleep_test: Pass, Fail # Issue 25757
+io/socket_info_ipv6_test: Skip
+verbose_gc_to_bmu_test: Skip
+
+[ $arch == arm && $mode == release && $runtime == dart_precompiled && $system == android ]
+io/stdout_stderr_non_blocking_test: Pass, Timeout # Issue 28426
+
+[ $arch == x64 && $compiler == dartkb && $runtime == vm && $system == linux ]
+io/stdout_stderr_non_blocking_test: Pass, Timeout # Issue 35192
+
+[ $arch == x64 && $mode == release && $runtime == vm && $system == linux ]
+io/http_bind_test: Pass, Timeout # Issue 35192
+
+[ $compiler != dart2analyzer && $system == windows ]
+io/platform_resolved_executable_test/06: RuntimeError # Issue 23641
+
+[ $mode == release && $runtime == vm && $system == macos ]
+io/http_server_close_response_after_error_test: Pass, Timeout # Issue 28370: timeout.
+io/named_pipe_script_test: Pass, RuntimeError # Issue 28737
+
+[ $mode == release && $runtime == vm && $system == windows ]
+io/http_server_close_response_after_error_test: Pass, Timeout # Issue 28370: timeout.
+
+[ $runtime == dart_precompiled && $system == linux && ($arch == simarm || $arch == simarm64 || $arch == x64) ]
+io/stdout_stderr_non_blocking_test: Pass, Timeout # Issue 35192
+
+[ $runtime == vm && ($arch == arm || $arch == arm64) ]
+io/dart_std_io_pipe_test: Timeout, Pass
+io/file_input_stream_test: Skip # Issue 26109
+io/file_stream_test: Skip # Issue 26109
+io/file_typed_data_test: Skip # Issue 26109
+io/process_sync_test: Timeout, Pass
+
+[ $runtime == vm && ($arch == simarm || $arch == simarm64) ]
+io/dart_std_io_pipe_test: Timeout, Pass
+io/http_client_stays_alive_test: Skip # Spawns process in Dart2 mode.
+io/process_sync_test: Timeout, Pass
diff --git a/tests/standalone_2/io/http_cookie_date_test.dart b/tests/standalone_2/io/http_cookie_date_test.dart
index 621d9e5..6b94254 100644
--- a/tests/standalone_2/io/http_cookie_date_test.dart
+++ b/tests/standalone_2/io/http_cookie_date_test.dart
@@ -2,11 +2,14 @@
 // 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.6
+
 library dart._http;
 
 import "dart:async";
 import "dart:collection";
 import "dart:convert";
+import "dart:developer";
 import "dart:io";
 import "dart:math";
 import "dart:typed_data";
diff --git a/tests/standalone_2/io/http_headers_test.dart b/tests/standalone_2/io/http_headers_test.dart
index 3a2cbb3..ea53d8a 100644
--- a/tests/standalone_2/io/http_headers_test.dart
+++ b/tests/standalone_2/io/http_headers_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.
 
+// @dart = 2.6
+
 library dart._http;
 
 import "dart:async";
diff --git a/tests/standalone_2/io/http_override_test.dart b/tests/standalone_2/io/http_override_test.dart
index adcb2ab..25d4598 100644
--- a/tests/standalone_2/io/http_override_test.dart
+++ b/tests/standalone_2/io/http_override_test.dart
@@ -16,6 +16,7 @@
   Duration connectionTimeout;
   int maxConnectionsPerHost;
   bool autoUncompress;
+  bool enableTimelineLogging;
 
   Future<HttpClientRequest> open(
           String method, String host, int port, String path) =>
@@ -55,6 +56,7 @@
   Duration connectionTimeout;
   int maxConnectionsPerHost;
   bool autoUncompress;
+  bool enableTimelineLogging;
 
   Future<HttpClientRequest> open(
           String method, String host, int port, String path) =>
diff --git a/tests/standalone_2/io/http_parser_test.dart b/tests/standalone_2/io/http_parser_test.dart
index d82f355..06ed070 100644
--- a/tests/standalone_2/io/http_parser_test.dart
+++ b/tests/standalone_2/io/http_parser_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.
 
+// @dart = 2.6
+
 library dart._http;
 
 import "dart:async";
diff --git a/tests/standalone_2/io/process_exit_negative_test.dart b/tests/standalone_2/io/process_exit_negative_test.dart
deleted file mode 100644
index 645f7e6..0000000
--- a/tests/standalone_2/io/process_exit_negative_test.dart
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (c) 2012, 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.
-//
-// Process test program to test that compilation errors in the process
-// exit handler are reported correctly.
-
-import "dart:io";
-import "process_test_util.dart";
-
-void main() {
-  var fp = Process.start(getProcessTestFileName(), const ["0", "0", "0", "0"]);
-  fp.then((p) {
-    p.exitCode.then((int s) {
-      print(a.toString()); // Should cause a compilation error here.
-    });
-    // Drain stdout and stderr.
-    p.stdout.listen((_) {});
-    p.stderr.listen((_) {});
-  });
-}
diff --git a/tests/standalone_2/io/web_socket_error_test.dart b/tests/standalone_2/io/web_socket_error_test.dart
index c757688..659ee7f 100644
--- a/tests/standalone_2/io/web_socket_error_test.dart
+++ b/tests/standalone_2/io/web_socket_error_test.dart
@@ -9,6 +9,8 @@
 // OtherResources=certificates/server_chain.pem
 // OtherResources=certificates/server_key.pem
 
+// @dart = 2.6
+
 library dart._http;
 
 import "dart:async";
diff --git a/tests/standalone_2/io/web_socket_ping_test.dart b/tests/standalone_2/io/web_socket_ping_test.dart
index 1ee03b5..3960958 100644
--- a/tests/standalone_2/io/web_socket_ping_test.dart
+++ b/tests/standalone_2/io/web_socket_ping_test.dart
@@ -7,6 +7,8 @@
 // VMOptions=--short_socket_write
 // VMOptions=--short_socket_read --short_socket_write
 
+// @dart = 2.6
+
 library dart._http;
 
 import "package:expect/expect.dart";
diff --git a/tests/standalone_2/io/web_socket_protocol_processor_test.dart b/tests/standalone_2/io/web_socket_protocol_processor_test.dart
index 75ac75a..fc50c61 100644
--- a/tests/standalone_2/io/web_socket_protocol_processor_test.dart
+++ b/tests/standalone_2/io/web_socket_protocol_processor_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.
 
+// @dart = 2.6
+
 library dart._http;
 
 import "package:async_helper/async_helper.dart";
diff --git a/tests/standalone_2/standalone_2_analyzer.status b/tests/standalone_2/standalone_2_analyzer.status
index fa699b4..170e2de 100644
--- a/tests/standalone_2/standalone_2_analyzer.status
+++ b/tests/standalone_2/standalone_2_analyzer.status
@@ -4,5 +4,3 @@
 
 [ $compiler == dart2analyzer ]
 deferred_transitive_import_error_test: Skip # Contains intentional errors.
-io/process_exit_negative_test: Skip
-
diff --git a/tools/VERSION b/tools/VERSION
index 200c0df..20a401d 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -33,7 +33,7 @@
 MAJOR 2
 MINOR 7
 PATCH 0
-PRERELEASE 1
+PRERELEASE 2
 PRERELEASE_PATCH 0
-ABI_VERSION 23
+ABI_VERSION 24
 OLDEST_SUPPORTED_ABI_VERSION 23
diff --git a/tools/bots/dart_sdk.py b/tools/bots/dart_sdk.py
index ac91988..a545a97 100755
--- a/tools/bots/dart_sdk.py
+++ b/tools/bots/dart_sdk.py
@@ -81,6 +81,11 @@
                         GuessExtension('gen_snapshot'))
             CopyBetween(product_sdk_path, sdk_path, 'bin',
                         GuessExtension('dartaotruntime'))
+            shutil.copy2(
+                os.path.join(product_sdk_path, 'lib', '_internal',
+                             'vm_platform_strong.dill'),
+                os.path.join(sdk_path, 'lib', '_internal',
+                             'vm_platform_strong_product.dill'))
 
 
 def DartArchiveUploadSDKs(system, arch, sdk_zip):
diff --git a/tools/bots/test_matrix.json b/tools/bots/test_matrix.json
index ea209ae..8854609 100644
--- a/tools/bots/test_matrix.json
+++ b/tools/bots/test_matrix.json
@@ -15,7 +15,9 @@
       "third_party/pkg_tested/",
       "tools/",
       "out/ReleaseX64/dart-sdk/",
-      "xcodebuild/ReleaseX64/dart-sdk/"
+      "out/ReleaseX64NNBD/dart-sdk/",
+      "xcodebuild/ReleaseX64/dart-sdk/",
+      "xcodebuild/ReleaseX64NNBD/dart-sdk/"
     ],
     "dart2js": [
       ".packages",
@@ -29,6 +31,7 @@
       "sdk/",
       "tests/angular/",
       "tests/co19_2/co19_2-analyzer.status",
+      "tests/co19_2/co19_2-co19.status",
       "tests/co19_2/co19_2-dart2js.status",
       "tests/co19_2/co19_2-dartdevc.status",
       "tests/co19_2/co19_2-kernel.status",
@@ -66,6 +69,7 @@
       "sdk_nnbd/",
       "tests/angular/",
       "tests/co19_2/co19_2-analyzer.status",
+      "tests/co19_2/co19_2-co19.status",
       "tests/co19_2/co19_2-dart2js.status",
       "tests/co19_2/co19_2-dartdevc.status",
       "tests/co19_2/co19_2-kernel.status",
@@ -106,6 +110,7 @@
       "sdk/",
       "tests/angular/",
       "tests/co19_2/co19_2-analyzer.status",
+      "tests/co19_2/co19_2-co19.status",
       "tests/co19_2/co19_2-dart2js.status",
       "tests/co19_2/co19_2-dartdevc.status",
       "tests/co19_2/co19_2-kernel.status",
@@ -143,6 +148,7 @@
       "sdk/",
       "tests/angular/",
       "tests/co19_2/co19_2-analyzer.status",
+      "tests/co19_2/co19_2-co19.status",
       "tests/co19_2/co19_2-dart2js.status",
       "tests/co19_2/co19_2-dartdevc.status",
       "tests/co19_2/co19_2-kernel.status",
@@ -241,6 +247,7 @@
       "third_party/observatory_pub_packages/packages/",
       "tests/angular/",
       "tests/co19_2/co19_2-analyzer.status",
+      "tests/co19_2/co19_2-co19.status",
       "tests/co19_2/co19_2-dart2js.status",
       "tests/co19_2/co19_2-dartdevc.status",
       "tests/co19_2/co19_2-kernel.status",
@@ -528,7 +535,7 @@
         "checked": true,
         "use-sdk": true
     }},
-    "dartdevc-strong-linux-release-chrome": {
+    "dartdevk-strong-linux-release-chrome": {
       "options": {
         "checked": true,
         "use-sdk": true,
@@ -536,7 +543,7 @@
         "enable-asserts": true
 
     }},
-    "dartdevc-weak-linux-release-chrome": {
+    "dartdevk-weak-linux-release-chrome": {
       "options": {
         "checked": true,
         "use-sdk": true,
@@ -555,6 +562,20 @@
         "compiler": "dart2analyzer",
         "enable-asserts": true,
         "use-sdk": true
+    }},
+    "analyzer-asserts-strong-linux": {
+      "options": {
+        "compiler": "dart2analyzer",
+        "enable-asserts": true,
+        "use-sdk": true,
+        "enable-experiment": ["non-nullable"]
+    }},
+    "analyzer-asserts-weak-linux": {
+      "options": {
+        "compiler": "dart2analyzer",
+        "enable-asserts": true,
+        "use-sdk": true,
+        "enable-experiment": ["non-nullable"]
     }}
   },
   "builder_configurations": [
@@ -1478,14 +1499,14 @@
         {
           "name": "ddc nnbd strong tests",
           "arguments": [
-            "-ndartdevc-strong-linux-release-chrome",
+            "-ndartdevk-strong-linux-release-chrome",
             "dartdevc_native"
           ]
         },
         {
           "name": "ddc nnbd weak tests",
           "arguments": [
-            "-ndartdevc-weak-linux-release-chrome",
+            "-ndartdevk-weak-linux-release-chrome",
             "dartdevc_native"
           ]
         }
@@ -1983,7 +2004,7 @@
           "name": "build gen_snapshot and dartaotruntime",
           "script": "tools/build.py",
           "arguments": ["--arch=x64,arm,arm64", "--mode=product",
-                        "copy_gen_snapshot", "copy_dartaotruntime"]
+                        "copy_gen_snapshot", "copy_dartaotruntime", "copy_vm_dill_files"]
         },
         {
           "name": "upload sdk",
@@ -2033,7 +2054,7 @@
           "name": "build gen_snapshot and dartaotruntime",
           "script": "tools/build.py",
           "arguments": ["--arch=x64", "--mode=product",
-                        "copy_gen_snapshot", "copy_dartaotruntime"]
+                        "copy_gen_snapshot", "copy_dartaotruntime", "copy_vm_dill_files"]
         },
         {
           "name": "upload sdk",
@@ -2070,7 +2091,7 @@
           "name": "build gen_snapshot and dartaotruntime",
           "script": "tools/build.py",
           "arguments": ["--arch=x64", "--mode=product",
-                        "copy_gen_snapshot", "copy_dartaotruntime"]
+                        "copy_gen_snapshot", "copy_dartaotruntime", "copy_vm_dill_files"]
         },
         {
           "name": "upload sdk",
@@ -2189,6 +2210,33 @@
     },
     {
       "builders": [
+        "analyzer-nnbd-linux-release"
+      ],
+      "meta": {
+        "description": "This configuration is used by the nnbd analyzer builder."
+      },
+      "steps": [
+        {
+          "name": "build dart",
+          "script": "tools/build.py",
+          "arguments": ["--nnbd", "create_sdk"]
+        },
+        {
+          "name": "analyze nnbd strong tests enable-asserts",
+          "arguments": [
+            "-nanalyzer-asserts-strong-${system}",
+            "language"]
+        },
+        {
+          "name": "analyze nnbd weak tests enable-asserts",
+          "arguments": [
+            "-nanalyzer-asserts-weak-${system}",
+            "language"]
+        }
+      ]
+    },
+    {
+      "builders": [
         "analyzer-analysis-server-linux",
         "analyzer-analysis-server-linux-analyzer-stable"
       ],
diff --git a/tools/experimental_features.yaml b/tools/experimental_features.yaml
index 82358dc..798f942 100644
--- a/tools/experimental_features.yaml
+++ b/tools/experimental_features.yaml
@@ -83,6 +83,9 @@
 variance:
   help: "Sound variance."
 
+nonfunction-type-aliases:
+  help: "Type aliases define a <type>, not just a <functionType>."
+
 #
 # Flags below this line are shipped, retired, or rejected, cannot be specified
 # on the command line, and will eventually be removed.
diff --git a/tools/gn.py b/tools/gn.py
index 81da03d..1a9908c 100755
--- a/tools/gn.py
+++ b/tools/gn.py
@@ -247,6 +247,7 @@
     gn_args['is_tsan'] = args.tsan
     gn_args['is_ubsan'] = args.ubsan
     gn_args['include_dart2native'] = True
+    gn_args['is_qemu'] = args.use_qemu
 
     if not args.platform_sdk and not gn_args['target_cpu'].startswith('arm'):
         gn_args['dart_platform_sdk'] = args.platform_sdk
@@ -522,6 +523,11 @@
         default=False,
         dest='use_crashpad',
         action='store_true')
+    other_group.add_argument(
+        '--use-qemu',
+        default=False,
+        dest='use_qemu',
+        action='store_true')
 
     options = parser.parse_args(args)
     if not ProcessOptions(options):
diff --git a/tools/test.dart b/tools/test.dart
index 5a47fb3..f4cbd7b 100755
--- a/tools/test.dart
+++ b/tools/test.dart
@@ -440,7 +440,6 @@
   final branches = (testMatrix["branches"] as List).cast<String>();
   final buildersConfigurations =
       testMatrix["builder_configurations"] as List<dynamic>;
-
   // Determine what named configuration to run and which builders to download
   // existing results from.
   ResolvedConfigurations configurations = resolveNamedConfigurations(
@@ -455,7 +454,7 @@
     exitCode = 1;
     return;
   }
-
+  // Print information about the resolved builders to compare with.
   for (final builder in configurations.builders) {
     if (localConfiguration != null) {
       print("Testing the named configuration $localConfiguration "
@@ -467,27 +466,30 @@
           "compared with builder $builder");
     }
   }
-
   // Use given commit or find out where the current HEAD branched.
   final commit = options["commit"] ??
       await findMergeBase(options["remote"], options["branch"]);
   print("Base commit is $commit");
-
   // Store the downloaded results and our test results in a temporary directory.
   final outDirectory = await Directory.systemTemp.createTemp("test.dart.");
   try {
-    final mergedResults = <String, Map<String, dynamic>>{};
-    final mergedFlaky = <String, Map<String, dynamic>>{};
-
+    final tasks = <Future>[];
     bool needsConfigurationOverride = localConfiguration != null &&
         localConfiguration != namedConfigurations.single;
     bool needsMerge = configurations.builders.length > 1;
-
-    // Use the buildbucket API to search for builds of the right commit.
     final inexactBuilds = <String, String>{};
+    var previousFileName = "previous.json";
+    var flakyFileName = "flaky.json";
+    var downloadNumber = 0;
+    // Download the previous results and flakiness info from cloud storage.
     for (final builder in configurations.builders) {
-      // Download the previous results and flakiness info from cloud storage.
+      if (needsMerge) {
+        previousFileName = "previous-$downloadNumber.json";
+        flakyFileName = "flaky-$downloadNumber.json";
+        downloadNumber++;
+      }
       print("Finding build on builder $builder to compare with...");
+      // Use the buildbucket API to search for builds of the right commit.
       final buildSearchResult =
           await searchForApproximateBuild(builder, commit);
       if (buildSearchResult.commit != commit) {
@@ -497,50 +499,19 @@
       }
       final buildNumber = buildSearchResult.build.toString();
       print("Downloading results from builder $builder build $buildNumber...");
-      await cpGsutil(buildFileCloudPath(builder, buildNumber, "results.json"),
-          "${outDirectory.path}/previous.json");
+      tasks.add(cpGsutil(
+          buildFileCloudPath(builder, buildNumber, "results.json"),
+          "${outDirectory.path}/$previousFileName"));
       if (!options["report-flakes"]) {
-        await cpGsutil(buildFileCloudPath(builder, buildNumber, "flaky.json"),
-            "${outDirectory.path}/flaky.json");
-      }
-      // Merge the results for the builders.
-      if (needsMerge || needsConfigurationOverride) {
-        var results =
-            await loadResultsMap("${outDirectory.path}/previous.json");
-        if (needsConfigurationOverride) {
-          overrideConfiguration(
-              results, namedConfigurations.single, localConfiguration);
-        }
-        mergedResults.addAll(results);
-        if (!options["report-flakes"]) {
-          var flakyTests =
-              await loadResultsMap("${outDirectory.path}/flaky.json");
-          if (needsConfigurationOverride) {
-            overrideConfiguration(
-                flakyTests, namedConfigurations.single, localConfiguration);
-          }
-          mergedFlaky.addAll(flakyTests);
-        }
+        tasks.add(cpGsutil(
+            buildFileCloudPath(builder, buildNumber, "flaky.json"),
+            "${outDirectory.path}/$flakyFileName"));
       }
     }
-
-    // Write out the merged results for the builders.
-    if (needsMerge || needsConfigurationOverride) {
-      await new File("${outDirectory.path}/previous.json").writeAsString(
-          mergedResults.values.map((data) => jsonEncode(data) + "\n").join(""));
-    }
-
-    // Ensure that there is a flaky.json even if it wasn't downloaded.
-    if (needsMerge || needsConfigurationOverride || options["report-flakes"]) {
-      await new File("${outDirectory.path}/flaky.json").writeAsString(
-          mergedFlaky.values.map((data) => jsonEncode(data) + "\n").join(""));
-    }
-
+    // Run the tests.
     final configurationsToRun = localConfiguration != null
         ? <String>[localConfiguration]
         : namedConfigurations;
-
-    // Run the tests.
     print("".padLeft(80, "="));
     print("Running tests");
     print("".padLeft(80, "="));
@@ -557,11 +528,47 @@
           ...options.rest,
         ],
         runInShell: Platform.isWindows);
-
+    // Wait for the downloads and the test run to complete.
+    await Future.wait(tasks);
+    // Merge the results and flaky data downloaded from the builders.
+    final mergedResults = <String, Map<String, dynamic>>{};
+    final mergedFlaky = <String, Map<String, dynamic>>{};
+    if (needsMerge || needsConfigurationOverride) {
+      for (int i = 0; i < downloadNumber; ++i) {
+        previousFileName = needsMerge ? "previous-$i.json" : "previous.json";
+        var results =
+            await loadResultsMap("${outDirectory.path}/$previousFileName");
+        if (needsConfigurationOverride) {
+          overrideConfiguration(
+              results, namedConfigurations.single, localConfiguration);
+        }
+        mergedResults.addAll(results);
+        if (!options["report-flakes"]) {
+          flakyFileName = needsMerge ? "flaky-$i.json" : "flaky.json";
+          var flakyTests =
+              await loadResultsMap("${outDirectory.path}/$flakyFileName");
+          if (needsConfigurationOverride) {
+            overrideConfiguration(
+                flakyTests, namedConfigurations.single, localConfiguration);
+          }
+          mergedFlaky.addAll(flakyTests);
+        }
+      }
+    }
+    // Deflake results of the tests if required.
     if (options["deflake"]) {
       await deflake(outDirectory, configurationsToRun, options.rest);
     }
-
+    // Write out the merged results for the builders.
+    if (needsMerge || needsConfigurationOverride) {
+      await new File("${outDirectory.path}/previous.json").writeAsString(
+          mergedResults.values.map((data) => jsonEncode(data) + "\n").join(""));
+    }
+    // Ensure that there is a flaky.json even if it wasn't downloaded.
+    if (needsMerge || needsConfigurationOverride || options["report-flakes"]) {
+      await new File("${outDirectory.path}/flaky.json").writeAsString(
+          mergedFlaky.values.map((data) => jsonEncode(data) + "\n").join(""));
+    }
     // Write out the final comparison.
     print("".padLeft(80, "="));
     print("Test Results");
diff --git a/utils/compiler/BUILD.gn b/utils/compiler/BUILD.gn
index 27dfc69..81893ed 100644
--- a/utils/compiler/BUILD.gn
+++ b/utils/compiler/BUILD.gn
@@ -2,6 +2,7 @@
 # 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("../../sdk_args.gni")
 import("../../utils/compile_platform.gni")
 import("../application_snapshot.gni")
 import("../create_timestamp.gni")
@@ -51,6 +52,12 @@
   ]
 }
 
+if (use_nnbd) {
+  libraries_specification_path = "sdk_nnbd/lib/libraries.json"
+} else {
+  libraries_specification_path = "sdk/lib/libraries.json"
+}
+
 application_snapshot("dart2js") {
   deps = [
     ":compile_dart2js_platform",
@@ -64,7 +71,7 @@
   main_dart = "$target_gen_dir/dart2js.dart"
   training_args = [
     "--packages=" + rebase_path("../../.packages"),
-    "--libraries-spec=" + rebase_path("../../sdk/lib/libraries.json"),
+    "--libraries-spec=" + rebase_path("../../$libraries_specification_path"),
     rebase_path("$target_gen_dir/dart2js.dart"),
   ]
 }
@@ -72,7 +79,8 @@
 compile_platform("compile_dart2js_platform") {
   single_root_scheme = "org-dartlang-sdk"
   single_root_base = rebase_path("../../")
-  libraries_specification_uri = "org-dartlang-sdk:///sdk/lib/libraries.json"
+  libraries_specification_uri =
+      "org-dartlang-sdk:///$libraries_specification_path"
 
   outputs = [
     "$root_out_dir/dart2js_platform.dill",
@@ -87,7 +95,8 @@
 compile_platform("compile_dart2js_server_platform") {
   single_root_scheme = "org-dartlang-sdk"
   single_root_base = rebase_path("../../")
-  libraries_specification_uri = "org-dartlang-sdk:///sdk/lib/libraries.json"
+  libraries_specification_uri =
+      "org-dartlang-sdk:///$libraries_specification_path"
 
   outputs = [
     "$root_out_dir/dart2js_server_platform.dill",
diff --git a/utils/dartdevc/BUILD.gn b/utils/dartdevc/BUILD.gn
index 8b03d63..c861280 100644
--- a/utils/dartdevc/BUILD.gn
+++ b/utils/dartdevc/BUILD.gn
@@ -4,13 +4,23 @@
 
 import("../../build/dart/dart_action.gni")
 import("../../sdk_args.gni")
+import("../../utils/compile_platform.gni")
 import("../application_snapshot.gni")
 import("../create_timestamp.gni")
 
 patched_sdk_dir = "$target_gen_dir/patched_sdk"
 sdk_summary = "$target_gen_dir/ddc_sdk.sum"
-sdk_dill = "$target_gen_dir/kernel/ddc_sdk.dill"
-sdk_libraries_json = "$target_gen_dir/libraries.json"
+
+# TODO(sigmund): rename to ddc_outline.dill to be consistent with the naming
+# convention from other tools.
+sdk_outline_dill = "$root_out_dir/ddc_sdk.dill"
+sdk_full_dill = "$root_out_dir/ddc_platform.dill"
+
+if (use_nnbd) {
+  libraries_specification_path = "sdk_nnbd/lib/libraries.json"
+} else {
+  libraries_specification_path = "sdk/lib/libraries.json"
+}
 
 application_snapshot("dartdevc") {
   main_dart = "../../pkg/dev_compiler/bin/dartdevc.dart"
@@ -19,28 +29,43 @@
     "--dart-sdk",
     rebase_path("../../sdk"),
     "--dart-sdk-summary",
-    rebase_path(sdk_dill),
+    rebase_path(sdk_outline_dill),
     "-k",
     "-o",
     "dartdevc.js",
-    rebase_path("../../pkg/dev_compiler/bin/dartdevc.dart"),
   ]
 
+  if (use_nnbd) {
+    training_args += [
+      "--enable-experiment=non-nullable",
+
+      # TODO(sigmund): restore training with dartdevc.dart. Currently blocked by
+      # some regressions in type-promotion in the CFE when nnbd is enabled.
+      # The following test file is pretty simple and has no imports, so it
+      # should be easier to compile while we bootstrap NNBD.
+      rebase_path("../../tests/language_2/abstract_equal_test.dart"),
+    ]
+  } else {
+    training_args += [ rebase_path("../../pkg/dev_compiler/bin/dartdevc.dart") ]
+  }
+
   deps = [
     ":dartdevc_kernel_sdk",
-    ":dartdevc_kernel_sdk_outline",
+    ":dartdevc_platform",
   ]
 
   inputs = [
-    sdk_dill,
+    sdk_outline_dill,
   ]
 }
 
 # TODO(#38701) Cleanup after merging the forked SDK into mainline.
 if (use_nnbd) {
   sdk_root = "../../sdk_nnbd"
+  libraries_specification_path = "sdk_nnbd/lib/libraries.json"
 } else {
   sdk_root = "../../sdk"
+  libraries_specification_path = "sdk/lib/libraries.json"
 }
 
 sdk_lib_files = exec_script("../../tools/list_dart_files.py",
@@ -229,7 +254,8 @@
     ":dartdevc",
     ":dartdevc_kernel_sdk",
     ":dartdevc_sdk",
-    ":dartdevc_test_pkg",
+    ":dartdevc_test_kernel_pkg",
+    ":dartdevc_test_legacy_pkg",
     "../..:create_sdk",
   ]
 }
@@ -241,7 +267,15 @@
   deps = [
     ":dartdevc_kernel_sdk",
     ":dartdevc_sdk",
-    ":dartdevc_test_pkg",
+    ":dartdevc_test_kernel_pkg",
+    ":dartdevc_test_legacy_pkg",
+  ]
+}
+
+group("dartdevc_test_kernel_local") {
+  deps = [
+    ":dartdevc_kernel_sdk",
+    ":dartdevc_test_kernel_pkg",
   ]
 }
 
@@ -257,19 +291,14 @@
 
 # Compiles the packages used by the tests to JS with dartdevc so that they are
 # available for loading by the tests.
-prebuilt_dart_action("dartdevc_test_pkg") {
+prebuilt_dart_action("dartdevc_test_legacy_pkg") {
   deps = [
     ":dartdevc_files_stamp",
-    ":dartdevc_kernel_sdk",
-    ":dartdevc_kernel_sdk_libraries_json",
-    ":dartdevc_kernel_sdk_outline",
     ":dartdevc_sdk",
     "../../pkg:pkg_files_stamp",
   ]
 
   inputs = [
-    sdk_dill,
-    sdk_libraries_json,
     sdk_summary,
     "$target_gen_dir/dartdevc_files.stamp",
     "$root_gen_dir/pkg_files.stamp",
@@ -297,28 +326,6 @@
     # any of the above packages that are only here because unittest uses them.
     "$target_gen_dir/pkg/unittest.js",
     "$target_gen_dir/pkg/unittest.sum",
-
-    "$target_gen_dir/pkg_kernel/async_helper.dill",
-    "$target_gen_dir/pkg_kernel/async_helper.js",
-    "$target_gen_dir/pkg_kernel/collection.dill",
-    "$target_gen_dir/pkg_kernel/collection.js",
-    "$target_gen_dir/pkg_kernel/expect.dill",
-    "$target_gen_dir/pkg_kernel/expect.js",
-    "$target_gen_dir/pkg_kernel/js.dill",
-    "$target_gen_dir/pkg_kernel/js.js",
-    "$target_gen_dir/pkg_kernel/matcher.dill",
-    "$target_gen_dir/pkg_kernel/matcher.js",
-    "$target_gen_dir/pkg_kernel/meta.dill",
-    "$target_gen_dir/pkg_kernel/meta.js",
-    "$target_gen_dir/pkg_kernel/path.dill",
-    "$target_gen_dir/pkg_kernel/path.js",
-    "$target_gen_dir/pkg_kernel/stack_trace.dill",
-    "$target_gen_dir/pkg_kernel/stack_trace.js",
-
-    # TODO(rnystrom): Remove this when unittest is no longer used. Also remove
-    # any of the above packages that are only here because unittest uses them.
-    "$target_gen_dir/pkg_kernel/unittest.dill",
-    "$target_gen_dir/pkg_kernel/unittest.js",
   ]
 
   script = "../../pkg/dev_compiler/tool/build_pkgs.dart"
@@ -326,8 +333,6 @@
   args = [
     "--analyzer-sdk",
     rebase_path(sdk_summary),
-    "--kernel-sdk",
-    rebase_path(sdk_dill),
     "--output",
     rebase_path("$target_gen_dir"),
   ]
@@ -335,7 +340,11 @@
   # TODO(38701): Cleanup after merging the forked SDK into mainline.
   if (use_nnbd) {
     args += [
-      "--enable-experiment=non-nullable",
+      # TODO(sigmund): reenable. We turned this off temporarily while the
+      # migration of libraries is in flux, this step otherwise fails
+      # with many nnbd-related compile-time errors because the packages are
+      # assumed to be nnbd compilant.
+      #  "--enable-experiment=non-nullable",
 
       # TODO(rnystrom): Most of the packages used by tests can be cleanly
       # compiled as opted-in libraries, but js.dart has an optional parameter
@@ -346,38 +355,172 @@
   }
 }
 
-prebuilt_dart_action("dartdevc_kernel_sdk_outline") {
+# Compiles to JavaScript any package used from tests.
+# TODO(sigmund): generate a js bundle or a module that load these indirectly so
+# we can stop referring to this list of packages explicitly in the test_runner.
+group("dartdevc_test_kernel_pkg") {
   deps = [
-    ":dartdevc_files_stamp",
-    ":dartdevc_sdk_patch_stamp",
-    "../../pkg:pkg_files_stamp",
+    ":async_helper_js",
+    ":collection_js",
+    ":expect_js",
+    ":js_js",
+    ":matcher_js",
+    ":meta_js",
+    ":path_js",
+    ":stack_trace_js",
+    ":unittest_js",
   ]
+}
 
-  inputs = [
-    "../../utils/bazel/kernel_worker.dart",
-    "$target_gen_dir/dartdevc_files.stamp",
-    "$root_gen_dir/pkg_files.stamp",
+template("dartdevc_kernel_compile") {
+  assert(defined(invoker.package),
+         "Need 'package' in $target_name (the name of the package)")
+
+  # Other optional invoker parameters:
+  #   * extra_libraries: entrypoints to include in the module as
+  #     "package:package_name/library_name.dart" (the rule implicitly adds
+  #     the default import "package:package_name/package_name.dart").
+  #   * package_dependencies: the name of other packages this package depends
+  #     on. When providing `name`, a separate `dartdevc_kernel_compile` target
+  #     named `${name}_js` must exist.
+  #   * nnbd_disabled: whether to disable the non-nullable experiment under the
+  #     NNBD build. This is used temporariy until we either migrate the packages
+  #     or add support to read the language version information from the package
+  #     itself.
+  #   * args: additional args to pass to dartdevc
+
+  prebuilt_dart_action(target_name) {
+    script = "../../pkg/dev_compiler/bin/dartdevc.dart"
+    module = invoker.package
+    outdir = rebase_path("$target_gen_dir")
+    sdk_path = rebase_path(sdk_outline_dill)
+
+    deps = [
+      ":dartdevc_files_stamp",
+      ":dartdevc_platform",
+
+      # TODO(sigmund): depend only on the compiler and the actual files in the
+      # package
+      "../../pkg:pkg_files_stamp",
+    ]
+
+    inputs = [
+      sdk_outline_dill,
+      "$target_gen_dir/dartdevc_files.stamp",
+      "$root_gen_dir/pkg_files.stamp",
+    ]
+
+    outputs = [
+      "$target_gen_dir/pkg_kernel/$module.dill",
+      "$target_gen_dir/pkg_kernel/$module.js",
+    ]
+
+    args = [
+      "-k",
+      "--dart-sdk-summary=$sdk_path",
+      "-o$outdir/pkg_kernel/$module.js",
+      "package:$module/$module.dart",
+    ]
+
+    if (defined(invoker.extra_libraries)) {
+      foreach(lib, invoker.extra_libraries) {
+        args += [ "package:$module/$lib.dart" ]
+      }
+    }
+
+    if (defined(invoker.package_dependencies)) {
+      foreach(dep, invoker.package_dependencies) {
+        deps += [ ":${dep}_js" ]
+        args += [ "-s$outdir/pkg_kernel/$dep.dill" ]
+      }
+    }
+
+    if (defined(invoker.args)) {
+      args += invoker.args
+    }
+
+    # TODO(sigmund): remove nnbd_disabled. We turned this off temporarily while
+    # the migration of libraries is in flux, this step otherwise fails with many
+    # nnbd-related compile-time errors because the packages are assumed to be
+    # nnbd compilant.
+    if (!defined(invoker.nnbd_disabled) || !invoker.nnbd_disabled) {
+      # TODO(38701): Cleanup after merging the forked SDK into mainline.
+      if (use_nnbd) {
+        args += [ "--enable-experiment=non-nullable" ]
+      }
+    }
+  }
+}
+
+dartdevc_kernel_compile("async_helper_js") {
+  package = "async_helper"
+}
+
+dartdevc_kernel_compile("collection_js") {
+  package = "collection"
+  nnbd_disabled = true
+}
+
+dartdevc_kernel_compile("expect_js") {
+  package = "expect"
+  extra_libraries = [ "minitest" ]
+}
+
+dartdevc_kernel_compile("js_js") {
+  package = "js"
+  extra_libraries = [ "js_util" ]
+}
+
+dartdevc_kernel_compile("matcher_js") {
+  package = "matcher"
+  package_dependencies = [ "stack_trace" ]
+  nnbd_disabled = true
+}
+
+dartdevc_kernel_compile("meta_js") {
+  package = "meta"
+}
+
+dartdevc_kernel_compile("path_js") {
+  package = "path"
+  nnbd_disabled = true
+}
+
+dartdevc_kernel_compile("stack_trace_js") {
+  package = "stack_trace"
+  package_dependencies = [ "path" ]
+  nnbd_disabled = true
+}
+
+# TODO(rnystrom): Remove this when unittest is no longer used. Also remove
+# any of the above packages that are only here because unittest uses them.
+dartdevc_kernel_compile("unittest_js") {
+  package = "unittest"
+  package_dependencies = [
+    "path",
+    "stack_trace",
   ]
+  extra_libraries = [
+    "html_config",
+    "html_individual_config",
+    "html_enhanced_config",
+  ]
+  nnbd_disabled = true
+}
+
+compile_platform("dartdevc_platform") {
+  single_root_scheme = "org-dartlang-sdk"
+  single_root_base = rebase_path("../../")
+  libraries_specification_uri =
+      "org-dartlang-sdk:///$libraries_specification_path"
 
   outputs = [
-    sdk_dill,
+    sdk_full_dill,
+    sdk_outline_dill,
   ]
 
-  script = "../../utils/bazel/kernel_worker.dart"
-
   args = [
-    "--summary-only",
-    "--target",
-    "ddc",
-    "--multi-root-scheme",
-    "org-dartlang-sdk",
-    "--multi-root",
-    "file:///" + rebase_path(sdk_root),
-    "--libraries-file",
-    "org-dartlang-sdk:///lib/libraries.json",
-    "--output",
-    rebase_path(sdk_dill),
-    "--source",
+    "--target=dartdevc",
     "dart:core",
   ]
 
@@ -387,26 +530,18 @@
   }
 }
 
-copy("dartdevc_kernel_sdk_libraries_json") {
-  sources = [
-    rebase_path("$sdk_root/lib/libraries.json"),
-  ]
-  outputs = [
-    sdk_libraries_json,
-  ]
-}
-
 # Compiles the DDC SDK's kernel summary and JS code.
 prebuilt_dart_action("dartdevc_kernel_sdk") {
   deps = [
     ":dartdevc_files_stamp",
-    ":dartdevc_sdk_patch_stamp",
+    ":dartdevc_platform",
     "../../pkg:pkg_files_stamp",
   ]
 
   inputs = [
     "$target_gen_dir/dartdevc_files.stamp",
     "$root_gen_dir/pkg_files.stamp",
+    sdk_full_dill,
   ]
 
   outputs = [
@@ -420,21 +555,13 @@
     "$target_gen_dir/kernel/legacy/dart_sdk.js.map",
   ]
 
-  script = "../../pkg/dev_compiler/bin/dartdevc.dart"
+  script = "../../pkg/dev_compiler/tool/compile_dartdevc_sdk.dart"
 
   args = [
-    "-k",
-    "--compile-sdk",
-    "dart:core",
-    "--no-summarize",
     "--multi-root-scheme",
     "org-dartlang-sdk",
-    "--multi-root",
-    "file:///" + rebase_path(sdk_root),
     "--multi-root-output-path",
-    rebase_path("$target_gen_dir/../../"),
-    "--libraries-file",
-    "org-dartlang-sdk:///lib/libraries.json",
+    rebase_path("$target_gen_dir/../../../"),
     "--modules",
     "amd",
     "-o",
@@ -451,6 +578,7 @@
     "legacy",
     "-o",
     rebase_path("$target_gen_dir/kernel/legacy/dart_sdk.js"),
+    rebase_path("$sdk_full_dill"),
   ]
 
   # TODO(38701): Cleanup after merging the forked SDK into mainline.